@zihanw/pi-forge 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +67 -103
  3. package/README.zh-CN.md +67 -95
  4. package/assets/pi-forge-header-concept-1.png +0 -0
  5. package/assets/readme/PROVENANCE.md +95 -0
  6. package/assets/readme/en/capability-tools.gif +0 -0
  7. package/assets/readme/en/context-composition.gif +0 -0
  8. package/assets/readme/en/context-toggle.gif +0 -0
  9. package/assets/readme/en/draft-diff.png +0 -0
  10. package/assets/readme/en/edit-draft-diff.gif +0 -0
  11. package/assets/readme/en/editor-overview-v3.png +0 -0
  12. package/assets/readme/en/editor-overview.png +0 -0
  13. package/assets/readme/en/mode-tools.gif +0 -0
  14. package/assets/readme/en/regex-transforms.gif +0 -0
  15. package/assets/readme/en/tool-selection.gif +0 -0
  16. package/assets/readme/tui-quickstart.gif +0 -0
  17. package/assets/readme/zh-CN/capability-tools.gif +0 -0
  18. package/assets/readme/zh-CN/context-composition.gif +0 -0
  19. package/assets/readme/zh-CN/context-toggle.gif +0 -0
  20. package/assets/readme/zh-CN/draft-diff.png +0 -0
  21. package/assets/readme/zh-CN/edit-draft-diff.gif +0 -0
  22. package/assets/readme/zh-CN/editor-overview-v3.png +0 -0
  23. package/assets/readme/zh-CN/editor-overview.png +0 -0
  24. package/assets/readme/zh-CN/mode-tools.gif +0 -0
  25. package/assets/readme/zh-CN/regex-transforms.gif +0 -0
  26. package/assets/readme/zh-CN/tool-selection.gif +0 -0
  27. package/dist/active-state.d.ts +148 -0
  28. package/dist/active-state.d.ts.map +1 -0
  29. package/dist/active-state.js +374 -0
  30. package/dist/active-state.js.map +1 -0
  31. package/dist/agent-profile.d.ts.map +1 -1
  32. package/dist/agent-profile.js +11 -0
  33. package/dist/agent-profile.js.map +1 -1
  34. package/dist/capabilities.d.ts +39 -0
  35. package/dist/capabilities.d.ts.map +1 -0
  36. package/dist/capabilities.js +160 -0
  37. package/dist/capabilities.js.map +1 -0
  38. package/dist/capability-anchors.d.ts +45 -0
  39. package/dist/capability-anchors.d.ts.map +1 -0
  40. package/dist/capability-anchors.js +263 -0
  41. package/dist/capability-anchors.js.map +1 -0
  42. package/dist/capability-command.d.ts +4 -0
  43. package/dist/capability-command.d.ts.map +1 -0
  44. package/dist/capability-command.js +164 -0
  45. package/dist/capability-command.js.map +1 -0
  46. package/dist/capability-events.d.ts +79 -0
  47. package/dist/capability-events.d.ts.map +1 -0
  48. package/dist/capability-events.js +478 -0
  49. package/dist/capability-events.js.map +1 -0
  50. package/dist/capability-projection.d.ts +22 -0
  51. package/dist/capability-projection.d.ts.map +1 -0
  52. package/dist/capability-projection.js +273 -0
  53. package/dist/capability-projection.js.map +1 -0
  54. package/dist/capability-protocol.d.ts +21 -0
  55. package/dist/capability-protocol.d.ts.map +1 -0
  56. package/dist/capability-protocol.js +15 -0
  57. package/dist/capability-protocol.js.map +1 -0
  58. package/dist/capability-state.d.ts +74 -0
  59. package/dist/capability-state.d.ts.map +1 -0
  60. package/dist/capability-state.js +43 -0
  61. package/dist/capability-state.js.map +1 -0
  62. package/dist/capability-tool.d.ts +11 -0
  63. package/dist/capability-tool.d.ts.map +1 -0
  64. package/dist/capability-tool.js +25 -0
  65. package/dist/capability-tool.js.map +1 -0
  66. package/dist/capability-web-host.d.ts +11 -0
  67. package/dist/capability-web-host.d.ts.map +1 -0
  68. package/dist/capability-web-host.js +105 -0
  69. package/dist/capability-web-host.js.map +1 -0
  70. package/dist/codecs/capability.d.ts +71 -0
  71. package/dist/codecs/capability.d.ts.map +1 -0
  72. package/dist/codecs/capability.js +363 -0
  73. package/dist/codecs/capability.js.map +1 -0
  74. package/dist/codecs/prompt-stack.d.ts +1 -1
  75. package/dist/codecs/prompt-stack.d.ts.map +1 -1
  76. package/dist/codecs/prompt-stack.js +140 -13
  77. package/dist/codecs/prompt-stack.js.map +1 -1
  78. package/dist/command-contribution/index.d.ts +21 -0
  79. package/dist/command-contribution/index.d.ts.map +1 -0
  80. package/dist/command-contribution/index.js +14 -0
  81. package/dist/command-contribution/index.js.map +1 -0
  82. package/dist/compile-cycle.d.ts +7 -1
  83. package/dist/compile-cycle.d.ts.map +1 -1
  84. package/dist/compile-cycle.js +2 -0
  85. package/dist/compile-cycle.js.map +1 -1
  86. package/dist/compiler.d.ts +7 -1
  87. package/dist/compiler.d.ts.map +1 -1
  88. package/dist/compiler.js +140 -19
  89. package/dist/compiler.js.map +1 -1
  90. package/dist/context-diff-history.d.ts +2 -0
  91. package/dist/context-diff-history.d.ts.map +1 -1
  92. package/dist/context-diff-history.js +9 -0
  93. package/dist/context-diff-history.js.map +1 -1
  94. package/dist/forge-command.d.ts +10 -0
  95. package/dist/forge-command.d.ts.map +1 -0
  96. package/dist/forge-command.js +106 -0
  97. package/dist/forge-command.js.map +1 -0
  98. package/dist/index.d.ts +2 -2
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +58 -7
  101. package/dist/index.js.map +1 -1
  102. package/dist/json-fingerprint.d.ts +11 -0
  103. package/dist/json-fingerprint.d.ts.map +1 -0
  104. package/dist/json-fingerprint.js +66 -0
  105. package/dist/json-fingerprint.js.map +1 -0
  106. package/dist/lifecycle.d.ts +14 -0
  107. package/dist/lifecycle.d.ts.map +1 -1
  108. package/dist/lifecycle.js +175 -66
  109. package/dist/lifecycle.js.map +1 -1
  110. package/dist/payload-command.d.ts +2 -2
  111. package/dist/payload-command.d.ts.map +1 -1
  112. package/dist/payload-command.js +80 -26
  113. package/dist/payload-command.js.map +1 -1
  114. package/dist/payload-state.d.ts +1 -0
  115. package/dist/payload-state.d.ts.map +1 -1
  116. package/dist/payload-state.js +1 -0
  117. package/dist/payload-state.js.map +1 -1
  118. package/dist/policy.d.ts +2 -1
  119. package/dist/policy.d.ts.map +1 -1
  120. package/dist/policy.js +3 -0
  121. package/dist/policy.js.map +1 -1
  122. package/dist/preset-command.d.ts +2 -0
  123. package/dist/preset-command.d.ts.map +1 -1
  124. package/dist/preset-command.js +101 -36
  125. package/dist/preset-command.js.map +1 -1
  126. package/dist/preview-text.d.ts +5 -0
  127. package/dist/preview-text.d.ts.map +1 -0
  128. package/dist/preview-text.js +27 -0
  129. package/dist/preview-text.js.map +1 -0
  130. package/dist/preview.d.ts +18 -1
  131. package/dist/preview.d.ts.map +1 -1
  132. package/dist/preview.js +134 -99
  133. package/dist/preview.js.map +1 -1
  134. package/dist/profile-command.d.ts +4 -1
  135. package/dist/profile-command.d.ts.map +1 -1
  136. package/dist/profile-command.js +77 -14
  137. package/dist/profile-command.js.map +1 -1
  138. package/dist/prompt-cache-warning.d.ts +23 -0
  139. package/dist/prompt-cache-warning.d.ts.map +1 -0
  140. package/dist/prompt-cache-warning.js +74 -0
  141. package/dist/prompt-cache-warning.js.map +1 -0
  142. package/dist/regex.d.ts.map +1 -1
  143. package/dist/regex.js +5 -0
  144. package/dist/regex.js.map +1 -1
  145. package/dist/render-helpers.d.ts.map +1 -1
  146. package/dist/render-helpers.js +2 -0
  147. package/dist/render-helpers.js.map +1 -1
  148. package/dist/repositories/capability.d.ts +53 -0
  149. package/dist/repositories/capability.d.ts.map +1 -0
  150. package/dist/repositories/capability.js +294 -0
  151. package/dist/repositories/capability.js.map +1 -0
  152. package/dist/runtime/capability-runtime.d.ts +91 -0
  153. package/dist/runtime/capability-runtime.d.ts.map +1 -0
  154. package/dist/runtime/capability-runtime.js +967 -0
  155. package/dist/runtime/capability-runtime.js.map +1 -0
  156. package/dist/runtime/tool-policy-runtime.d.ts +8 -0
  157. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
  158. package/dist/runtime/tool-policy-runtime.js +171 -30
  159. package/dist/runtime/tool-policy-runtime.js.map +1 -1
  160. package/dist/session-adapter.d.ts +13 -0
  161. package/dist/session-adapter.d.ts.map +1 -1
  162. package/dist/session-adapter.js +110 -0
  163. package/dist/session-adapter.js.map +1 -1
  164. package/dist/session-usage.d.ts +65 -0
  165. package/dist/session-usage.d.ts.map +1 -0
  166. package/dist/session-usage.js +134 -0
  167. package/dist/session-usage.js.map +1 -0
  168. package/dist/subagent/fingerprints.d.ts +3 -15
  169. package/dist/subagent/fingerprints.d.ts.map +1 -1
  170. package/dist/subagent/fingerprints.js +5 -69
  171. package/dist/subagent/fingerprints.js.map +1 -1
  172. package/dist/subagent/index.d.ts +2 -0
  173. package/dist/subagent/index.d.ts.map +1 -1
  174. package/dist/subagent/index.js +2 -0
  175. package/dist/subagent/index.js.map +1 -1
  176. package/dist/subagent-host.d.ts +2 -2
  177. package/dist/subagent-host.d.ts.map +1 -1
  178. package/dist/subagent-host.js +13 -1
  179. package/dist/subagent-host.js.map +1 -1
  180. package/dist/types.d.ts +6 -1
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js.map +1 -1
  183. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  184. package/dist/web-editor/client-script.generated.js +1 -1
  185. package/dist/web-editor/client-script.generated.js.map +1 -1
  186. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  187. package/dist/web-editor/client-styles.generated.js +1 -1
  188. package/dist/web-editor/client-styles.generated.js.map +1 -1
  189. package/dist/web-editor/server.d.ts.map +1 -1
  190. package/dist/web-editor/server.js +152 -4
  191. package/dist/web-editor/server.js.map +1 -1
  192. package/dist/web-editor/styles.d.ts.map +1 -1
  193. package/dist/web-editor/styles.js +521 -116
  194. package/dist/web-editor/styles.js.map +1 -1
  195. package/dist/web-editor/types.d.ts +81 -1
  196. package/dist/web-editor/types.d.ts.map +1 -1
  197. package/dist/web-host.d.ts +7 -0
  198. package/dist/web-host.d.ts.map +1 -1
  199. package/dist/web-host.js +168 -5
  200. package/dist/web-host.js.map +1 -1
  201. package/dist/workspace.d.ts +11 -0
  202. package/dist/workspace.d.ts.map +1 -1
  203. package/dist/workspace.js +63 -5
  204. package/dist/workspace.js.map +1 -1
  205. package/docs/README.md +4 -0
  206. package/docs/design/README.md +3 -1
  207. package/docs/design/architecture-0.5.md +22 -0
  208. package/docs/design/archive/2026-09-12-system-update-design.md +229 -0
  209. package/docs/design/pi-forge-system-update-design-notes.md +157 -0
  210. package/docs/development/release.md +20 -20
  211. package/docs/development/roadmap.md +17 -2
  212. package/docs/development/scoped-global-profiles-stacks.md +1 -1
  213. package/docs/development/setup.md +1 -1
  214. package/docs/getting-started.md +1 -1
  215. package/docs/guides/delegation.md +22 -20
  216. package/docs/guides/migrating-to-0.5.md +29 -0
  217. package/docs/guides/use-cases.md +6 -2
  218. package/docs/guides/web-editor.md +73 -5
  219. package/docs/reference/active-state.md +77 -0
  220. package/docs/reference/capabilities.md +259 -0
  221. package/docs/reference/commands.md +52 -24
  222. package/docs/reference/configuration.md +4 -2
  223. package/docs/reference/features.md +70 -4
  224. package/docs/reference/provider-support.md +67 -0
  225. package/docs/reference/public-api.md +49 -3
  226. package/docs/reference/session-cache.md +112 -0
  227. package/docs/reference/stack-schema.md +18 -4
  228. package/docs/reference/subagent-host-port.md +8 -0
  229. package/docs/zh-CN/README.md +3 -0
  230. package/docs/zh-CN/getting-started.md +1 -1
  231. package/docs/zh-CN/guides/delegation.md +22 -10
  232. package/docs/zh-CN/guides/migrating-to-0.5.md +29 -0
  233. package/docs/zh-CN/guides/web-editor.md +74 -7
  234. package/docs/zh-CN/reference/capabilities.md +259 -0
  235. package/docs/zh-CN/reference/commands.md +61 -33
  236. package/docs/zh-CN/reference/provider-support.md +67 -0
  237. package/docs/zh-CN/reference/session-cache.md +112 -0
  238. package/examples/capabilities/review.json +12 -0
  239. package/examples/capabilities/write-tools.json +15 -0
  240. package/examples/read-first-worker-prompt-stack.json +49 -0
  241. package/package.json +16 -9
@@ -0,0 +1,157 @@
1
+ # Capabilities — accepted 0.5.5 design
2
+
3
+ [Documentation](../README.md) · [Lean architecture](architecture-0.5.md) · [Roadmap](../development/roadmap.md)
4
+
5
+ **Status:** implementation authorized, 2026-09-20; accepted 9/21 amendment incorporated. Functional source is delivered across all planned lanes: foundation codecs, human CLI core (`/capability`), plain metadata anchor projection, Web Session capabilities activity panel, live Preset bindings (`capabilities`) in dedicated peer Capability bindings tab with finite overrides and opt-in `modelCallable: true`, restricted model-callable Agent control (`forge_capability`), Web Capabilities surface CRUD with SDK-grouped tool picker and `sourceRevision` stale-save protection, custom default tools policy (`tools.initial`), guarded human Web activation picker (`GET /api/capability-state/available`, `POST /api/capability-state/enable`), and Pi 0.87 transcript/projection migration. Parent safeguards enforce raw source/revision coherence, external new-bindings stale-save protection, and lifecycle/re-entry fences (`disposed`, `lifecycleRevision`, `sameContext`). [Current reference](../reference/capabilities.md) states operational boundaries. Capabilities support `add`/`remove` only; candidate `only`/allowlist is not implemented. Parent build and full verification passed on Pi 0.87.0 (773 Node / 37 browser); development package version remains 0.5.4; release version bump decision pending between 0.5.5 or 0.6; repo dev SDK is pinned to `0.87.0` with peer range `>=0.87.0 <0.88.0` (no dual 0.86 support claim).
6
+
7
+ This supersedes the [September 12 upstream-blocked proposal](archive/2026-09-12-system-update-design.md). Historical spike notes below reflect dated 0.86 exploration; current production architecture builds directly on Pi 0.87 APIs.
8
+
9
+ ## Ownership and bounded scope
10
+
11
+ **Definitions are reusable; authorization belongs to Presets; active state belongs to Sessions.** Capabilities contain continuing collaboration/output guidance and optional tool selection changes. Skills remain the place for procedures, scripts and reference material.
12
+
13
+ - Forge owns semantic events, activation snapshots, derived delivery anchors and request-only capability projection.
14
+ - Pi owns ordinary transcript storage/branching, message protocols, provider encoding and actual tool execution. No fork or private `AgentSession` patches.
15
+ - `ForgeWorkspace` remains the single resource-state owner. Existing codecs/repositories/catalogs are reused. The capability reducer is a pure view, not a second mutable workspace.
16
+ - `tool-policy-runtime` remains the only Forge owner of executable tool selection. Text saying a tool is disabled is not enforcement.
17
+ - CLI, restricted Agent tool and Web UI share one application service. No dynamic control-tool schema, new registry/framework/package entry point, arbitrary JSON Patch, inheritance chain, capability dependencies, automatic resource bundling, or general undo/redo.
18
+
19
+ ## Evidence behind the architecture
20
+
21
+ An isolated Pi 0.86 `AgentSession`/extension-runner spike used fake models/tools and intercepted adapter payload assembly; no provider HTTP was sent by that harness. Nineteen assertions and a separate smoke passed, including assertions that intentionally reproduce integration failures. They are not nineteen production features passing.
22
+
23
+ 1. Keeping and mutating `before_agent_start.systemPromptOptions.sections` across a tool loop did not reliably synchronize later changes: the expected text sequence off/on/off became off/on/on while tools restored correctly. The command options getter was not a live-run setter.
24
+ 2. Returning Forge's current full `systemPrompt` invokes Pi's forced request projection after context hooks; it suppresses later native system updates. `customPrompt` is not an exact replacement because the cwd contribution remains.
25
+ 3. A Forge-owned marker/context projector worked in the sampled repeated toggle, native/user/native switch, branch/JSON reconstruction and manual-compaction scenarios. Those samples do not establish production crash recovery, automatic compaction, concurrency, old-Preset compatibility or tool-baseline recovery.
26
+ 4. `systemPromptOptions.sections` is a prompt-building input; `SystemMessage.sections` is still useful as a native request representation. Failure of the tested thin bridge does not prove every upstream integration impossible.
27
+ 5. `sendMessage` steering with explicit `triggerTurn:false` did not enter the next request in the tested live loop. Omitting it worked while streaming and did not start inference in the tested idle command. Context-hook exceptions alone are swallowed; explicit abort behavior must be accounted for.
28
+
29
+ The implemented request-base bridge preserves compiled replacement strings while retaining foreign named sections and tool declarations. Built-in base text and selected-tool macros refresh when the executable set changes.
30
+
31
+ **Production architecture:** management completely avoids transcript `sendMessage` and `custom_message` carriers, preventing dialogue contamination and spurious model turns. Under Pi 0.87, standard `context` hooks intentionally exclude System messages; Forge moves the entire compiler, base prompt replacement, and capability projection pipeline to `context_with_system` without an internal two-phase split. Delivery is anchored using plain `custom` session entries under the same delivery type (`pi-forge-capability-delivery`) carrying strictly cursor-only metadata (`{ schemaVersion: 1, throughEventId: string }`).
32
+
33
+ - **Anchor persistence points:**
34
+ - **Idle:** persisted immediately upon `/capability` execution or synchronization.
35
+ - **Running session:** safely deferred while a tool loop is busy; anchors are never inserted between an in-flight tool call and its matching result.
36
+ - **On `agent_end`:** uncommitted pending anchors are committed after the assistant's final response when no Forge context failure or incomplete batch remains, before the next user turn.
37
+ - **Cycle reset on `agent_settled`:** while `agent_end` commits anchors, compile cycles and the busy fence reset only on `agent_settled`. This ensures `agent_before_settle` continuations preserve compiled Preset inputs and active capabilities across low-level runs.
38
+ - **Context assembly via canonical projection:**
39
+ - Runtime, Preview, and anchor helpers build against Pi 0.87's `buildSessionProjection` (handling `context_edit` omissions, replacements, and `sourceEntry`). Raw session history on disk is never modified.
40
+ - `prepareCapabilityMessages` materializes before Preset compilation plain metadata anchors into ephemeral in-memory markers at their exact ordinal positions, verifying a unique ordered alignment against the canonical session projection.
41
+ - Incoming SDK leading System prompts always remain first; Forge's own prefix plain metadata anchors are inserted after it.
42
+ - `projectCapabilityMessages` then projects active capability deltas into native request-only `SystemMessage.sections` or fallback attributed timeline user messages.
43
+ - **Decoupled UI notification:** UI status notifications (`ctx.ui.setStatus` and Web activity panel) are completely independent and never enqueue turns to the model.
44
+
45
+ Preceding extension message rewrites (modifying messages in context hooks) are a legal and valid Pi SDK capability. However, Forge's anchor materialization requires a unique ordered alignment with canonical session entries. Content/protocol rewrites, inserted messages, non-custom omissions and ambiguous custom-message omissions fail closed. Prior full-System context extensions must move to `context_with_system`; `before_agent_start` forced System prompt injection continues to execute later in Pi's lifecycle; and final request arbitrary preceding rewrites still fail closed. Users may adjust conflicting extension order or extension behavior, but this is an operational suggestion only; Forge does not guarantee post-extension rewrite safety, nor can it guarantee generic plugin compatibility, prompt cache retention, warming, or automatic overflow handling. Upstream Pi metadata chunking and semantic-cut defects are NOT patched and remain unfixed upstream; legacy session carriers remain untouched, and Oh My Pi (OMP) is not supported or promised.
46
+
47
+ The SDK queue exception is explicit: persisted custom messages can be absent from the current tool follow-up and have different live/persisted envelope timestamps. Compare full content/protocol fields, ignore only the regenerated custom timestamp, and permit custom-message omissions only when earliest/latest ordered alignments agree. Identical ambiguous omissions fail closed. Never rebuild/overwrite incoming context or reinsert omitted peer messages.
48
+
49
+ ## Resource and binding contract
50
+
51
+ Discovered directories:
52
+
53
+ - `.pi/forge/capabilities/*.json`
54
+ - `~/.pi/forge/capabilities/*.json`
55
+
56
+ ```json
57
+ {
58
+ "schemaVersion": 1,
59
+ "type": "pi-forge.capability",
60
+ "id": "review",
61
+ "name": "Review",
62
+ "description": "Report findings and evidence before editing.",
63
+ "content": "List findings, evidence and risks. Do not directly edit files.",
64
+ "tools": {
65
+ "add": ["grep", "find", "ls"],
66
+ "remove": ["bash", "powershell", "write", "edit"]
67
+ }
68
+ }
69
+ ```
70
+
71
+ The definition has no Agent authorization. Content is literal text, not an executable template or file path. `name`/`description` are optional; omitted tool arrays normalize to empty arrays. At least non-whitespace text or one tool effect is required. Content is bounded to 100,000 characters, name to 1,000, each tool array to 256 names and each exact tool name to 128 characters. Tool names cannot contain whitespace, controls, `*` or `?`. Capabilities support `add` and `remove` only; candidate `only` or capability-level allowlists are not implemented. Unknown and malformed fields fail closed.
72
+
73
+ Preset binding field:
74
+
75
+ ```json
76
+ {
77
+ "capabilities": [{
78
+ "ref": "global:review",
79
+ "id": "review",
80
+ "modelCallable": true,
81
+ "overrides": {
82
+ "appendContent": "Also inspect backwards compatibility.",
83
+ "tools": { "add": ["grep", "find"] }
84
+ }
85
+ }]
86
+ }
87
+ ```
88
+
89
+ The `capabilities` field is live in the Preset schema and validated by codecs and editors.
90
+
91
+ ### Accepted 9/21 amendment: Tool selection and UX refinements
92
+
93
+ - **Preset initial tools (`tools.initial?: string[]`):** Configures initial active tools for a preset using concrete valid tool names (no wildcards allowed). When omitted, legacy behavior is preserved (selective allow selects matching registered tools; unrestricted/deny retains or filters the session baseline). When set to `[]`, zero tools are active initially. The `allow`/`deny` ceiling remains authoritative and exclusive; tools blocked by policy produce validation errors. Extensions and mods register allowed inactive tools: if `initial` is set, dynamically registered tools remain inactive unless listed or added by an active capability. Configured defaults serve as the active base throughout preset activation (not a one-time reset per turn): disabling a capability or calling disable/reset restores these defaults plus remaining capabilities; disabling the preset restores the reconciled session baseline (including preserved external changes).
94
+ - **Capability grouped picker:** The tool picker organizes tools using SDK `sourceInfo` (Pi built-in tools, packages, or top-level entry points). It saves exact concrete tool names: no package references are persisted, no packages are auto-installed, and newly added package tools are not auto-added. Inactive registered tools are visible in the picker; unloaded tools are unavailable in the session, but manual saved references are preserved.
95
+ - **Preset bindings tab:** Preset bindings are relocated from Preset metadata to a dedicated peer **Capability bindings** tab (`bindings`). Overrides (content, tools add/remove) and source-effective preview are collapsed under an advanced toggle (`showAdvanced` / `hideAdvanced`).
96
+ - **Default tools editor:** An opt-in, searchable, collapsible grouped picker in the Policy tab allows choosing default tools, while retaining advanced literal and wildcard allow/deny policy.
97
+ - **Save execution behavior:** Saving a Capability in the Capabilities surface updates its library definition only and never activates it. Saving an inactive Preset updates disk bytes without selecting or activating it. Crucially, saving the currently active Preset reloads and syncs its live tool and capability authorization policy immediately in the session without replacing frozen active capability snapshots (UI docs accurately reflect this; never promise that all saves leave execution untouched).
98
+ - **Compatibility and versioning:** Stacks using `tools.initial` require new Forge (older Forge ignores `initial`, not downgrade-compatible). Development remains in the 0.5.4 tree with release version bump pending (0.5.5 or maybe 0.6); host requirement remains Pi `>=0.87.0 <0.88.0` unchanged.
99
+ - **Prompt caching:** On compatible Codex transports, first-time additions can preserve request prefixes if retained history contains no removals/redeclarations; this is not a cache-hit guarantee. Removals/re-additions use the full-current-tool fallback. No permission bypass or caching guarantees.
100
+
101
+ - Direct library selection of a bare ID uses project-over-global. Invalid or duplicate local definitions do not fall back to global.
102
+ - A bare Preset reference resolves in its owner's scope. A project Preset must explicitly write `global:<id>` to use a global capability; a global Preset cannot use project capabilities.
103
+ - UI writes qualified references. Binding ID defaults to the referenced ID; duplicate effective binding IDs are rejected, including same-name cross-scope references unless explicitly disambiguated. At most 256 bindings per Preset.
104
+ - Only `modelCallable: true` grants eligibility for the Agent control path; omission defaults to `false`. Current tool policy and registration still apply on every call.
105
+ - Overrides allow `content` (replace) **or** `appendContent` (paragraph append with two newlines), never both. Each specified `tools.add`/`tools.remove` array replaces that entire field; the other field is preserved. Identity, name, authorization, and arbitrary fields cannot be overridden.
106
+ - Base resources must validate before applying overrides; an override cannot repair an invalid source silently. Effective results are defensive snapshots.
107
+
108
+ ## Semantic events and snapshots
109
+
110
+ The internal schema is persisted through existing `session-adapter`/Pi custom entries, not a new persistence backend. Semantic entries carry validated snapshots; delivery messages carry only a versioned event cursor. Baseline records belong to the existing tool-policy owner.
111
+
112
+ Common event fields: `schemaVersion: 1`, `eventId`, `op`, `actor`, `createdAt` (finite nonnegative milliseconds). Branch order, not timestamps, determines reduction. Opaque event/activation IDs are at most 128 characters. Resource/Preset/binding IDs keep the existing grammar.
113
+
114
+ - **activate:** actor `user` or `agent`, with an immutable `snapshot` containing `activationId`, `source`, optional name, content, normalized tool patch, and content fingerprint.
115
+ - **deactivate:** targets an `activationId`; actor `user`, `agent` or `lifecycle`.
116
+ - **reset:** user only. Clears current activity, not historical events.
117
+ - Source is `{ kind: "manual" }` or `{ kind: "capability", key: { scope, id }, binding?: { preset: { scope, id }, id } }`.
118
+ - Agent activation requires an authorized bound capability (`modelCallable: true`). Agent deactivation cannot close user-owned activations. Lifecycle deactivation is restricted to bound capabilities; it cannot clear manual or unbound user rules.
119
+ - Unknown/repeated off is a no-op. Activation IDs cannot be reused within one branch even after reset/off. Repeated identical event IDs are no-ops without moving the latest event marker backwards; conflicting reuse fails closed.
120
+ - Repeated `enable` is deduplicated and idempotent; it never performs an automatic owner takeover between user and agent. Takeover requires explicit deactivation and reactivation.
121
+ - Malformed owned event data fails reduction with an index/error, never a partially restored active set. Unrelated Pi entries are filtered by the adapter, not fed as fake capability events.
122
+ - Fingerprints use Forge's canonical `sha256:v1` algorithm. The payload is domain-tagged effective source/name/content/tools, excluding activation ID. It represents content identity, not a cryptographic signature.
123
+
124
+ Snapshot content never drifts with source edits. Switching Presets appends deactivations for old bound activations while retaining manual and unbound user rules; reloading the same Preset retains immutable active snapshots. Revoked authorization does not retroactively erase active snapshots; human recovery via CLI or Web disable/reset is the recovery path.
125
+
126
+ ## Delivery, recovery, tools, and parent safeguards
127
+
128
+ Derived plain `custom` metadata entries anchor delivery; they do not independently own active state, duplicate authoritative snapshot payloads, or pollute conversation dialogue. One semantic history supports both presentations:
129
+
130
+ - Native: request-only `SystemMessage.sections` keyed by activation identity; off uses a null patch and Pi's existing removal wording, without an extra duplicate user notice.
131
+ - Unsupported models: an attributed timeline user update/stop notice. Do not silently fold Forge capability updates into the leading prompt. Genuine user/tool content is never promoted to system authority.
132
+ - Transform only clearly owned Forge rule content, never an entire mixed system message. Preserve unrelated content/sections and `toolsAdded`/`toolsRemoved` for Pi's adapters.
133
+ - Compaction requires an owned current-state checkpoint derived from semantic events; suppress pre-checkpoint anchors, including retained-tail copies, then replay later deltas. Request-only sections are not automatically saved by Pi's raw transcript checkpoint. Checkpoint placement remains unchanged (precedes summary, follows leading system prompt); the upstream Pi metadata chunking bug is an independent issue and remains unfixed.
134
+ - Compaction input characterization: in real SDK compaction, summarizers receive no metadata anchors and no Forge rule bodies (projection is request-only), while user, assistant, and peer dialogue are preserved. Simulated responses in test harnesses characterize request plumbing and harness shape, not remote LLM semantic compaction fidelity or summarizer compliance.
135
+ - **Breaking pre-release rename boundary:** no legacy aliases or readers are provided for the former instruction-mode schema, directories, or capability state. Existing development configuration must be converted and continuing old sessions are unsupported; Forge does not rewrite old JSONL or historical summaries, so converted configurations require a new session.
136
+ - Immediate tool synchronization vs. next-request prompt projection: admission validates text/reference/authorization/tool effects before commit. Executable tool policy synchronizes *immediately* (`sync()` / `setActiveTools()`), whereas prompt text and native sections or user updates take effect at the *next model request* boundary. Running tool batches are not interrupted.
137
+ - Tool policy calculation: tools are computed from a recoverable baseline plus all remaining additions minus all remaining removals, subject to top-level Preset deny policy; removal wins globally across active capabilities. Additions must be registered and permitted by the active Preset.
138
+ - Read-only resource discovery and Preview: inspecting capabilities, calling `GET /api/capability-state/available`, or inspecting the Preview dock never mutates tool policies, commits session events, or marks pending capabilities prepared.
139
+ - Parent safeguards:
140
+ - Raw source and revision coherence: GET operations couple editable data and `sourceRevision` from the same raw file bytes.
141
+ - External new bindings stale save detection: Preset saves enforce `sourceRevision` checks whenever bindings are present or modified, rejecting stale overwrites (409 Conflict) if the file changed on disk (including externally added bindings).
142
+ - Lifecycle and re-entry fences: explicit `disposed` flag, `lifecycleRevision` increment, and `sameContext` verification prevent cross-session pollution or operations after session disposal.
143
+ - Provider-managed cache warning: prompt caching, tool transport, and KV cache hits are downstream provider-managed. Stable prefixes may help caching, but schema changes, removals, fallback, base recompilation, model switches, and compaction alter cache boundaries; pi-forge provides no guarantees of zero KV invalidation or exact cache hits.
144
+ - Human recovery: human CLI (`/capability disable`, `/capability reset`) and Web panel controls remain available; an Agent-owned capability cannot disable its own control path without a safe recovery policy.
145
+
146
+ ## Staged implementation and release gates
147
+
148
+ 1. **Foundation (verified):** JSON codec, finite overrides, scoped resolution, immutable snapshots, and strict event reduction.
149
+ 2. **Human CLI core and metadata anchor projection (implemented):** Pi 0.87 dependency upgrade, `context_with_system` full pipeline, `buildSessionProjection` canonical alignment, request-base bridge, scoped discovery, session event persistence, plain `custom` cursor-only metadata anchors (replacing transcript carriers), ordinal materialization, compaction checkpoints, and executable tool-policy coordination. Real SDK tests cover same-run toggles, native/fallback switches, fake tool execution, disk reopens, branches, crash-window baseline recovery, and legitimate preceding extension rewrite fail-closed safety.
150
+ 3. **Session activity UI and compaction characterization (implemented):** read/control view derived from the existing runtime, never a second state owner. Human disable/reset carries an exact session/leaf/revision guard with runtime-instance fencing; Web requires trust, pure reads never synchronize or infer, and stale pages cannot retry writes automatically. Real-SDK compaction-input characterization confirms Forge metadata and request-only rules are absent from summarizer history while user, assistant, and peer dialogue remain intact; fake test responses are plumbing characterization, not remote semantic validation.
151
+ 4. **Preset authorization and restricted Agent control (implemented):** live Preset binding schema (`capabilities`), opt-in `modelCallable: true`, and restricted fixed-schema `forge_capability` (list, status, enable, disable, ID ≤ 128 chars). Per-call trust, binding identity, authorization, and tool policy checks prevent privilege escalation. CLI additions `/capability bindings` and `/capability enable-bound <id>` provide human parity. Management operations do not initiate paid inference.
152
+ 5. **Capabilities library CRUD, binding editor, and guarded human Web activation picker (delivered in functional source):** dedicated **Capabilities** surface for project/global capability CRUD with `sourceRevision` stale-save guards; Preset metadata bindings editor with finite overrides and live source-effective preview; guarded human Web activation picker (`GET /api/capability-state/available`, `POST /api/capability-state/enable`) with pre-activation preview and session/leaf/revision plus content fingerprint validation. Parent safeguards enforce raw source/revision coherence, external new bindings stale-save detection, and lifecycle/re-entry fences.
153
+ 6. **Release closeout (pending release review and user authorization):** Pi 0.87 migration and accepted tool-selection/UX amendment passed parent build and full verification (773 Node / 37 browser). Development package version remains 0.5.4; release version bump decision pending between 0.5.5 or 0.6; repo dev SDK is pinned to `0.87.0` with peer range `>=0.87.0 <0.88.0` (no dual 0.86 support claim); release, git push, and host reload (`/reload`) are separate user-authorized actions.
154
+
155
+ Acceptance includes old Presets, regex/history filtering, repeated same-run toggles, native/user/native transitions, request abort/retry/concurrency, explicit and automatic compaction, disk resume/branches/crash boundaries, baseline recovery, real tool-call rejection, external tool changes, warming, and payload/usage association.
156
+
157
+ No universal native support, obedience, zero-KV-invalidation, or guaranteed cache-hit claims. No automatic legacy migration, no old summary rewrites, and no Pi split patch. Publishing, host upgrades, reloads, and deployment remain separate user-authorized actions.
@@ -2,36 +2,36 @@
2
2
 
3
3
  [Documentation](../README.md)
4
4
 
5
- ## Before release
6
-
7
- 1. Confirm the changelog and user documentation describe the intended version and experimental surfaces accurately.
8
- 2. Publish and smoke-test any required `@zihanw/pi-subagent-runtime` version first.
9
- 3. Install dependencies from the lockfile and run `npm run verify`; require the
10
- Ubuntu, macOS, and Windows GitHub Actions jobs to pass for the release commit.
11
- 4. Test a packed installation against the documented minimum and current Pi versions.
12
- 5. Exercise ordinary stack/profile use independently of delegation.
13
- 6. Exercise both configured foreground backends and confirm unsupported host capabilities fail closed before provider transport.
14
- 7. Inspect `npm pack --dry-run` for package size and unexpected or missing files.
15
-
16
- The macOS and Windows jobs run the same complete verification surface as Linux,
17
- including the real-browser editor suite against the hosted runner's system
18
- Chrome. Compatibility-version and scheduled latest-Pi probes remain Linux-only;
19
- they test dependency drift rather than operating-system behavior.
5
+ ## Independent packages
6
+
7
+ The main `@zihanw/pi-forge` package has **no** dependency on `@zihanw/pi-forge-subagents` or `@zihanw/pi-subagent-runtime`. It can release independently; unfinished optional features do not block ordinary Forge use or a main-package release.
8
+
9
+ The optional package is tested against the released Forge host before its own publication. Any required runtime version must be published and smoke-tested before publishing the optional package that depends on it. Backend, continuation, background-task, and nested-usage producer acceptance belong to that companion release, not to the main package.
10
+
11
+ ## Before main-package release
12
+
13
+ 1. Confirm the intended version in the manifest, lockfile, changelog, and current user documentation. Preserve historical release records and document breaking configuration/session boundaries.
14
+ 2. Install dependencies from the lockfile with `npm ci`, build, and run the complete `npm run verify` chain: Node tests, browser tests, types, generated client, docs, distribution, package contents, and packed installation.
15
+ 3. Require the Ubuntu, macOS, Windows, and configured Pi compatibility GitHub Actions jobs to pass for the **exact release commit**, not an earlier source revision.
16
+ 4. Test a packed main-package installation against both the documented minimum and current tested Pi versions; exercise ordinary Preset/Profile/Capability behavior independently of optional delegation.
17
+ 5. Inspect `npm pack --dry-run` for package size and unexpected or missing files. Publish the verified artifact, not an unreviewed working tree.
18
+
19
+ The macOS and Windows jobs run the same complete verification surface as Linux, including the real-browser editor suite. Compatibility-version and scheduled latest-Pi probes remain Linux-only; they test dependency drift rather than operating-system behavior.
20
20
 
21
21
  ## Dependency policy
22
22
 
23
- Published manifests use wildcard peer dependencies for Pi-host-provided SDK packages. Exact versions belong in development dependencies and the lockfile so tests are reproducible without restricting compatible host releases.
23
+ The four Pi SDK packages remain host-provided optional peers, never private runtime dependencies. Forge 0.5.5 requires Pi `>=0.87.0 <0.88.0`, with development fixtures pinned to `0.87.0`; `typebox` remains a wildcard optional peer. Pi 0.86 and future minor versions are not implicitly supported. Exact tested versions belong in development dependencies and the lockfile, not exact host-version requirements.
24
24
 
25
- `pi-subagent-runtime` remains a normal exact dependency until its compatibility policy says otherwise. Its own host-facing Pi dependencies must follow the same host-provided peer model.
25
+ Published `@zihanw/pi-forge-subagents` 0.5.3 does not understand `tools.initial`. The upcoming optional package needs the matching fix and a Forge dependency floor of `^0.5.5` for the new command-contribution entry. This is a companion compatibility gate, not a requirement to publish the packages simultaneously. See the [host-port compatibility note](../reference/subagent-host-port.md#tool-selection-compatibility).
26
26
 
27
27
  ## Package contents
28
28
 
29
- The tarball must include compiled `dist/`, examples, the English and Chinese landing pages, changelog, license, and user/reference documentation. It must not include physical `src/` files. Both the default extension entry and experimental subagent entry must resolve to compiled output.
29
+ The tarball must include compiled `dist/`, examples, the English and Chinese landing pages, changelog, license, and user/reference documentation. It must not include physical `src/` files. The root, `/subagent`, `/ui-contribution`, and `/command-contribution` entries must resolve to compiled output.
30
30
 
31
31
  The root `PUBLIC_API.md` and `SUBAGENT_ADAPTER_CONTRACT.md` files are compatibility pointers; authoritative content lives under `docs/reference/`.
32
32
 
33
33
  ## Publish and verify
34
34
 
35
- Publish the intended version/tag, then install it through Pi in a clean project. Verify `/preset`, `/profile`, `/preset ui`, and—when deliberately enabled—delegation. Restart Pi after installation to avoid testing a stale extension instance.
35
+ With release authorization, publish the intended version using the intended tag (`latest` for a stable main-package release). Verify registry version, tag, and tarball integrity, then install the published package through Pi in a clean project and smoke-test the main commands and resource workflow without model inference.
36
36
 
37
- For a stable release, ensure npm `latest` points to the new version and any prerelease channel no longer leaves users on an incompatible older build.
37
+ Do not silently move unrelated legacy or prerelease tags. Publishing is not a host upgrade: restart or reload a user's existing host only with that user's authorization, and start a new session when the release's migration notes require it. Keep release evidence separate from static documentation; a version bump or changelog entry alone is not proof of successful publication.
@@ -4,7 +4,22 @@
4
4
 
5
5
  This file contains forward-looking product work only. Completed capability belongs in the [feature inventory](../reference/features.md), release history in the root [changelog](../../CHANGELOG.md), and completed investigation in the [design archive](../design/README.md).
6
6
 
7
- ## 0.5.0 breaking cleanup (lean)
7
+ ## Active 0.5.5: session capabilities
8
+
9
+ Implementation is authorized under the [accepted capability design](../design/pi-forge-system-update-design-notes.md) and [lean-plan amendment](../design/architecture-0.5.md#accepted-055-amendment-session-capabilities). Pi 0.86 is released; the old upstream-blocked thin-sections proposal is superseded.
10
+
11
+ One active lane at a time:
12
+
13
+ 1. **Foundation (verified):** strict capability/override codec, scoped binding resolution, immutable snapshots, and branch event reducer.
14
+ 2. **Human CLI core & metadata anchor projection (implemented):** Pi 0.87 dependency upgrade, request-base replacement, `context_with_system` full pipeline, `buildSessionProjection` canonical alignment, native/user projection, semantic events and plain `custom` cursor-only metadata anchors, durable tool baselines, repositories/ForgeWorkspace discovery, and `/capability` add/list/bindings/enable/enable-bound/disable/status/reset. See [current reference](../reference/capabilities.md).
15
+ 3. **Session observability & activity panel (implemented):** derived multi-capability state, actual selected tools, delivery status (`none`, `pending`, `prepared`), presentation indicators, and guarded human disable/reset; real SDK summarizer-input characterization.
16
+ 4. **Preset authorization & restricted Agent control (implemented):** live Preset binding schema (`capabilities`), opt-in `modelCallable: true`, and model-callable `forge_capability` tool with fixed list/status/enable/disable schema; per-call trust, binding identity, authorization, and tool policy checks; strict user-vs-agent ownership.
17
+ 5. **Capabilities library CRUD, Preset binding editor, and guarded human Web activation picker (delivered in functional source):** dedicated **Capabilities** surface for project/global capability CRUD with `sourceRevision` stale-save guards; dedicated peer Capability bindings editor with finite overrides and live source-effective preview; guarded human Web activation picker (`GET /api/capability-state/available`, `POST /api/capability-state/enable`) with pre-activation preview and session guard plus content fingerprint validation. Parent safeguards enforce raw source/revision coherence, external new bindings stale-save detection, and lifecycle/re-entry fences (`disposed`, `lifecycleRevision`, `sameContext`).
18
+ 6. **Main-package 0.5.5 release closeout:** The accepted UI and local full verification closed out on 2026-09-24 (`89c6ba2`); bilingual README B and reviewed continuous media are adopted. UI scope is frozen except for regressions/release blockers. The main package is versioned 0.5.5; publication requires the exact-commit CI and packed-install gates in the [release process](release.md). No paid provider matrix is implied. The optional package and runtime have independent unfinished release work and are not a main-package gate. Repo dev SDK remains pinned to 0.87.0 with peer `>=0.87.0 <0.88.0` (no dual 0.86 support claim).
19
+
20
+ Existing README and optional Pet active-state changes are preserved. No host upgrade, reload or publication follows implicitly from local feature development. Foundation tests are not proof of live 0.5.5 behavior.
21
+
22
+ ## 0.5.0 breaking cleanup (lean history)
8
23
 
9
24
  0.5.0 is a deliberately breaking cleanup release plus the minimum foundation for 0.5.x. Net-new feature work is frozen.
10
25
 
@@ -78,7 +93,7 @@ Candidate history controls need concrete use cases and dangling tool-pair tests.
78
93
  - Skill filtering is model-visible prompt filtering, not an invocation or security boundary.
79
94
  - Delegation remains opt-in, foreground, clean-context, and fail-closed on missing capabilities, and lives in the optional package.
80
95
  - Do not report shared-user read-only policy as an OS sandbox.
81
- - New editor product workflows are frozen; migration changes retain real-browser coverage.
96
+ - New editor workflows remain frozen except the explicitly accepted capability surfaces above; migration and new workflows retain real-browser coverage.
82
97
  - Run the full verification and package checks before release.
83
98
 
84
99
  The detailed completed 0.4 plan is retained in the [historical roadmap](../design/roadmap-0.4-archive.md).
@@ -158,7 +158,7 @@ For compatibility:
158
158
 
159
159
  - Read legacy branch entries containing only `activeStackId` using effective lookup.
160
160
  - Write new entries with a scoped active-stack reference.
161
- - Preserve the explicit `none`/`off` selection as a scope-independent opt-out.
161
+ - Preserve the explicit `none`/`disable` selection as a scope-independent opt-out.
162
162
  - Profile provenance should add the profile scope/key while continuing to accept older provenance that has only `profileId` and `sourcePath`.
163
163
  - Drift snapshots should store the resolved scoped stack reference so status can distinguish definition changes from a scope change.
164
164
 
@@ -55,7 +55,7 @@ Set `CHROME_PATH` when Chrome/Chromium is outside a standard location. CI runs t
55
55
 
56
56
  ## Pi compatibility
57
57
 
58
- Published pi-forge treats Pi-owned SDK packages (`pi-agent-core`, `pi-ai`, `pi-coding-agent`, `pi-tui`, and `typebox`) as host-provided wildcard peers. The running Pi host supplies one coherent SDK instance, avoiding duplicate packages and avoiding an install-time lock to Pi's frequent release cadence.
58
+ Pi-forge treats Pi-owned SDK packages (`pi-agent-core`, `pi-ai`, `pi-coding-agent`, `pi-tui`, and `typebox`) as host-provided optional peers, not private runtime dependencies. The repository dev SDK is pinned to `0.87.0` and the peer requirement is `>=0.87.0 <0.88.0` for the four Pi SDK peers; `typebox` remains `*`. There is no claim of dual 0.86 runtime support. The running host supplies one coherent SDK instance, avoiding duplicate packages and exact-version locks while expressing the actual API requirement.
59
59
 
60
60
  The repository keeps exact SDK versions as development/test fixtures for reproducibility. Exact fixtures do not constrain which Pi version may load the published extension.
61
61
 
@@ -25,7 +25,7 @@ mkdir -p .pi/forge/prompt-stacks
25
25
  cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json
26
26
  ```
27
27
 
28
- When installed from npm, open `/preset ui` and create a stack; new stacks start from the same mirror layout.
28
+ Open `/forge ui` to create a preset without copying a file. In Forge 0.5.5, you can choose the default Pi mirror layout, an empty preset (where Pi retains its base prompt and history), or a minimal worker template (`bash` and `edit` only).
29
29
 
30
30
  Reload and activate it:
31
31
 
@@ -4,7 +4,10 @@
4
4
 
5
5
  > **Experimental:** This API and its backends may change independently of stable prompt-stack and profile behavior.
6
6
 
7
- The optional `@zihanw/pi-forge-subagents` package executes an explicitly authorized agent profile as a separate, clean, one-shot Pi process. It runs in the foreground and returns a bounded report to the parent conversation.
7
+ The optional `@zihanw/pi-forge-subagents` package executes an explicitly authorized agent profile through a selected backend. The default read-only backends use a separate, clean, one-shot Pi process; write-capable backends have different boundaries described below. The documented flow runs in the foreground and returns a bounded report to the parent conversation.
8
+
9
+ > **Default-tool compatibility:** Forge 0.5.5 provides `tools.initial`; the independently published optional subagents 0.5.3 is not compatible with this field. Until the optional package raises its Forge floor to `^0.5.5` and ships its separate fix, use matching local checkouts; see [tool-selection compatibility](../reference/subagent-host-port.md#tool-selection-compatibility). This optional compatibility work is not a main-package release gate.
10
+
8
11
 
9
12
  ## Enable a profile
10
13
 
@@ -43,7 +46,7 @@ Humans use:
43
46
 
44
47
  `plan` resolves the profile and stack, compiles and validates the exact immutable provider-bound plan, displays it, and discards it without provider transport.
45
48
 
46
- Profile selectors accept the same grammar everywhere: `reviewer` (project first), `project:reviewer`, or `global:reviewer`. When both scopes expose the same ID, the project profile keeps the concise selector and the global profile remains callable as `global:<id>`.
49
+ Profile selectors use the same grammar everywhere: `reviewer`, `project:reviewer`, or `global:reviewer`. For delegation, a bare ID selects `project:<id>`; use an explicit `global:<id>` selector for a global profile. Same-ID profiles remain separate and do not inherit delegation policy from one another.
47
50
 
48
51
  The parent model uses `forge_subagent_profiles` to discover enabled profiles and `forge_subagent` to invoke one. A restrictive parent stack must allow both tool names. Discovery is local/no-egress and reports metadata, resolution readiness, effective backend/timeout, approval mode, and whether parent tool policy permits invocation.
49
52
 
@@ -51,18 +54,20 @@ Projects with only a few frequently used profiles can set `summaryInToolDescript
51
54
 
52
55
  ## Parallel invocation
53
56
 
54
- `forge_subagent` is a parallel-execution tool: the parent model may issue several calls in one turn, and they prepare and run concurrently. Interactive approval dialogs are serialized one at a time because Pi's selector/editor UI is a single slot—a second concurrent dialog would clear the first and leave it unresolved—so each call waits its turn for the dialog and then executes immediately, letting approved runs overlap. Unattended invocation needs no dialog and is fully concurrent. Each run is an independent `pi` subprocess and provider request; a burst of parallel calls multiplies provider cost and process load, so keep the parent tool policy conservative until a configurable concurrency cap lands.
57
+ `forge_subagent` is a parallel-execution tool: the parent model may issue several calls in one turn, and they prepare and run concurrently. Interactive approval dialogs are serialized one at a time because Pi's selector/editor UI is a single slot—a second concurrent dialog would clear the first and leave it unresolved—so each call waits its turn for the dialog and then executes immediately, letting approved runs overlap. Unattended invocation needs no dialog and is fully concurrent. Fresh-process backends create an independent child process and provider request; `pi-inprocess` instead runs in the host runtime. A burst of parallel calls multiplies provider cost and process load, so keep the parent tool policy conservative until a configurable concurrency cap lands.
55
58
 
56
59
  ## Backends and precedence
57
60
 
58
- Two fresh-process backends are registered:
61
+ Matching development versions of the optional subagents package and runtime expose four backend IDs. These notes describe unfinished optional-package source, not a finalized companion release; the main Forge 0.5.5 package does not require them.
59
62
 
60
- - `pi-subprocess-readonly` is the default and uses `pi --mode text --print`.
61
- - `pi-rpc-readonly` uses `pi --mode rpc`.
63
+ - `pi-subprocess-readonly` is the default and uses `pi --mode text --print`. It exposes the `read`/`grep`/`find`/`ls` allowlist and is shared-user: the allowlist is not an OS sandbox.
64
+ - `pi-rpc-readonly` uses `pi --mode rpc` with the same shared-user read-only policy; only the process protocol differs.
65
+ - `pi-inprocess` runs in the host model runtime with the invoking user's full privileges. It is a workspace-write backend and can expose `read`/`grep`/`find`/`ls`/`edit`/`write`/`bash` when the sealed access level and stack policy allow them; it has no OS sandbox. It is the backend for extension-registered providers that cannot be used in fresh children.
66
+ - `pi-bwrap-write` is an opt-in Linux Bubblewrap backend. It provides an isolated `workspace-write` mount for the selected workspace and can expose `read`/`grep`/`find`/`ls`/`edit`/`write`/`bash` when allowed. Writes go directly to that workspace; they are not staged for a separate approval/apply step. Bubblewrap and, by default, a git workspace are required.
62
67
 
63
- Both execute the same sealed prompt and shared-user read-only policy; only their process protocol differs. There is no fallback if the selected backend is unavailable.
68
+ There is no fallback if the selected backend is unavailable. Fresh-process backends reject extension-registered providers as non-portable; use `pi-inprocess` for those providers. Do not read the development matrix or the `tools.initial` compatibility fix as a claim that the paired companion release is already published.
64
69
 
65
- Interactive backend precedence is: per-run override, project profile override, project default, user default, built-in default. Unattended model invocation is pinned to the effective configured backend and rejects a per-call override. Timeout follows profile, project, user, then the 60-second built-in default; valid values are 1,000–3,600,000 ms. Host timeout is best effort.
70
+ For human runs, backend precedence is: explicit per-run `--backend`, matching profile override, trusted project default, global default, then the built-in `pi-subprocess-readonly`. An interactive model invocation may also supply a per-call backend override; an unattended model invocation is pinned to the effective profile/configured backend and rejects that override. Timeout follows matching profile override, trusted project default, global default, then the 60-second built-in default; valid values are 1,000–3,600,000 ms. Host timeout is best effort.
66
71
 
67
72
  ## Approval and unattended invocation
68
73
 
@@ -76,28 +81,25 @@ To authorize the parent model without per-run approval:
76
81
  }
77
82
  ```
78
83
 
79
- This affects only `forge_subagent`; `/forge-agent run` remains interactive. It is ignored in untrusted projects and malformed values fail closed. Treat this project `subagents.json` as an authorization file: do not enable or commit it unless every parent agent allowed to call `forge_subagent` may send the compiled prompt and readable file contents to the selected provider without asking again.
84
+ This affects only `forge_subagent`; `/forge-agent run` remains interactive. The flag may come from global defaults or a trusted project file, with the project value taking precedence. With the unreleased companion fix, an absent flag inherits; an explicitly non-boolean value sets that layer to `false` and emits a warning. A valid boolean in a higher-priority layer still overrides normally. If an entire config file is unreadable, malformed, or not a JSON object, that file is ignored with a warning and an earlier valid layer may remain effective. An untrusted project's project settings are ignored, and the execution trust gate blocks delegation runs from that project. Treat `subagents.json` as an authorization file: do not enable or commit unattended invocation unless every permitted parent agent may send the compiled prompt and readable file contents to the selected provider without asking again.
80
85
 
81
86
  ## Child context and output
82
87
 
83
- The child receives a clean conversation, the exact profile model/thinking/stack, and the delegated task as a protected final user message. It does not automatically receive parent history.
88
+ An ordinary new child starts with a clean conversation, the exact profile model/thinking/stack, and the delegated task as a protected final user message. It does not automatically receive parent history. Explicit retained-child continuation and background execution are separate development features documented in the [companion package](https://github.com/MacroSony/pi-forge-subagents).
84
89
 
85
- Candidate tools are `read`, `grep`, `find`, and `ls`, further restricted by stack tool policy. The child loads no write/edit/shell tools, skills, prompt templates, project context files, or third-party extensions.
90
+ For `pi-subprocess-readonly` and `pi-rpc-readonly`, candidate tools are `read`, `grep`, `find`, and `ls`, further restricted by stack tool policy; these children load no write/edit/shell tools, skills, prompt templates, project context files, or third-party extensions. `pi-inprocess` and `pi-bwrap-write` can receive the write-capable tool surface described above only when their access level and stack policy allow it.
86
91
 
87
92
  The model-visible result is bounded. Expandable human details retain normalized status, a text transcript, tool events, diagnostics, usage, approval receipt, and execution report. Retained strings are bounded, base64-like text is redacted, and the transcript keeps a 512 KiB rolling tail. Inline image bytes are replaced by MIME/encoded-size metadata before retention in the parent session.
88
93
 
89
94
  ## Security boundary
90
95
 
91
- The current backends are **shared-user, not operating-system sandboxes**.
96
+ The security boundary is backend-specific:
92
97
 
93
- - “Read-only” is a model-tool policy. The process retains the invoking user's OS permissions.
94
- - Absolute paths readable by that user may be read and sent to the selected provider.
95
- - Text may be retained in parent tool-result details and Pi's on-disk session JSONL.
96
- - Timeout and cancellation are best effort.
97
- - `/tree` changes the active conversation branch; abandoned entries can remain on disk.
98
- - `/tree` cannot undo provider requests, billing, or external effects.
99
- - Removing sensitive retained text requires deleting the relevant Pi session data.
98
+ - The subprocess and RPC read-only backends are **shared-user, not OS sandboxes**. “Read-only” is a model-tool policy; the child retains the invoking user's OS permissions. Absolute paths readable by that user may be read and sent to the selected provider.
99
+ - `pi-inprocess` is also shared-user and runs in the host process with full user privileges. Its allowlist can permit write/edit/`bash`, but it provides no OS isolation.
100
+ - `pi-bwrap-write` is the isolated Linux exception: Bubblewrap exposes the selected workspace as the writable project mount, alongside read-only runtime mounts and temporary sandbox storage. It is not a staged patch/apply workflow, and it does not provide network isolation.
101
+ - Across backends, timeout and cancellation are best effort. Text may be retained in parent tool-result details and Pi's on-disk session JSONL; `/tree` cannot undo provider requests, billing, or external effects, and abandoned entries can remain on disk. Removing sensitive retained text requires deleting the relevant Pi session data.
100
102
 
101
- The default tools intentionally provide no mutation path. Do not add write, edit, or shell access to this shared-user design. OS isolation and separately approved staged writes remain future work.
103
+ Choose a read-only backend when no mutation path is intended. Treat write-capable backends as explicit authorization to modify the selected workspace, not as a promise of separately approved staged changes.
102
104
 
103
105
  For integration authors, see the [subagent host port contract](../reference/subagent-host-port.md).
@@ -101,6 +101,35 @@ Subagent execution moved out of the main package into the optional `@zihanw/pi-f
101
101
  | `@zihanw/pi-forge/src/*` aliases | removed; no replacement (internals) |
102
102
  | root loader/profile/catalog/engine re-exports | removed; no replacement (internals) |
103
103
 
104
+ ## Upstream Pi 0.87 migration
105
+
106
+ Forge 0.5.5 requires upstream Pi `>=0.87.0 <0.88.0`. Dual 0.86 runtime support is not provided (repo dev SDK is pinned to `0.87.0`, peer range `>=0.87.0 <0.88.0`). Main and optional packages release independently.
107
+
108
+ **Restart Pi after upgrading:** Updating the global installation does not replace the core in already-running processes. If the session predates the upgrade, exit and start Pi again before resuming it; extension-only `/reload` does not upgrade the running core. Use the new `/preset ui` URL; old server tokens are not retained.
109
+
110
+ ### Context hook migration (`context_with_system`)
111
+
112
+ - **Standard `context` excludes System:** In Pi 0.87, standard `context` lifecycle hooks intentionally exclude System messages. Any prior extension or custom integration that inspected, modified, or relied upon full System context must move to the full `context_with_system` hook.
113
+ - **Unified Forge pipeline:** Forge moves its entire compiler, base prompt replacement, and capability projection pipeline together to `context_with_system`, operating cleanly at the full-transcript boundary without an internal two-phase split.
114
+ - **`before_agent_start` timing:** Any forced System prompt injection via `before_agent_start` continues to execute later in Pi's lifecycle than `context_with_system`.
115
+
116
+ ### Canonical projection and session history
117
+
118
+ - **`buildSessionProjection` integration:** Runtime execution, the Preview dock, and anchor locator helpers now use Pi 0.87's `buildSessionProjection`. Turn-level `context_edit` omissions, replacements, and `sourceEntry` references are reflected in ephemeral model requests while raw session JSONL history on disk remains untouched.
119
+ - **Leading System message ordering:** The SDK's incoming leading System message always remains first in the request transcript; Forge's own prefix plain metadata anchors are inserted immediately after it, never displacing the request head or user fallback.
120
+ - **Arbitrary preceding rewrites fail closed:** Third-party extensions performing arbitrary message rewrites prior to Forge must maintain unique ordered alignment with the canonical session projection. Ambiguous or destructive preceding rewrites still fail closed.
121
+
122
+ ### Continuations and settlement lifecycle
123
+
124
+ - **`agent_end` vs. `agent_settled`:** `agent_end` offers an anchor boundary after a low-level run, provided no Forge context failure or incomplete tool batch remains. However, the compile cycle and busy fence reset only on `agent_settled`. This guarantees that `agent_before_settle` continuations preserve compiled Preset inputs and active capabilities across low-level runs without dropping prompt context.
125
+
126
+ ### Guardrails and semantics unchanged
127
+
128
+ - **Project trust:** Activations and Agent control require an explicitly trusted project (`isProjectTrusted()`); human CLI disable/reset recovery remains available.
129
+ - **`sourceRevision` stale-save guard:** Existing capability updates/deletes and binding-bearing Preset updates must match the loaded source revision; capability creation must not overwrite an existing file. Stale saves fail with `409 Conflict`.
130
+ - **Save ≠ Enable:** Saving a capability library definition updates its file only and does not enable it in the session; saving an active Preset refreshes that Preset's policy immediately (updating live tool and capability authorization policy), without replacing frozen active capability snapshots.
131
+ - **Upstream defect status:** Upstream Pi metadata chunking and semantic-cut defects are NOT patched; compaction checkpoint placement is unchanged. Existing legacy session carriers remain untouched without automatic migration, and Oh My Pi (OMP) is not supported or promised.
132
+
104
133
  ## Compatibility notes
105
134
 
106
135
  - The wire shape of the host port is additive across `FORGE_HOST_PORT_VERSION = 1`; unknown operations are rejected with a plain `{ ok: false, error }` result (`"Unknown Forge host operation: …"`), not a thrown error, and optional packages must treat any operation failure as terminal for that request.
@@ -36,7 +36,7 @@ Keep independent project files:
36
36
  translator.json
37
37
  ```
38
38
 
39
- Switch with `/preset use coder`, `/preset use writer`, or `/preset use translator`. Capture a profile when a mode also needs a specific model and thinking level.
39
+ Switch with `/preset use coder`, `/preset use writer`, or `/preset use translator`. Capture a profile when a capability also needs a specific model and thinking level.
40
40
 
41
41
  ## Read-only scout
42
42
 
@@ -44,13 +44,17 @@ Allow only `read`, `grep`, `find`, and `ls`, omit editing tools, and cap chat hi
44
44
 
45
45
  Tool policy constrains model tool calls but is not an operating-system sandbox. A normal Pi agent may still have other non-tool ways to interact with its host; do not describe a prompt stack alone as process isolation.
46
46
 
47
+ ## Read first, enable command/edit tools on demand
48
+
49
+ The [Read-first Worker pair](../reference/capabilities.md#read-first-worker) keeps the minimal-worker shape: one role block and chat history. Defaults are `read` and `ls` plus `forge_capability`; one explicitly authorized binding adds `bash` and `edit`. Follow the paired-file setup and ownership/sandbox caveats before trying it.
50
+
47
51
  ## Surgical patcher
48
52
 
49
53
  Keep the Pi mirror, require the tools needed for the workflow, strip prior assistant thinking from inserted history, and move project context near the current user turn. This reduces distracting prompt material without removing relevant repository instructions.
50
54
 
51
55
  ## Payload lab
52
56
 
53
- Include `active-model` and `date-cwd`, then add compiled regex rules for deterministic redaction or formatting. Pair the stack with `/payload next` or the web editor's capture view to audit exactly what changed.
57
+ Include `active-model` and `date-cwd`, then add compiled regex rules for deterministic redaction or formatting. Pair the stack with `/forge payload next` (or bare `/payload`) or the web editor's capture view to audit exactly what changed. Use `save="path with spaces.json"` when saving a capture; existing files require `--overwrite`.
54
58
 
55
59
  Redaction is limited to the declared patterns and supported text targets. It is useful for known shapes but is not an exhaustive credential scanner or security boundary.
56
60