@zihanw/pi-forge 0.5.4 → 0.5.6

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 (237) hide show
  1. package/CHANGELOG.md +83 -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 +1 -0
  32. package/dist/agent-profile.d.ts.map +1 -1
  33. package/dist/agent-profile.js +20 -14
  34. package/dist/agent-profile.js.map +1 -1
  35. package/dist/capabilities.d.ts +39 -0
  36. package/dist/capabilities.d.ts.map +1 -0
  37. package/dist/capabilities.js +160 -0
  38. package/dist/capabilities.js.map +1 -0
  39. package/dist/capability-anchors.d.ts +45 -0
  40. package/dist/capability-anchors.d.ts.map +1 -0
  41. package/dist/capability-anchors.js +263 -0
  42. package/dist/capability-anchors.js.map +1 -0
  43. package/dist/capability-command.d.ts +4 -0
  44. package/dist/capability-command.d.ts.map +1 -0
  45. package/dist/capability-command.js +164 -0
  46. package/dist/capability-command.js.map +1 -0
  47. package/dist/capability-events.d.ts +79 -0
  48. package/dist/capability-events.d.ts.map +1 -0
  49. package/dist/capability-events.js +478 -0
  50. package/dist/capability-events.js.map +1 -0
  51. package/dist/capability-projection.d.ts +22 -0
  52. package/dist/capability-projection.d.ts.map +1 -0
  53. package/dist/capability-projection.js +273 -0
  54. package/dist/capability-projection.js.map +1 -0
  55. package/dist/capability-protocol.d.ts +21 -0
  56. package/dist/capability-protocol.d.ts.map +1 -0
  57. package/dist/capability-protocol.js +15 -0
  58. package/dist/capability-protocol.js.map +1 -0
  59. package/dist/capability-state.d.ts +74 -0
  60. package/dist/capability-state.d.ts.map +1 -0
  61. package/dist/capability-state.js +43 -0
  62. package/dist/capability-state.js.map +1 -0
  63. package/dist/capability-tool.d.ts +11 -0
  64. package/dist/capability-tool.d.ts.map +1 -0
  65. package/dist/capability-tool.js +25 -0
  66. package/dist/capability-tool.js.map +1 -0
  67. package/dist/capability-web-host.d.ts +11 -0
  68. package/dist/capability-web-host.d.ts.map +1 -0
  69. package/dist/capability-web-host.js +105 -0
  70. package/dist/capability-web-host.js.map +1 -0
  71. package/dist/codecs/capability.d.ts +71 -0
  72. package/dist/codecs/capability.d.ts.map +1 -0
  73. package/dist/codecs/capability.js +363 -0
  74. package/dist/codecs/capability.js.map +1 -0
  75. package/dist/codecs/prompt-stack.d.ts +1 -1
  76. package/dist/codecs/prompt-stack.d.ts.map +1 -1
  77. package/dist/codecs/prompt-stack.js +140 -13
  78. package/dist/codecs/prompt-stack.js.map +1 -1
  79. package/dist/command-contribution/index.d.ts +21 -0
  80. package/dist/command-contribution/index.d.ts.map +1 -0
  81. package/dist/command-contribution/index.js +14 -0
  82. package/dist/command-contribution/index.js.map +1 -0
  83. package/dist/compile-cycle.d.ts +1 -0
  84. package/dist/compile-cycle.d.ts.map +1 -1
  85. package/dist/compile-cycle.js.map +1 -1
  86. package/dist/compiler.d.ts.map +1 -1
  87. package/dist/compiler.js +81 -17
  88. package/dist/compiler.js.map +1 -1
  89. package/dist/forge-command.d.ts +10 -0
  90. package/dist/forge-command.d.ts.map +1 -0
  91. package/dist/forge-command.js +106 -0
  92. package/dist/forge-command.js.map +1 -0
  93. package/dist/index.d.ts +2 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +58 -5
  96. package/dist/index.js.map +1 -1
  97. package/dist/json-fingerprint.d.ts +11 -0
  98. package/dist/json-fingerprint.d.ts.map +1 -0
  99. package/dist/json-fingerprint.js +66 -0
  100. package/dist/json-fingerprint.js.map +1 -0
  101. package/dist/lifecycle.d.ts +14 -0
  102. package/dist/lifecycle.d.ts.map +1 -1
  103. package/dist/lifecycle.js +167 -67
  104. package/dist/lifecycle.js.map +1 -1
  105. package/dist/payload-command.d.ts +2 -2
  106. package/dist/payload-command.d.ts.map +1 -1
  107. package/dist/payload-command.js +80 -26
  108. package/dist/payload-command.js.map +1 -1
  109. package/dist/payload-state.d.ts +1 -0
  110. package/dist/payload-state.d.ts.map +1 -1
  111. package/dist/payload-state.js +1 -0
  112. package/dist/payload-state.js.map +1 -1
  113. package/dist/policy.d.ts +2 -1
  114. package/dist/policy.d.ts.map +1 -1
  115. package/dist/policy.js +3 -0
  116. package/dist/policy.js.map +1 -1
  117. package/dist/preset-command.d.ts +1 -0
  118. package/dist/preset-command.d.ts.map +1 -1
  119. package/dist/preset-command.js +94 -36
  120. package/dist/preset-command.js.map +1 -1
  121. package/dist/preview-text.d.ts +5 -0
  122. package/dist/preview-text.d.ts.map +1 -0
  123. package/dist/preview-text.js +27 -0
  124. package/dist/preview-text.js.map +1 -0
  125. package/dist/preview.d.ts +18 -1
  126. package/dist/preview.d.ts.map +1 -1
  127. package/dist/preview.js +132 -97
  128. package/dist/preview.js.map +1 -1
  129. package/dist/profile-command.js +68 -9
  130. package/dist/profile-command.js.map +1 -1
  131. package/dist/regex.d.ts.map +1 -1
  132. package/dist/regex.js +5 -0
  133. package/dist/regex.js.map +1 -1
  134. package/dist/render-helpers.d.ts.map +1 -1
  135. package/dist/render-helpers.js +2 -0
  136. package/dist/render-helpers.js.map +1 -1
  137. package/dist/repositories/capability.d.ts +53 -0
  138. package/dist/repositories/capability.d.ts.map +1 -0
  139. package/dist/repositories/capability.js +294 -0
  140. package/dist/repositories/capability.js.map +1 -0
  141. package/dist/runtime/capability-runtime.d.ts +93 -0
  142. package/dist/runtime/capability-runtime.d.ts.map +1 -0
  143. package/dist/runtime/capability-runtime.js +987 -0
  144. package/dist/runtime/capability-runtime.js.map +1 -0
  145. package/dist/runtime/profile-runtime.d.ts.map +1 -1
  146. package/dist/runtime/profile-runtime.js +10 -9
  147. package/dist/runtime/profile-runtime.js.map +1 -1
  148. package/dist/runtime/prompt-stack-runtime.d.ts +7 -4
  149. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
  150. package/dist/runtime/prompt-stack-runtime.js +47 -11
  151. package/dist/runtime/prompt-stack-runtime.js.map +1 -1
  152. package/dist/runtime/tool-policy-runtime.d.ts +10 -0
  153. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
  154. package/dist/runtime/tool-policy-runtime.js +171 -30
  155. package/dist/runtime/tool-policy-runtime.js.map +1 -1
  156. package/dist/session-adapter.d.ts +13 -0
  157. package/dist/session-adapter.d.ts.map +1 -1
  158. package/dist/session-adapter.js +110 -0
  159. package/dist/session-adapter.js.map +1 -1
  160. package/dist/session-usage.d.ts +65 -0
  161. package/dist/session-usage.d.ts.map +1 -0
  162. package/dist/session-usage.js +134 -0
  163. package/dist/session-usage.js.map +1 -0
  164. package/dist/subagent/fingerprints.d.ts +3 -15
  165. package/dist/subagent/fingerprints.d.ts.map +1 -1
  166. package/dist/subagent/fingerprints.js +5 -69
  167. package/dist/subagent/fingerprints.js.map +1 -1
  168. package/dist/subagent/index.d.ts +2 -0
  169. package/dist/subagent/index.d.ts.map +1 -1
  170. package/dist/subagent/index.js +2 -0
  171. package/dist/subagent/index.js.map +1 -1
  172. package/dist/subagent-host.d.ts +2 -2
  173. package/dist/subagent-host.d.ts.map +1 -1
  174. package/dist/subagent-host.js +13 -1
  175. package/dist/subagent-host.js.map +1 -1
  176. package/dist/types.d.ts +6 -1
  177. package/dist/types.d.ts.map +1 -1
  178. package/dist/types.js.map +1 -1
  179. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  180. package/dist/web-editor/client-script.generated.js +1 -1
  181. package/dist/web-editor/client-script.generated.js.map +1 -1
  182. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  183. package/dist/web-editor/client-styles.generated.js +1 -1
  184. package/dist/web-editor/client-styles.generated.js.map +1 -1
  185. package/dist/web-editor/server.d.ts.map +1 -1
  186. package/dist/web-editor/server.js +152 -4
  187. package/dist/web-editor/server.js.map +1 -1
  188. package/dist/web-editor/styles.d.ts.map +1 -1
  189. package/dist/web-editor/styles.js +573 -165
  190. package/dist/web-editor/styles.js.map +1 -1
  191. package/dist/web-editor/types.d.ts +81 -1
  192. package/dist/web-editor/types.d.ts.map +1 -1
  193. package/dist/web-host.d.ts +9 -0
  194. package/dist/web-host.d.ts.map +1 -1
  195. package/dist/web-host.js +210 -11
  196. package/dist/web-host.js.map +1 -1
  197. package/dist/workspace.d.ts +11 -0
  198. package/dist/workspace.d.ts.map +1 -1
  199. package/dist/workspace.js +63 -5
  200. package/dist/workspace.js.map +1 -1
  201. package/docs/README.md +4 -0
  202. package/docs/design/README.md +3 -1
  203. package/docs/design/architecture-0.5.md +22 -0
  204. package/docs/design/archive/2026-09-12-system-update-design.md +229 -0
  205. package/docs/design/pi-forge-system-update-design-notes.md +157 -229
  206. package/docs/development/release.md +20 -20
  207. package/docs/development/roadmap.md +21 -2
  208. package/docs/development/scoped-global-profiles-stacks.md +1 -1
  209. package/docs/development/setup.md +1 -1
  210. package/docs/getting-started.md +1 -1
  211. package/docs/guides/delegation.md +22 -20
  212. package/docs/guides/migrating-to-0.5.md +29 -0
  213. package/docs/guides/use-cases.md +6 -2
  214. package/docs/guides/web-editor.md +74 -5
  215. package/docs/reference/active-state.md +77 -0
  216. package/docs/reference/capabilities.md +259 -0
  217. package/docs/reference/commands.md +52 -24
  218. package/docs/reference/configuration.md +4 -2
  219. package/docs/reference/features.md +70 -4
  220. package/docs/reference/provider-support.md +67 -0
  221. package/docs/reference/public-api.md +49 -3
  222. package/docs/reference/session-cache.md +112 -0
  223. package/docs/reference/stack-schema.md +18 -4
  224. package/docs/reference/subagent-host-port.md +8 -0
  225. package/docs/zh-CN/README.md +3 -0
  226. package/docs/zh-CN/getting-started.md +1 -1
  227. package/docs/zh-CN/guides/delegation.md +22 -10
  228. package/docs/zh-CN/guides/migrating-to-0.5.md +29 -0
  229. package/docs/zh-CN/guides/web-editor.md +75 -7
  230. package/docs/zh-CN/reference/capabilities.md +259 -0
  231. package/docs/zh-CN/reference/commands.md +61 -33
  232. package/docs/zh-CN/reference/provider-support.md +67 -0
  233. package/docs/zh-CN/reference/session-cache.md +112 -0
  234. package/examples/capabilities/review.json +12 -0
  235. package/examples/capabilities/write-tools.json +15 -0
  236. package/examples/read-first-worker-prompt-stack.json +49 -0
  237. package/package.json +16 -9
@@ -0,0 +1,259 @@
1
+ # Capabilities (`/capability`)
2
+
3
+ [Documentation](../README.md) · [中文](../zh-CN/reference/capabilities.md)
4
+
5
+ Pi-forge introduces capabilities: session-scoped prompt directives paired with dynamic tool selection. `/capability` is the CLI command. This reference details configuration, CLI usage, Web editing, Agent controls, delivery models, recovery boundaries, and compatibility limits.
6
+
7
+ ## Requirements and installation
8
+
9
+ - **Host requirement:** Pi `>=0.87.0 <0.88.0` (repository dev SDK pinned to `0.87.0`, peer range `>=0.87.0 <0.88.0`; min SDK 0.87 unchanged; no dual 0.86 runtime support claim). Capabilities require Forge 0.5.5.
10
+ - **Project trust:** Activating capabilities, preset bindings, or manual directives requires a trusted project (`isProjectTrusted()`).
11
+ - **Compatibility:** Configurations utilizing `tools.initial` require a Forge version with this support; older Forge versions may ignore `initial`, so configurations are not downgrade-compatible.
12
+
13
+ Capabilities are JSON files stored in:
14
+
15
+ - **Project scope:** `.pi/forge/capabilities/<id>.json`
16
+ - **Global scope:** `~/.pi/forge/capabilities/<id>.json`
17
+
18
+ ```json
19
+ {
20
+ "schemaVersion": 1,
21
+ "type": "pi-forge.capability",
22
+ "id": "review",
23
+ "name": "Review",
24
+ "description": "Report findings and evidence before editing.",
25
+ "content": "List findings, evidence, and risks. Do not directly edit files.",
26
+ "tools": {
27
+ "add": [],
28
+ "remove": ["bash", "powershell", "write", "edit"]
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### Resource rules
34
+
35
+ - **Literal content:** `content` is literal text (up to 100,000 characters). It is not a file path, script, or macro; template variables are not expanded.
36
+ - **Tool identifiers:** Names in `add` and `remove` arrays must be exact tool names (up to 128 characters, no whitespace, control characters, or wildcards `*`/`?`, max 256 tools per array).
37
+ - **Tool patch constraints:** Capabilities support `add` and `remove` ONLY; candidate `only` or capability-level allowlists are not implemented.
38
+ - **Resolution and shadowing:** Bare selectors use project-over-global shadowing. If a project capability contains invalid JSON, resolution fails closed locally; it does not fall back to global. Exact scopes can be targeted using `project:<id>` or `global:<id>`.
39
+
40
+ ## Ownership scopes and lifecycle
41
+
42
+ - **Owner scopes:** Definitions (capabilities) are reusable resources stored in project or global libraries. Authorizations and bindings belong to Presets (top-level `capabilities` array in the Preset JSON). Active state and activations belong strictly to Sessions.
43
+ - **Direct vs. bound use:**
44
+ - Direct activation via CLI (`/capability enable <[scope:]id>`) or Web library activation creates an *unbound* session activation.
45
+ - Bound activation via CLI (`/capability enable-bound <id>`) or Web preset binding activation creates a *preset-bound* session activation tied to the active Preset.
46
+ - **Immutable snapshot semantics:** Activation captures an immutable snapshot (`content`, `tools`, `fingerprint`). Modifying or deleting capability files on disk does not mutate already active session snapshots.
47
+ - **Same-Preset reload vs. switching:** Reloading the same Preset retains immutable active snapshots. Switching Presets automatically retires (lifecycle-deactivates) old bound activations while retaining manual and unbound user rules. A switch first checks the surviving capabilities against the target tool policy; a conflict rejects the switch without changing the current selection, tools, or activation events. Disable the conflicting capability before retrying. This does not retroactively modify frozen snapshots when their source files change.
48
+ - **Revocation behavior:** Revoking a binding's authorization (`modelCallable: false`) or removing the binding from the Preset does not retroactively erase active snapshots; human CLI (`/capability disable` or `/capability reset`) or Web panel deactivation is the recovery path.
49
+ - **User vs. Agent ownership and deduplication:** Activations record actor attribution (`user` vs `agent`). Repeated `enable` of an already active capability is idempotent and never performs an automatic owner takeover between user and agent. Takeover requires an explicit deactivation and reactivation cycle.
50
+
51
+ ## Preset-authorized Agent controls
52
+
53
+ Preset `capabilities` bindings support autonomous Agent activation when explicitly authorized:
54
+
55
+ - **Model-callable tool:** The fixed-schema `forge_capability` tool is registered once. Its visibility follows the normal executable tool selection; registration alone grants no capability authorization. Calls require an active Preset and enable/disable recheck the specific current binding.
56
+ - **Opt-in authorization:** Only bindings with `modelCallable: true` in the active Preset may be activated by the Agent; omission defaults to `false`.
57
+ - **Fixed parameter schema:** Accepts only `{ action: "list" | "status" | "enable" | "disable", id?: string }` (ID ≤ 128 characters).
58
+ - `list`: lists currently eligible bound capabilities for the active Preset; use `status` to inspect active snapshots.
59
+ - `status`: returns session active capability count, presentation model, delivery state, and effective tools.
60
+ - `enable`: requires binding `id`. Activates only authorized preset-bound capabilities with `modelCallable: true`.
61
+ - `disable`: requires `id` (binding ID or activation UUID). Stops only activations owned by the `agent`.
62
+ - **Safety and ownership fences:**
63
+ - Rechecks project trust, active Preset, binding identity, `modelCallable: true`, and current tool policy on every call.
64
+ - The Agent cannot stop human-owned activations.
65
+ - The Agent cannot invoke `reset` or add arbitrary prompt directives.
66
+ - The Agent cannot activate a capability that removes `forge_capability`.
67
+ - Disposed, restoring, or cross-session re-entry requests fail closed immediately.
68
+
69
+ Agent list/status replies intentionally omit full rule bodies: list returns authored descriptions and effects; status reports activity metadata. This avoids duplicating request-only instructions into ordinary tool history and later summaries. Human CLI/Web inspection still displays the complete frozen content. Genuine dialogue and authored descriptions are not scrubbed.
70
+
71
+ ### Read-first Worker
72
+
73
+ A minimal main-package example pair: [Preset](../../examples/read-first-worker-prompt-stack.json) and [Write tools capability](../../examples/capabilities/write-tools.json). Use Forge 0.5.5; older published Forge may ignore `tools.initial`. Optional subagent execution remains an independent unfinished release.
74
+
75
+ 1. In a trusted scratch project, copy the Preset to `.pi/forge/prompt-stacks/read-first-worker.json` and the capability to `.pi/forge/capabilities/write-tools.json`. Check for existing files first; do not overwrite your own resources. Importing the Preset alone does not install its referenced capability.
76
+ 2. Start a fresh Pi session with Forge loaded, run `/preset reload`, then `/preset use project:read-first-worker`. The example has `autoActivate: false` and uses a **project-scoped** binding; a global copy needs a global capability and an updated `ref`.
77
+ 3. With no other active capabilities, defaults are `read`, `ls`, and `forge_capability`. The latter is a capability-management tool, not a file-writing tool. The model can list authorized bindings with `{ "action": "list" }`, enable commands/edits with `{ "action": "enable", "id": "write-tools" }`, then disable its own activation with `{ "action": "disable", "id": "write-tools" }`.
78
+ 4. Observe `read, ls, forge_capability` → plus `bash, edit` → defaults again in **Current session** or `/capability status`. Other active capabilities still participate. If a human enabled the capability instead, the model cannot turn that human-owned activation off; stop it from the UI or `/capability disable <activation-id>`.
79
+
80
+ `allow` is the ceiling; `initial` selects defaults; `modelCallable: true` explicitly authorizes this binding without a new human approval prompt on each use. Change it to `false` if you want human-only activation. Off is requested by the sample prompt, not automatically enforced at task completion. It neither undoes changes nor terminates running tools. **Read-first is not a read-only sandbox:** `bash` can execute arbitrary commands, not just write files; these settings provide no filesystem/process isolation. This deliberately minimal replacement prompt omits Pi's normal project-context, skill and guidance slots; fork the default Pi mirror when you need them.
81
+
82
+ ## Commands
83
+
84
+ Manage active instructions through the `/capability` command:
85
+
86
+ | Command | Behavior |
87
+ |---|---|
88
+ | `/capability list` | Explicitly reload the capability library and list available capabilities with validation status. |
89
+ | `/capability bindings` | List capability bindings declared in the active Preset, including human-only bindings. |
90
+ | `/capability enable <[scope:]id>` | Select and activate an unbound library capability (bare ID or qualified selector). |
91
+ | `/capability enable-bound <id>` | Activate a Preset binding by ID as a human; `modelCallable` is not required. |
92
+ | `/capability status` | Show active capability count, presentation model, delivery state, and selected tools. |
93
+ | `/capability disable <activation-or-capability-id>` | Deactivate an active capability by activation UUID or capability ID. |
94
+ | `/capability reset` | Deactivate all active capabilities and manual directives (user only). |
95
+ | `/capability add <text>` | Append a manual literal instruction rule to the active session without tool changes. |
96
+ | `/capability help` | Show command usage and command details. |
97
+
98
+ Completions use the current session and last published workspace snapshot. They do not perform discovery on every keystroke. Run `/capability list` when an explicit discovery refresh is needed. `/capability enable` completions offer bare IDs when unique, and qualified selectors on same-ID collision or when typing a `:` scope prefix (with labels always qualified by source and name). Human-only bindings remain in `bindings`; `modelCallable: false` prevents Agent control but does not filter the binding from human inspection or activation.
99
+
100
+ **No inference cost:** All `/capability` commands and Web activity panel actions execute locally. They update internal session state and synchronize tool policies without starting model inference or consuming API tokens for the operation itself. Instruction text consumes input tokens on subsequent model requests when inference occurs.
101
+
102
+ ## Web resource editing
103
+
104
+ ### Capabilities surface (CRUD)
105
+
106
+ The top-level **Capabilities** navigation surface supports full project and global capability management. Its library API is `GET /api/capabilities`, with selector and effective variants at `/api/capabilities/<selector>` and `/api/capabilities/effective`.
107
+
108
+ - **Browse and inspect:** View capability ID, display name, description, instruction text, and tool modifications (`+add`, `-remove`), with validation diagnostics.
109
+ - **Create:** Author new capabilities in explicit project (`.pi/forge/capabilities/`) or global (`~/.pi/forge/capabilities/`) scope.
110
+ - **Edit and Save:** Edit display name, description, instruction content, and tool additions/removals. Capability IDs are immutable on save.
111
+ - **Grouped tool picker:** Capability tool selection (`+add` / `-remove`) includes a grouped picker organized by SDK `sourceInfo` (Pi built-in tools, packages, and top-level entry points). The picker saves exact concrete tool names: it does not persist package references or auto-install packages, and newly introduced tools from packages are not automatically added. Inactive registered tools remain visible in the picker; unloaded tools are unavailable in the session, but manually saved references are not discarded.
112
+ - **Delete:** Delete capability JSON files with confirmation.
113
+ - **Stale-save protection (`sourceRevision`):** Save and delete operations require the displayed `sourceRevision` (sha256 of raw source bytes). Stale requests fail with `409 Conflict`, preserving the user's draft in the editor.
114
+ - **Resource safety and save execution impact:** Saving a capability updates its library definition only and never activates it into the active session. Invalid JSON fails closed locally with diagnostics. Symlink targets and directories cannot be mutated.
115
+
116
+ ### Preset Capability bindings tab
117
+
118
+ In the Preset editor, capability bindings are configured under the dedicated peer **Capability bindings** tab (`bindings`); Preset metadata no longer contains bindings:
119
+
120
+ - **Qualified capability reference:** Requires a qualified reference (`project:<id>` or `global:<id>`).
121
+ - **Binding ID and metadata:** Unique binding identifier within the Preset; activation controls accept IDs up to 128 characters.
122
+ - **Agent authorization:** Toggle `modelCallable` (defaults to `false`) to permit Agent selection via `forge_capability`.
123
+ - **Collapsed advanced section:** Overrides and source-effective preview are collapsed under an advanced section to keep the primary binding list clear.
124
+ - **Finite overrides:**
125
+ - **Content override:** Choose between *None (use base content)*, *Replace* (`content`), or *Append* (`appendContent`, separated by two newlines).
126
+ - **Tool overrides:** Independently choose *Inherit* (omit the field) or *Custom override* (literal list, including explicit `[]` to clear the source list), with the integrated tool picker.
127
+ - Arbitrary fields, scripts, or inheritance chains cannot be authored.
128
+ - **Source vs. effective preview:** Side-by-side comparison displays source content/tools alongside effective content/tools, resolved through the same server resolver (`resolveCapabilityBindings`) as runtime activation.
129
+ - **Stale-save guard:** Preset saves enforce a `sourceRevision` check against disk bytes whenever bindings are present or modified, rejecting stale overwrites (409 Conflict), including when external edits added bindings.
130
+ - **Preset save execution impact:** Saving an inactive Preset updates its definition and does not select or activate it. Crucially, saving the currently active Preset immediately reloads and synchronizes its live tool and capability authorization policy in the session, without replacing frozen active capability snapshots. If the proposed policy conflicts with those snapshots, saving or overwriting the active Preset is rejected before writing the file; disable the conflicting capability and retry. Editing files outside Forge bypasses this preflight and may require manual recovery after reload.
131
+
132
+ ## Web session capabilities panel
133
+
134
+ The web editor retains a global **Session capabilities** summary linking to the non-modal **Current session** workspace: capability/tool controls beside the current session projection. The Preset editing workspace retains its own Preview/Draft diff/Run diff dock; navigation preserves unsaved edits and inspection layout.
135
+
136
+ ### State display and active capabilities
137
+
138
+ - **Active capabilities list:** Lists active capabilities and manual directives for the current session. Each card provides:
139
+ - **Identity and source:** Activation ID, display name, and resolved source (e.g. `project:review`, `global:review`, or `manual`).
140
+ - **Actor:** Attribution indicating whether the capability was activated by the `user` or an `agent`.
141
+ - **Frozen snapshot content:** A visible excerpt plus an expandable view of the exact literal rule text captured upon activation.
142
+ - **Tool adjustments and effective tools:** Cards label configured patches separately from current effective tools. The latest successful action in this browser shows observed net additions/removals; overlapping Capabilities can leave the effective set unchanged.
143
+ - **Delivery and presentation indicators:**
144
+ - **Delivery status:** Displays `none` (no capability events recorded yet), `pending` (updates queued for next request), or `prepared` (request context assembled for the current turn). The panel notes that `prepared` indicates prompt context preparation only, not remote model compliance or delivery confirmation.
145
+ - **Text presentation:** Indicates whether capability instructions are projected as `native` system message sections or attributed `user` timeline updates.
146
+ - **Session controls:**
147
+ - **Individual deactivation:** Click **Deactivate** to turn off a specific capability by its `activationId`.
148
+ - **Reset confirmation:** The **Reset all** button initiates a two-step confirmation prompt (**Confirm reset** / **Cancel**) before clearing active capabilities and manual directives.
149
+ - **Prompt cache usage:** When prompt caching statistics exist on the current branch, the panel renders prompt-cache hit rates and request counts for the current turn and session, maintaining visible separation between main assistant requests and nested tool runs. See [Session cache usage](session-cache.md).
150
+
151
+ ### Human activation picker (guarded preview and use)
152
+
153
+ The panel includes a human activation picker section:
154
+
155
+ - **Session projection (`GET /api/capability-state/preview`):** Read-only inspection of the active saved Preset and current capability snapshots, with session/leaf/revision and active-Preset fingerprint checks before and after compilation. The Preview sidecar links actual projected update blocks to activation IDs without modifying prompt messages. Requires a trusted session and active Preset; missing/stale context fails explicitly. This does not prepare a request, synchronize tools, or prove provider delivery/cache reuse.
156
+ - **Resource discovery (`GET /api/capability-state/available`):** Pure read-only endpoint returning current session state and available choices categorized into *Library capabilities (unbound)* and *Current preset (bound)*. Read operations never mutate tool policies or session events.
157
+ - **Explicit pre-activation preview:** Selecting a capability in the dropdown renders an immediate pre-activation preview card displaying:
158
+ - Label, ID, kind badge (`library` or `preset binding`), and short content fingerprint (`#<hash>`).
159
+ - Tool diff preview (`+add`, `-remove`, or `No tool changes`).
160
+ - Problem banner if the capability fails tool policy validation.
161
+ - Full literal instruction content.
162
+ - **Guarded activation (`POST /api/capability-state/enable`):**
163
+ - Payload sends `{ guard: { sessionId, leafId, revision }, kind, id, fingerprint }`.
164
+ - Server re-verifies session guard and content fingerprint against disk definitions before applying.
165
+ - If the session, branch, revision, or source file changed, the server rejects with `409 Conflict`.
166
+ - Never automatically infers or retries.
167
+ - Modifying requires project trust (`isProjectTrusted() === true`); untrusted sessions reject with `403 Forbidden`.
168
+
169
+ ### Polling, state guarding, and security
170
+
171
+ - **Visibility-based polling with zero inference:** The web client quietly polls `GET /api/capability-state` every 3 seconds only while visible (`document.visibilityState === "visible"`), on window focus, or via manual refresh. Catalog reads (`/api/capability-state/available`) happen on workspace entry, explicit refresh and mutation follow-up, not every status poll. Unchanged background checks do not toggle loading/disable controls. The session projection follows semantic state changes and ignores late responses after leaving. All queries are local reads with zero LLM inference cost.
172
+ - **Manual reconciliation on error or conflict:** Errors, stale state, or 409 Conflicts mark the view as stale and require manual review. Mutations do not blindly retry.
173
+ - **Project trust requirement:** Modifying session capabilities requires an explicitly trusted project (`isProjectTrusted() === true`). Untrusted sessions reject mutations with `403 Forbidden`; CLI recovery via `/capability reset` remains available.
174
+ - **State guard and lifecycle protection:** Mutations enforce derived guards (`sessionId`, `leafId`, `revision`). Unmounted or disposed runtimes return `503 Service Unavailable`.
175
+
176
+ ### Local developer testing and host reload
177
+
178
+ When testing in a local developer harness with local build wiring already configured:
179
+ - Hot reloading the Pi host requires the user to run `/reload` in the Pi console.
180
+ - If a web server was already active prior to `/reload`, run `/preset ui restart` in the host and open the newly returned URL. The pre-existing web server closure retains previous route handlers and will not pick up newly added routes upon host reload alone. Global host switching is not automatic.
181
+
182
+ ## Lifecycle and tool synchronization
183
+
184
+ - **Unified `context_with_system` pipeline:** In Pi 0.87, standard `context` lifecycle hooks intentionally exclude System messages. Forge moves the complete compiler, base prompt replacement, and capability projection pipeline to `context_with_system` without an internal two-phase split.
185
+ - **Canonical projection with `buildSessionProjection`:** Runtime, Preview, and anchor helpers build against Pi 0.87's canonical `buildSessionProjection` (handling `context_edit` omissions, replacements, and `sourceEntry`), ensuring ephemeral request assembly reflects turn edits while raw session history remains untouched on disk.
186
+ - **Leading System preservation:** SDK incoming leading System prompts remain first; Forge's own prefix plain metadata anchors are inserted immediately after it.
187
+ - **Continuation and settlement lifecycle:** `agent_end` remains an anchor opportunity after a low-level run, provided no Forge context failure or incomplete tool batch remains, but the compile cycle and busy fence reset only on `agent_settled`. This ensures `agent_before_settle` continuations preserve compiled Preset state without dropping active capabilities.
188
+ - **Immediate tool sync vs. next-request prompt projection:**
189
+ - Executable tool selection synchronizes *immediately* (`pi.setActiveTools()`). Disallowed tools are blocked at execution time.
190
+ - Prompt text and native System sections or fallback user updates apply at the *next model request* boundary.
191
+ - Running tool batches mid-flight are never interrupted.
192
+ - **Top-level policy precedence:** Capabilities cannot bypass Preset policies. If an active Preset denies a tool (`tools.deny`), a capability's `add` cannot enable it. Conflicting tool removals win globally across all active capabilities.
193
+ - **Baseline recovery:** Turning off a capability recomputes Preset defaults plus remaining active capabilities. When neither Preset tool selection nor capability overlays apply, Forge restores the reconciled session baseline, including preserved external changes. If a baseline cannot be recovered, Forge does not guess that all registered tools were previously active.
194
+ - **Parent lifecycle and re-entry fences:** Parent safeguards maintain `disposed` flags, `lifecycleRevision` counters, and strict `sameContext` verification, preventing cross-session pollution or operations after session disposal.
195
+
196
+ ## Previewing capability updates
197
+
198
+ The **Preview** dock evaluates the selected Preset draft against current session capability snapshots:
199
+
200
+ - Uses the same pure preset/capability projection as the request path: native named system sections or attributed user updates, including stop notices and compaction checkpoints.
201
+ - Delivery markers are pure metadata anchors and do not appear as dialogue messages.
202
+ - System body text, native named sections, and historical tool declarations are kept separate. Text copy contains only body/section values; inspector prose (`Added tool`, `Updated system prompt section`) is not inserted into native text.
203
+ - Historical tool declarations are collapsed and explicitly marked as not the current selection.
204
+ - Preview tool selection uses the evaluated draft policy plus current capability overlays.
205
+ - Text estimates exclude tool schemas and inspector labels; genuinely empty post-projection System cards are hidden.
206
+ - History is grouped only in consecutive runs: intervening capability updates stay in chronological position between surrounding messages.
207
+ - Pure read-only inspection: Preview never mutates tool policies, commits session events, runs inference, or marks pending capabilities prepared. Full preview text is not clipped at layout limits.
208
+
209
+ ## Delivery models: native vs. fallback
210
+
211
+ Forge projects capability deltas dynamically on each request through a two-stage assembly:
212
+
213
+ 1. **Materialize before compilation:** Session context entries are projected via `buildSessionProjection` and scanned for plain `custom` metadata anchors (`pi-forge-capability-delivery`). At the request context boundary (`prepareCapabilityMessages`), anchors are validated and materialized into ephemeral in-memory markers at their exact ordinal positions matching the canonical projection, without modifying stored dialogue or raw session history.
214
+ 2. **Rule projection:** `projectCapabilityMessages` transforms materialized deltas into the appropriate model presentation:
215
+ - **Native delivery:** When the provider supports mid-conversation system messages (`compat.supportsMidConvoSystemMessages === true`), updates are projected as request-only `SystemMessage.sections` keyed by activation identity (`forge-capability-<id>`). Deactivations send null patches. Native delivery depends strictly on provider capability flags and is not universally guaranteed.
216
+ - **Fallback delivery:** When native updates are unsupported, updates are projected as attributed timeline user messages (`[pi-forge capability update]`). Forge never folds updates into the leading system prompt; genuine user/tool dialogue is never promoted to system authority.
217
+ - **Tool-only capabilities:** A capability whose text is empty or whitespace-only sends no text update in either path — no section on activation, no removal notice when it stops, and nothing in compaction checkpoints. Only its tool changes reach the request, and **Current session** offers no Locate action for it.
218
+ - **Which path applies:** The choice is made on each request from the current model's `compat` entry in Pi's model catalog, which Pi fetches and caches locally and may change with updates. The provider name, authentication method, or an auth extension does not decide it, and models from one provider can differ. For example, the catalog observed on 2026-09-26 with Pi 0.87.1 flagged `anthropic/claude-opus-4-8`, `claude-opus-5`, and `claude-opus-5-5`, but not `anthropic/claude-sonnet-5`. Switching with `/model` changes delivery for later requests. `/capability status` and the Agent `status` action report `native system sections` or `attributed user updates`; check this before testing native updates or cache behavior. See [Provider support](provider-support.md) for the per-API behavior and flagged models recorded for Pi 0.87.1.
219
+ - **Fallback side effects:** For unflagged models, Pi also folds its own tool-change declarations into the leading system message and top-level tool list, so a tool change rewrites the start of the next request and its cached prefix is not reused. Some models may treat the labeled user update as untrusted text and question it before using the new tools.
220
+
221
+ ## Recovery and offline verification
222
+
223
+ Active state is derived deterministically from session events and delivery cursors (`throughEventId`):
224
+
225
+ - **Plain metadata delivery anchors:** Delivery markers are stored as plain `custom` session entries using the same delivery type (`pi-forge-capability-delivery`) with cursor-only metadata payload `{ schemaVersion: 1, throughEventId }`. They are not persisted as `custom_message` dialogue and do not use `sendMessage` steering. Idle updates anchor immediately; in-flight changes safely defer until after all tool results in a running batch complete; and `agent_end` anchors uncommitted deltas after the assistant's final response when no Forge context failure or incomplete batch remains. UI status notifications (`ctx.ui.setStatus`) are decoupled and never enqueue extra model turns.
226
+ - **Offline SDK verification:** State recovery across session reloads, manual compaction checkpoints, and branch tree navigation (`session.navigateTree`) is verified offline using SDK test harnesses. This confirms prompt assembly and tool gating, but does not provide an empirical guarantee of remote model compliance or obedience.
227
+ - **Compaction input and characterization:** Compaction checkpoints remain placed after the leading system prompt (`leadingSystem`) and before the compaction `summary` (placement unchanged; the upstream Pi metadata chunking bug is an independent issue and remains unfixed). Characterization tests verify real SDK summarization request inputs with simulated summaries. In this characterization, the summarizer observes user, assistant, and peer dialogue, but does not automatically receive new control metadata or request-only rule projections. Genuine dialogue quoting rule text is retained. Test-harness simulated responses verify request plumbing and harness shape, not remote LLM semantic compaction fidelity or summarizer compliance.
228
+ - **Breaking pre-release boundary:** This rename has no legacy aliases or readers. Existing development configs using instruction-mode keys, schemas, directories, or tool names must be converted to the new capability names, and sessions that contain the old capability state are unsupported for continuing that state. Forge does not rewrite old JSONL or historical summaries; start a new session after conversion rather than relying on partial restoration.
229
+ - **Session disk flushing:** In fresh sessions where only slash commands execute before the first assistant turn, Pi may not have flushed JSONL entries to disk yet.
230
+
231
+ ## Compatibility and security boundaries
232
+
233
+ - **Upstream Pi 0.87 required:** Upstream Pi `>=0.87.0 <0.88.0` is required. Dual 0.86 runtime support is not provided. Extensions that previously manipulated or inspected full System messages in `context` must migrate to the full `context_with_system` hook.
234
+ - **Timing with `before_agent_start`:** Any forced System prompt injection via `before_agent_start` continues to execute later than `context_with_system`.
235
+ - **Preceding extension message rewrites:** Pi permits context hooks to rewrite messages. When visible metadata anchors or unanchored events need positioning, Forge requires a unique ordered alignment with the canonical session projection and fails closed if arbitrary preceding rewrites break alignment. Pi may persist queued custom messages absent from a tool follow-up: Forge permits only uniquely alignable custom-message omissions, ignores their regenerated envelope timestamps, and preserves incoming objects without restoring omitted dialogue. A preceding rewrite can therefore conflict with this locator; moving it later does not guarantee safe composition. Broad plugin, warming, and automatic-overflow compatibility remain unverified.
236
+ - **Upstream defect status and protocol limits:** Upstream Pi metadata chunking and semantic-cut defects are NOT patched and remain unfixed upstream. Compaction checkpoint placement is unchanged. Old sessions and former delivery carriers remain untouched and unsupported for continuing capability state; Forge does not migrate old JSONL or rewrite historical summaries. Oh My Pi (OMP) is not supported or promised.
237
+ - **System prompt getters:** `ctx.getSystemPrompt()` and SDK getters return Pi's raw base prompt, not Forge's compiled request. Inspect compiled requests via `/forge payload` (bare `/payload` remains compatible) or Run context diffs. Forge does not claim to synchronize SDK getters. Extensions returning a full `systemPrompt` in lifecycle hooks cause forced projection conflicts and are unsupported.
238
+ - **Provider-managed tool transport and prompt caching:** Tool transport serialization and prompt prefix cache reuse are downstream provider-managed. Tool policy additions/removals, fallback formatting, and compaction alter prompt boundaries. For compatible Codex transports, clean first-time tool additions can retain request prefixes; removals or same-name redeclarations anywhere in retained history switch to full-current-tool serialization. Anthropic native tool changes and other per-API behavior are summarized in [Provider support](provider-support.md). Provider cache hits are not guaranteed. Pi-forge issues conservative provider-managed cache warnings and makes no permission bypass or caching guarantees (zero KV cache invalidation is not guaranteed).
239
+ - **Sandbox disclaimer:** Capabilities provide no OS-level sandboxing or process isolation. The demo `review.json` removes `bash`, `powershell`, `write`, and `edit`, but does not block external MCP tools or subagents. Configure tool removals matching your specific execution tools.
240
+
241
+ ## Implementation status (0.5.5)
242
+
243
+ The 0.5.5 core functional implementation is delivered in source across all planned lanes:
244
+
245
+ - Foundation codecs, scoped discovery, semantic events, and immutable snapshot reducer.
246
+ - Human CLI commands (`/capability` add, list, bindings, enable, enable-bound, disable, status, reset).
247
+ - Formal plain metadata delivery anchor projection with pre-compilation ordinal materialization.
248
+ - Web Session capabilities activity panel and guarded human activation picker (`GET /api/capability-state/available`, `POST /api/capability-state/enable`).
249
+ - Live Preset bindings (`capabilities`) in dedicated peer Capability bindings tab, with finite overrides, collapsed advanced view, and opt-in `modelCallable: true`.
250
+ - Restricted model-callable `forge_capability` agent tool (list, status, enable, disable, ID ≤ 128 chars).
251
+ - Web Capabilities surface (CRUD) with SDK-grouped tool picker and `sourceRevision` stale-save guards.
252
+ - Preset policy custom default tools editor (`tools.initial?: string[]`) with concrete names, zero-default support (`[]`), and legacy fallback on omission.
253
+ - Parent safeguards: raw source/revision coherence, external new bindings stale-save detection, and lifecycle/re-entry fences.
254
+ - Tool patch schema supports `add` and `remove` only; candidate `only`/allowlist is not implemented.
255
+ - Conservative provider-managed prompt cache warnings; compatible Codex additional-tool delivery can preserve prefixes for new names when retained history has no removals/redeclarations; tool removal/redeclaration falls back to the current full tool list (not guaranteed cache hits); no automatic legacy migration or old summary rewrites; no Pi split patch; no claims of forced prompt, warming, auto overflow, or remote acceptance.
256
+ - Local build and full Node/browser/package verification passed at the 2026-09-24 UI closeout (commit `89c6ba2`); this is a dated local result, not current CI evidence, remote-provider acceptance, or npm publication. Pi `>=0.87.0 <0.88.0` remains required; optional runtime/subagent integration and its producer work are independently tested and released.
257
+
258
+
259
+ Filesystem safety checks reject symlinks present when checked. They are not isolation against another local process racing directory replacement; revision checks likewise are not cross-process locking. Do not use resource mutation against an adversarial shared filesystem.
@@ -2,23 +2,41 @@
2
2
 
3
3
  [Documentation](../README.md) · [中文](../zh-CN/reference/commands.md)
4
4
 
5
- Arguments in brackets are optional. Commands that write project files require a trusted project.
5
+ Arguments in brackets are optional. Main pi-forge command arguments are strict: unknown flags and extra arguments are rejected. Commands that write project files require a trusted project.
6
6
 
7
- ## Prompt stacks
7
+ ## Forge commands
8
+
9
+ `/forge` is the canonical root. With no arguments it opens Forge command help; `/forge help` does the same.
10
+
11
+ | Command | Behavior |
12
+ |---|---|
13
+ | `/forge ui [stop\|restart]` | Open, stop, or explicitly restart the local web editor. |
14
+ | `/forge payload next [save=<path> [--overwrite]]` | Arm capture of the next provider-hook payload, display it, and optionally save it. Quote paths containing spaces, for example `save="path with spaces.json"`. |
15
+ | `/forge payload status` | Show whether a capture is pending and whether a latest capture exists. |
16
+ | `/forge payload cancel` | Cancel only the pending next-capture request. It does not delete or reset retained captures or context-diff history. |
17
+ | `/forge payload help` | Show payload syntax and capture boundaries. |
18
+ | `/forge subagent plan ...` | Optional execution-plan command supplied by the matching `@zihanw/pi-forge-subagents` package. Duplicate contributors fail closed. |
19
+
20
+ `/forge payload` and bare `/payload` both arm the next capture. `/intercept` remains a compatibility shortcut for the same arm-without-save operation. A save never overwrites an existing file unless `--overwrite` is present; `--overwrite` is valid only with `save=<path>`; an armed capture does not call a model. Capture is taken at `before_provider_request`, so later plugin shaping may change the final wire body. Saved payloads may contain prompt and conversation text even when credential-shaped fields are redacted.
21
+
22
+ The legacy `/subagent` command is a separate low-level smoke helper. It is not the actual `/forge subagent plan` execution-plan command.
23
+
24
+ ## Prompt presets
8
25
 
9
26
  | Command | Behavior |
10
27
  |---|---|
11
- | `/preset list` | List stacks and activation/validation state. |
12
- | `/preset status` | Show the selected stack and diagnostics summary. |
13
- | `/preset use <id>` | Validate and select a stack. |
14
- | `/preset use none` | Disable prompt stacks for this session branch. `off` is accepted as an alias. |
15
- | `/preset preview [id]` | Compile and display a stack without provider transport. Defaults to the selected stack. |
16
- | `/preset validate [id]` | Validate one stack or all stacks when omitted. |
28
+ | `/preset list` | List presets and activation/validation state. |
29
+ | `/preset status` | Show the selected preset and diagnostics summary. |
30
+ | `/preset use <id>` | Validate and select a preset. |
31
+ | `/preset use none` | Disable prompt presets for this session branch. `disable` is accepted as an alias. |
32
+ | `/preset preview [id]` | Compile and display a preset without provider transport. Defaults to the selected preset. |
33
+ | `/preset validate [id]` | Validate the selected preset when omitted, or one named preset when supplied. It does not validate every preset by default. |
17
34
  | `/preset diagnostics` | Show loader, runtime, policy, regex, and trusted-extension diagnostics. |
18
- | `/preset reload` | Reload stacks and trusted macro/slot registrations. |
19
- | `/preset ui [stop\|restart]` | Open, stop, or replace the local web editor. |
35
+ | `/preset reload` | Reload presets and trusted macro/slot registrations. |
36
+ | `/preset ui [stop\|restart]` | Compatibility lifecycle entry for the local web editor; prefer `/forge ui`. |
37
+ | `/preset help` | Show preset command help. |
20
38
 
21
- ## Storage migration and import
39
+ ## Storage migration
22
40
 
23
41
  | Command | Behavior |
24
42
  |---|---|
@@ -32,30 +50,40 @@ Use migration dry runs before overwriting or deleting anything.
32
50
  |---|---|
33
51
  | `/profile list` | List project profiles and resolution diagnostics. |
34
52
  | `/profile use <id>` | Preflight and apply a profile once. |
35
- | `/profile save <id> [--overwrite]` | Capture the current model, thinking level, and stack. |
53
+ | `/profile save <id> [--overwrite]` | Capture the current model, thinking level, and preset. |
36
54
  | `/profile status` | Compare current runtime with last-applied branch provenance. |
37
- | `/profile preview <id>` | Resolve model/auth/thinking/stack/tools without applying. |
38
- | `/profile validate [id]` | Validate one profile or all profiles when omitted. |
55
+ | `/profile preview <id>` | Resolve model/auth/thinking/preset/tools without applying. |
56
+ | `/profile validate [id]` | Validate all loaded profiles when omitted, or one named profile when supplied. |
39
57
  | `/profile reload` | Reload definitions without applying them. |
40
58
  | `/profile forget` | Remove last-applied provenance without changing runtime state. |
59
+ | `/profile help` | Show profile command help. |
41
60
 
42
- ## Experimental foreground delegation
61
+ ## Capabilities
43
62
 
44
- The commands below are provided by the optional `@zihanw/pi-forge-subagents` package.
63
+ `/capability` is the command for managing session capabilities.
45
64
 
46
65
  | Command | Behavior |
47
66
  |---|---|
48
- | `/forge-agent backends` | List registered experimental backends, capabilities, and effective defaults. |
49
- | `/forge-agent plan <profile> [--backend <id>] <task>` | Prepare, validate, display, and discard an exact plan without provider transport. |
50
- | `/forge-agent run <profile> [--backend <id>] <task>` | Review and approve an exact foreground read-only run. |
67
+ | `/capability add <text>` | Add a literal manual instruction. |
68
+ | `/capability list` | Explicitly reload and list the capability library. |
69
+ | `/capability bindings` | List bindings on the active preset, including human-only bindings (`modelCallable: false`). |
70
+ | `/capability enable <[scope:]id>` | Enable an unbound library capability. |
71
+ | `/capability enable-bound <id>` | Enable a binding from the active preset. |
72
+ | `/capability disable <activation-id>` | Disable one active capability. |
73
+ | `/capability status` | Show active capabilities and effective tools. |
74
+ | `/capability reset` | Disable all active capabilities and manual directives. |
75
+ | `/capability help` | Show usage and compatibility notes. |
76
+
77
+ Completions use the current session and last published workspace snapshot. They do not scan resources on every keystroke. Use `/capability list` for an explicit discovery refresh. Human-only bindings remain visible in `bindings`; `modelCallable: false` only prevents Agent control.
51
78
 
52
- Only explicitly scoped profiles are accepted: use `project:<id>` or `global:<id>` keys in `subagents.json`. A bare authorization key always means `project:<id>`, even in the global file; `.pi/forge/config.json.subagents` remains a read-only legacy fallback. The model-callable equivalents are `forge_subagent_profiles` (local discovery) and `forge_subagent` (execution). See the [delegation safety guide](../guides/delegation.md).
79
+ ## Optional foreground delegation
53
80
 
54
- ## Payload inspection
81
+ The following commands are supplied by the matching optional `@zihanw/pi-forge-subagents` package, not by main pi-forge:
55
82
 
56
83
  | Command | Behavior |
57
84
  |---|---|
58
- | `/intercept` | Display the next redacted provider payload. |
59
- | `/payload next [save=<path>]` | Display the next payload, optionally save it, and expose it to the web editor. |
85
+ | `/forge-agent backends` | List registered backends, capabilities, and effective defaults. |
86
+ | `/forge-agent plan <profile> [--backend <id>] <task>` | Prepare, display, and discard an exact plan without provider transport. |
87
+ | `/forge-agent run <profile> [--backend <id>] <task>` | Prepare a foreground run, always ask for human approval, then execute through the selected backend. A backend may write; this is not inherently read-only. |
60
88
 
61
- Saved payloads may include prompt and conversation text even though credential-shaped fields are redacted. Handle them as potentially sensitive.
89
+ Only explicitly scoped profiles are accepted by the optional package: use `project:<id>` or `global:<id>` keys in its `subagents.json`. The model-callable equivalents are `forge_subagent_profiles` (local discovery) and `forge_subagent` (execution). The model-callable `forge_subagent` tool is a separate path. Its unattended behavior is controlled by explicit trusted-project authorization; it is not a way to bypass the approval requirement of `/forge-agent run`. See the [delegation safety guide](../guides/delegation.md).
@@ -21,6 +21,8 @@ The port is preferred, not guaranteed. The editor binds only to `127.0.0.1` and
21
21
 
22
22
  ## Experimental subagents
23
23
 
24
+ The explicit non-boolean approval-flag handling described below remains an unreleased companion source fix; published `@zihanw/pi-forge-subagents` 0.5.3 does not contain it. It is optional-package work, not a Forge 0.5.5 main-package feature. Configuration parsing belongs to that optional package, not the Forge host.
25
+
24
26
  Subagent configuration is owned by the optional `@zihanw/pi-forge-subagents` package. Dedicated files are `.pi/forge/subagents.json` for a trusted project and `~/.pi/forge/subagents.json` for user defaults. Legacy `.pi/forge/config.json` / `~/.pi/forge/config.json` `subagents` sections are read-only fallback material and emit a warning.
25
27
 
26
28
  User defaults may set general settings:
@@ -50,11 +52,11 @@ Trusted project `subagents.json` may override defaults, authorize individual pro
50
52
  }
51
53
  ```
52
54
 
53
- Valid timeouts are 1,000–3,600,000 ms. Invalid fields warn and fall back to the preceding applicable default. General backend precedence is project then user then built-in; an interactive run and a project profile entry can further override it as described in [delegation](../guides/delegation.md#backends-and-precedence).
55
+ Valid timeouts are 1,000–3,600,000 ms. Invalid timeout fields warn and fall back to the preceding applicable default. General backend precedence is project then user then built-in; a matching profile entry and an interactive per-run override can further override it as described in [delegation](../guides/delegation.md#backends-and-precedence).
54
56
 
55
57
  `summaryInToolDescription` (default `false`) embeds a compact, bounded summary of enabled subagent profiles directly in the `forge_subagent` tool description so the parent model can pick a profile without a discovery call. Ready profiles appear first, and unavailable enabled profiles include their first resolution error. It may be set in user or trusted-project `subagents.json` and applies wherever it is enabled.
56
58
 
57
- Profile authorization keys should use canonical selectors: `project:<id>` or `global:<id>`. A bare key is a compatibility spelling for `project:<id>` regardless of which config file contains it; it never authorizes a global profile. Therefore a global profile must be written explicitly as `"global:reviewer": { "enabled": true }` in `~/.pi/forge/subagents.json`. Same-ID profiles never inherit enablement, backend, or timeout policy from each other. `allowAgentInvocationWithoutApproval` is project-only, requires trust, and fails closed when malformed. Deleting a profile does not modify `subagents.json`; remove any enabled entry for the deleted profile manually.
59
+ Profile authorization keys should use canonical selectors: `project:<id>` or `global:<id>`. A bare key is a compatibility spelling for `project:<id>` regardless of which config file contains it; it never authorizes a global profile. Therefore a global profile must be written explicitly as `"global:reviewer": { "enabled": true }` in `~/.pi/forge/subagents.json`. Same-ID profiles never inherit enablement, backend, or timeout policy from each other. `allowAgentInvocationWithoutApproval` may be supplied by global defaults or a trusted project file; the project value overrides the global value, and the execution trust gate still blocks delegation from an untrusted project. When that flag is absent at a layer it inherits; an explicitly non-boolean value sets that layer to `false` and emits a warning, while 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 any earlier valid layer remains effective. Deleting a profile does not modify `subagents.json`; remove any enabled entry for the deleted profile manually.
58
60
 
59
61
  Treat project configuration as an authorization boundary. In particular, do not commit unattended delegation unless every permitted parent agent may transmit compiled prompt and readable project content without another human approval.
60
62
 
@@ -10,7 +10,7 @@ This file tracks the currently implemented feature surface for agent profiles, t
10
10
  - Tarball verification rejects physical `src/` entries and requires the root and subagent compiled entry points.
11
11
  - The web editor's HTML page shell and static styles are maintained separately from its browser behavior modules.
12
12
  - Strict typed web-editor client modules bundled into one self-contained browser script at build time, with generated-client consistency verification.
13
- - Supported Node.js baseline is 22.19+. Published Pi SDK dependencies are host-provided wildcard peers; exact repository versions are reproducible development/test fixtures rather than runtime constraints.
13
+ - Supported Node.js baseline is 22.19+. The four Pi SDK packages are host-provided optional peers at `>=0.87.0 <0.88.0`; `typebox` is an optional wildcard peer. Exact repository versions are reproducible development/test fixtures rather than runtime constraints.
14
14
  - Project trust check before loading prompt stacks.
15
15
  - Footer status showing the active prompt stack.
16
16
 
@@ -55,7 +55,7 @@ This file tracks the currently implemented feature surface for agent profiles, t
55
55
  - `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` copies legacy stacks into the forge storage location.
56
56
  - `default.json` auto-activation unless `autoActivate` is `false`.
57
57
  - Branch-aware persisted active stack restore from session entries.
58
- - Persisted `/preset use none` / `off` opt-out.
58
+ - Persisted `/preset use none` / `disable` opt-out.
59
59
  - Invalid stacks with error diagnostics are skipped by automatic selection.
60
60
  - Raw stack fields are shape-checked before recovery normalization, including behavior-changing booleans/enums, defaults, context, variables, and item fields.
61
61
  - Stack validation for duplicate item IDs, duplicate stack IDs, unsupported slots, missing chat-history slots, and ignored items.
@@ -172,6 +172,15 @@ This file tracks the currently implemented feature surface for agent profiles, t
172
172
  - `/preset reload`
173
173
  - `/preset ui [stop|restart]`
174
174
  - `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]`
175
+ - `/capability add <text>`
176
+ - `/capability list`
177
+ - `/capability bindings`
178
+ - `/capability enable <[scope:]id>`
179
+ - `/capability enable-bound <id>`
180
+ - `/capability disable <activation-or-capability-id>`
181
+ - `/capability status`
182
+ - `/capability reset`
183
+ - `/capability help`
175
184
  - `/intercept`
176
185
  - `/payload next [save=<path>]`
177
186
 
@@ -199,7 +208,7 @@ This file tracks the currently implemented feature surface for agent profiles, t
199
208
  - Resource inventory and preview remain usable when a reclaimed editor host is refreshed from lifecycle contexts that do not expose command-only prompt APIs.
200
209
  - Stack list with active/error/warning indicators.
201
210
  - Collapsible prompt-stack sidebar.
202
- - Collapsible stack metadata panel and main-area tabs for Items, Regex, Policy, and Stack JSON/context/variables work.
211
+ - Preset properties from the resource header, with peer Stack, Regex, Policy, Bindings and Advanced editing tabs; the separate Preview/Draft diff/Run diff dock stays alongside the editor.
203
212
  - Light/dark theme toggle, button icons, and tooltips for common actions.
204
213
  - English/中文 interface switch (`webEditor.locale`: `"en"`, `"zh-CN"`, or `"auto"` following the browser language); contributed settings tabs remain provider-authored and are not translated.
205
214
  - Unsaved-change badge in the top bar.
@@ -229,7 +238,7 @@ This file tracks the currently implemented feature surface for agent profiles, t
229
238
  - Export the current edited stack JSON from the browser, with clipboard fallback when download is unavailable.
230
239
  - Fork the current stack into a new stack file, with optional activation.
231
240
  - Delete stack files, disabling prompt-stack replacement if the deleted stack was active.
232
- - Trust and path guardrails for save/import/fork/delete writes.
241
+ - Built-in Web writes cover Presets, Profiles, Capabilities, and trusted Forge configuration, with trust and path guardrails for save/import/fork/delete operations.
233
242
  - Top-level navigation between prompt stacks and project agent profiles; stack drafts, selection, and active state survive surface switches.
234
243
  - Profile list shows ID, name, model/thinking/stack targets, validation state, and `autoActivate` and last-applied badges.
235
244
  - Profile create, edit, validate, save, one-shot apply, and delete reuse the shared resolver, transactional application service, and guarded repository; save rejects a second auto-activation profile and on-disk conflicts.
@@ -237,3 +246,60 @@ This file tracks the currently implemented feature surface for agent profiles, t
237
246
  - A runtime/provenance card distinguishes current runtime, last-applied provenance, source-definition state, and per-field runtime drift after external model, thinking-level, or stack changes.
238
247
  - The main web editor no longer ships a delegation card; delegation configuration is owned by the optional `@zihanw/pi-forge-subagents` package through `.pi/forge/subagents.json`.
239
248
  - Smoke tests cover editor server token checks, bundled page/script markers, save, payload arm/capture/clear, create/fork, native JSON import, collision handling, delete, and stop behavior.
249
+
250
+ ## Capabilities and System Updates
251
+
252
+ - Upstream host requirement: Pi `>=0.87.0 <0.88.0` (repository dev SDK pinned to `0.87.0`, peer range `>=0.87.0 <0.88.0`; no dual 0.86 runtime support claim).
253
+ - File-backed capability definitions stored in `.pi/forge/capabilities/<id>.json` (project scope) and `~/.pi/forge/capabilities/<id>.json` (global scope) with schema `schemaVersion: 1`, `type: "pi-forge.capability"`.
254
+ - Literal text content (up to 100,000 characters) without macro, template, or script evaluation.
255
+ - Tool modification patches supporting `add` and `remove` arrays (tool IDs ≤ 128 characters, no whitespace/controls/wildcards, up to 256 tools per array). Capabilities support `add` and `remove` ONLY; candidate `only`/allowlist is not implemented.
256
+ - Fail-closed project-over-global shadowing for bare IDs; invalid local definitions fail closed with diagnostics and never fall back to global definitions.
257
+ - Scoped selectors (`project:<id>` and `global:<id>`) for targeting exact definitions.
258
+ - Local execution with zero inference cost: `/capability` commands and Web activity panel actions update internal session state and tool policy without invoking model inference or consuming API tokens.
259
+ - Unified `context_with_system` lifecycle: whole compiler, base prompt replacement, and capability projection pipeline moved to `context_with_system` without an internal two-phase split.
260
+ - Canonical session projection via `buildSessionProjection`: runtime, preview, and anchor locator helpers reflect turn-level `context_edit` omissions, replacements, and `sourceEntry` tracking without mutating raw session JSONL history on disk.
261
+ - Leading System prompt preservation: SDK incoming leading System message always remains first; Forge prefix plain metadata delivery anchors are inserted immediately after it.
262
+ - Settlement lifecycle and continuations: `agent_end` acts as an anchor commit boundary after tool batches or turns; compile cycle and busy fence reset only on `agent_settled` so `agent_before_settle` continuations preserve compiled Preset inputs.
263
+ - Immediate executable tool policy synchronization (`setActiveTools`) paired with next-model-request prompt text and section declaration delivery. Running tool batches are not killed mid-flight.
264
+ - Top-level Preset policy precedence: capability additions cannot enable tools denied by the active Preset (`tools.deny`); tool removals win globally across all active capabilities.
265
+ - Tool baseline recovery: restores session tools to a pristine baseline upon capability disable, adopting a conservative baseline when a session has no recorded baseline.
266
+ - Delivery via plain `custom` session entries carrying cursor-only metadata (`pi-forge-capability-delivery` with `{ schemaVersion: 1, throughEventId }`), replacing transcript `sendMessage` steering and `custom_message` carriers.
267
+ - Pre-compilation ordinal materialization into ephemeral in-memory markers at exact session positions matching canonical projection order.
268
+ - Request-only projection to native `SystemMessage.sections` (`forge-capability-<id>`) when supported by the provider, or fallback attributed user timeline updates (`[pi-forge capability update]`).
269
+ - Compaction input characterization: metadata delivery anchors and request-only rule text do not enter summarizer inputs while dialogue history is preserved.
270
+ - Breaking pre-release rename: no legacy aliases or readers are provided for the former instruction-mode schema, directories, or continuing capability state. Convert development configuration and start a new session; old JSONL and summaries are not rewritten.
271
+ - Provider-managed prompt cache warning: prompt caching and tool transport are downstream provider-managed; no guarantee of zero KV cache invalidation or exact cache hits.
272
+
273
+ ## Preset Capability Bindings
274
+
275
+ - Declarative `capabilities` binding list in the Preset schema.
276
+ - Qualified capability references (`project:<id>`, `global:<id>`), unique binding IDs (≤ 128 characters), and opt-in `modelCallable: boolean` (defaults to `false`).
277
+ - Finite overrides: either content replacement (`content`) or paragraph append (`appendContent` with two newlines), and independent whole-array replacement for `tools.add` and/or `tools.remove`.
278
+ - Source-effective preview via the shared server resolver (`resolveCapabilityBindings`).
279
+ - Stale-save guard using `sourceRevision` checking against raw file bytes, rejecting concurrent or external edits (409 Conflict) whenever bindings are present or modified.
280
+ - Same-Preset reload preserves immutable active snapshots; switching Presets retires old bound activations while retaining manual/unbound rules.
281
+ - Revocation behavior: disabling `modelCallable` does not retroactively erase active snapshots; human CLI or Web deactivation is the recovery path.
282
+
283
+ ## Agent Capability Controls
284
+
285
+ - Model-callable tool `forge_capability` registered when an active Preset includes bound capabilities.
286
+ - Fixed parameter schema: `{ action: "list" | "status" | "enable" | "disable", id?: string }` (ID ≤ 128 characters).
287
+ - Re-verifies project trust, active Preset existence, binding existence, `modelCallable: true`, and current tool policy on every call.
288
+ - Strict actor ownership: agent can only activate authorized bindings; agent `disable` can only stop its own agent-owned activations; agent cannot stop human rules, reset capabilities, add arbitrary prompt text, or remove `forge_capability`.
289
+ - Repeated use is idempotent and does not take over ownership from user to agent.
290
+ - Fences against disposed runtimes, restoring sessions, and cross-session re-entry.
291
+
292
+ ## Web Editor Capabilities and Session Activity
293
+
294
+ - Top-level **Capabilities** surface for project and global capability CRUD with validation diagnostics.
295
+ - Capability writes and deletions require `sourceRevision` checking against raw file bytes; 409 Conflict on stale views preserves user drafts.
296
+ - Capability saves never activate definitions into the active session.
297
+ - Dedicated peer **Capability bindings** tab in the Preset editor with binding configuration, `modelCallable` toggle, finite overrides, and live source vs effective preview.
298
+ - Global **Session capabilities** summary opens the non-modal **Current session** workspace, pairing controls with the active saved Preset/session projection and showing active capabilities, actor attribution (`user`/`agent`), collapsible frozen snapshots, tool deltas, effective tools, delivery status (`none`/`pending`/`prepared`), and presentation mode.
299
+ - Human activation picker with available capabilities (`GET /api/capability-state/available`) categorized into Library capabilities (unbound) and Current preset (bound).
300
+ - Explicit pre-activation preview displaying label, ID, badge, fingerprint, tool diff, problem banner, and full literal content.
301
+ - Bodyguard activation (`POST /api/capability-state/enable`) requiring session guard (`sessionId`, `leafId`, `revision`) and source fingerprint validation, rejecting stale or modified sources (409 Conflict) without automatic retry or inference.
302
+ - Read-only resource discovery and Preview never mutate tool policies, commit session events, or mark pending capabilities as prepared.
303
+ - Quiet state polling (every 3 seconds while visible, and on focus) with zero inference; catalog discovery occurs on workspace entry, explicit refresh and mutation follow-up, not each status poll.
304
+
305
+ The [Read-first Worker example](capabilities.md#read-first-worker) demonstrates default reading tools plus a model-authorized `bash`/`edit` capability. It is a tool-selection pattern, not a sandbox.