@zihanw/pi-forge 0.3.2 → 0.4.0-beta.1

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 (244) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/PUBLIC_API.md +28 -0
  3. package/README.md +137 -11
  4. package/README.zh-CN.md +137 -11
  5. package/SUBAGENT_ADAPTER_CONTRACT.md +199 -0
  6. package/dist/agent-profile.d.ts +71 -0
  7. package/dist/agent-profile.d.ts.map +1 -0
  8. package/dist/agent-profile.js +303 -0
  9. package/dist/agent-profile.js.map +1 -0
  10. package/dist/forge-config.d.ts +8 -0
  11. package/dist/forge-config.d.ts.map +1 -0
  12. package/dist/forge-config.js +40 -0
  13. package/dist/forge-config.js.map +1 -0
  14. package/dist/forge-extensions.d.ts.map +1 -1
  15. package/dist/forge-extensions.js +19 -3
  16. package/dist/forge-extensions.js.map +1 -1
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +75 -361
  20. package/dist/index.js.map +1 -1
  21. package/dist/lifecycle.d.ts +11 -3
  22. package/dist/lifecycle.d.ts.map +1 -1
  23. package/dist/lifecycle.js +90 -4
  24. package/dist/lifecycle.js.map +1 -1
  25. package/dist/loader.d.ts.map +1 -1
  26. package/dist/loader.js +116 -5
  27. package/dist/loader.js.map +1 -1
  28. package/dist/payload-capture.d.ts.map +1 -1
  29. package/dist/payload-capture.js +27 -0
  30. package/dist/payload-capture.js.map +1 -1
  31. package/dist/payload-command.d.ts +3 -3
  32. package/dist/payload-command.d.ts.map +1 -1
  33. package/dist/payload-command.js.map +1 -1
  34. package/dist/preview.d.ts +2 -2
  35. package/dist/preview.d.ts.map +1 -1
  36. package/dist/preview.js +2 -3
  37. package/dist/preview.js.map +1 -1
  38. package/dist/profile-command.d.ts +12 -0
  39. package/dist/profile-command.d.ts.map +1 -0
  40. package/dist/profile-command.js +291 -0
  41. package/dist/profile-command.js.map +1 -0
  42. package/dist/profile-service.d.ts +103 -0
  43. package/dist/profile-service.d.ts.map +1 -0
  44. package/dist/profile-service.js +215 -0
  45. package/dist/profile-service.js.map +1 -0
  46. package/dist/runtime/profile-runtime.d.ts +13 -0
  47. package/dist/runtime/profile-runtime.d.ts.map +1 -0
  48. package/dist/runtime/profile-runtime.js +47 -0
  49. package/dist/runtime/profile-runtime.js.map +1 -0
  50. package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
  51. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
  52. package/dist/runtime/prompt-stack-runtime.js +104 -0
  53. package/dist/runtime/prompt-stack-runtime.js.map +1 -0
  54. package/dist/runtime/subagent-runtime.d.ts +30 -0
  55. package/dist/runtime/subagent-runtime.d.ts.map +1 -0
  56. package/dist/runtime/subagent-runtime.js +114 -0
  57. package/dist/runtime/subagent-runtime.js.map +1 -0
  58. package/dist/runtime/tool-policy-runtime.d.ts +15 -0
  59. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
  60. package/dist/runtime/tool-policy-runtime.js +170 -0
  61. package/dist/runtime/tool-policy-runtime.js.map +1 -0
  62. package/dist/runtime/web-editor-runtime.d.ts +9 -0
  63. package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
  64. package/dist/runtime/web-editor-runtime.js +131 -0
  65. package/dist/runtime/web-editor-runtime.js.map +1 -0
  66. package/dist/runtime-state.d.ts +4 -0
  67. package/dist/runtime-state.d.ts.map +1 -1
  68. package/dist/runtime-state.js +2 -0
  69. package/dist/runtime-state.js.map +1 -1
  70. package/dist/storage.d.ts +3 -0
  71. package/dist/storage.d.ts.map +1 -1
  72. package/dist/storage.js +9 -0
  73. package/dist/storage.js.map +1 -1
  74. package/dist/subagent/backend-registry.d.ts +75 -0
  75. package/dist/subagent/backend-registry.d.ts.map +1 -0
  76. package/dist/subagent/backend-registry.js +463 -0
  77. package/dist/subagent/backend-registry.js.map +1 -0
  78. package/dist/subagent/canonical.d.ts +10 -0
  79. package/dist/subagent/canonical.d.ts.map +1 -0
  80. package/dist/subagent/canonical.js +52 -0
  81. package/dist/subagent/canonical.js.map +1 -0
  82. package/dist/subagent/context.d.ts +8 -0
  83. package/dist/subagent/context.d.ts.map +1 -0
  84. package/dist/subagent/context.js +125 -0
  85. package/dist/subagent/context.js.map +1 -0
  86. package/dist/subagent/contract.d.ts +11 -0
  87. package/dist/subagent/contract.d.ts.map +1 -0
  88. package/dist/subagent/contract.js +11 -0
  89. package/dist/subagent/contract.js.map +1 -0
  90. package/dist/subagent/diagnostics.d.ts +3 -0
  91. package/dist/subagent/diagnostics.d.ts.map +1 -0
  92. package/dist/subagent/diagnostics.js +5 -0
  93. package/dist/subagent/diagnostics.js.map +1 -0
  94. package/dist/subagent/index.d.ts +13 -0
  95. package/dist/subagent/index.d.ts.map +1 -0
  96. package/dist/subagent/index.js +13 -0
  97. package/dist/subagent/index.js.map +1 -0
  98. package/dist/subagent/pi-model-runtime.d.ts +8 -0
  99. package/dist/subagent/pi-model-runtime.d.ts.map +1 -0
  100. package/dist/subagent/pi-model-runtime.js +22 -0
  101. package/dist/subagent/pi-model-runtime.js.map +1 -0
  102. package/dist/subagent/pi-sdk-backend.d.ts +23 -0
  103. package/dist/subagent/pi-sdk-backend.d.ts.map +1 -0
  104. package/dist/subagent/pi-sdk-backend.js +383 -0
  105. package/dist/subagent/pi-sdk-backend.js.map +1 -0
  106. package/dist/subagent/pi-subprocess-backend.d.ts +72 -0
  107. package/dist/subagent/pi-subprocess-backend.d.ts.map +1 -0
  108. package/dist/subagent/pi-subprocess-backend.js +756 -0
  109. package/dist/subagent/pi-subprocess-backend.js.map +1 -0
  110. package/dist/subagent/plan.d.ts +14 -0
  111. package/dist/subagent/plan.d.ts.map +1 -0
  112. package/dist/subagent/plan.js +160 -0
  113. package/dist/subagent/plan.js.map +1 -0
  114. package/dist/subagent/preflight.d.ts +4 -0
  115. package/dist/subagent/preflight.d.ts.map +1 -0
  116. package/dist/subagent/preflight.js +108 -0
  117. package/dist/subagent/preflight.js.map +1 -0
  118. package/dist/subagent/request.d.ts +4 -0
  119. package/dist/subagent/request.d.ts.map +1 -0
  120. package/dist/subagent/request.js +122 -0
  121. package/dist/subagent/request.js.map +1 -0
  122. package/dist/subagent/response.d.ts +8 -0
  123. package/dist/subagent/response.d.ts.map +1 -0
  124. package/dist/subagent/response.js +155 -0
  125. package/dist/subagent/response.js.map +1 -0
  126. package/dist/subagent/subprocess-bridge.d.ts +21 -0
  127. package/dist/subagent/subprocess-bridge.d.ts.map +1 -0
  128. package/dist/subagent/subprocess-bridge.js +87 -0
  129. package/dist/subagent/subprocess-bridge.js.map +1 -0
  130. package/dist/subagent/subprocess-report.d.ts +4 -0
  131. package/dist/subagent/subprocess-report.d.ts.map +1 -0
  132. package/dist/subagent/subprocess-report.js +55 -0
  133. package/dist/subagent/subprocess-report.js.map +1 -0
  134. package/dist/subagent/tools.d.ts +4 -0
  135. package/dist/subagent/tools.d.ts.map +1 -0
  136. package/dist/subagent/tools.js +42 -0
  137. package/dist/subagent/tools.js.map +1 -0
  138. package/dist/subagent/types.d.ts +384 -0
  139. package/dist/subagent/types.d.ts.map +1 -0
  140. package/dist/subagent/types.js +3 -0
  141. package/dist/subagent/types.js.map +1 -0
  142. package/dist/subagent/validation.d.ts +35 -0
  143. package/dist/subagent/validation.d.ts.map +1 -0
  144. package/dist/subagent/validation.js +500 -0
  145. package/dist/subagent/validation.js.map +1 -0
  146. package/dist/subagent-command.d.ts +4 -0
  147. package/dist/subagent-command.d.ts.map +1 -0
  148. package/dist/subagent-command.js +153 -0
  149. package/dist/subagent-command.js.map +1 -0
  150. package/dist/subagent-contract.d.ts +8 -0
  151. package/dist/subagent-contract.d.ts.map +1 -0
  152. package/dist/subagent-contract.js +8 -0
  153. package/dist/subagent-contract.js.map +1 -0
  154. package/dist/subagent-host.d.ts +44 -0
  155. package/dist/subagent-host.d.ts.map +1 -0
  156. package/dist/subagent-host.js +291 -0
  157. package/dist/subagent-host.js.map +1 -0
  158. package/dist/subagent-profile-tool.d.ts +26 -0
  159. package/dist/subagent-profile-tool.d.ts.map +1 -0
  160. package/dist/subagent-profile-tool.js +93 -0
  161. package/dist/subagent-profile-tool.js.map +1 -0
  162. package/dist/subagent-tool.d.ts +50 -0
  163. package/dist/subagent-tool.d.ts.map +1 -0
  164. package/dist/subagent-tool.js +385 -0
  165. package/dist/subagent-tool.js.map +1 -0
  166. package/dist/web-editor/client/api.d.ts +9 -0
  167. package/dist/web-editor/client/api.d.ts.map +1 -0
  168. package/dist/web-editor/client/api.js +26 -0
  169. package/dist/web-editor/client/api.js.map +1 -0
  170. package/dist/web-editor/client/dom.d.ts +13 -0
  171. package/dist/web-editor/client/dom.d.ts.map +1 -0
  172. package/dist/web-editor/client/dom.js +30 -0
  173. package/dist/web-editor/client/dom.js.map +1 -0
  174. package/dist/web-editor/client/inspector.d.ts +22 -0
  175. package/dist/web-editor/client/inspector.d.ts.map +1 -0
  176. package/dist/web-editor/client/inspector.js +226 -0
  177. package/dist/web-editor/client/inspector.js.map +1 -0
  178. package/dist/web-editor/client/main.d.ts +2 -0
  179. package/dist/web-editor/client/main.d.ts.map +1 -0
  180. package/dist/web-editor/client/main.js +1468 -0
  181. package/dist/web-editor/client/main.js.map +1 -0
  182. package/dist/web-editor/client/policy-editor.d.ts +16 -0
  183. package/dist/web-editor/client/policy-editor.d.ts.map +1 -0
  184. package/dist/web-editor/client/policy-editor.js +330 -0
  185. package/dist/web-editor/client/policy-editor.js.map +1 -0
  186. package/dist/web-editor/client/regex-editor.d.ts +19 -0
  187. package/dist/web-editor/client/regex-editor.d.ts.map +1 -0
  188. package/dist/web-editor/client/regex-editor.js +281 -0
  189. package/dist/web-editor/client/regex-editor.js.map +1 -0
  190. package/dist/web-editor/client/types.d.ts +60 -0
  191. package/dist/web-editor/client/types.d.ts.map +1 -0
  192. package/dist/web-editor/client/types.js +2 -0
  193. package/dist/web-editor/client/types.js.map +1 -0
  194. package/dist/web-editor/client-script.d.ts +2 -0
  195. package/dist/web-editor/client-script.d.ts.map +1 -0
  196. package/dist/web-editor/client-script.generated.d.ts +2 -0
  197. package/dist/web-editor/client-script.generated.d.ts.map +1 -0
  198. package/dist/web-editor/client-script.generated.js +3 -0
  199. package/dist/web-editor/client-script.generated.js.map +1 -0
  200. package/dist/web-editor/client-script.js +2 -0
  201. package/dist/web-editor/client-script.js.map +1 -0
  202. package/dist/web-editor/page.d.ts.map +1 -1
  203. package/dist/web-editor/page.js +6 -3249
  204. package/dist/web-editor/page.js.map +1 -1
  205. package/dist/web-editor/styles.d.ts +2 -0
  206. package/dist/web-editor/styles.d.ts.map +1 -0
  207. package/dist/web-editor/styles.js +996 -0
  208. package/dist/web-editor/styles.js.map +1 -0
  209. package/dist/web-host.d.ts +3 -3
  210. package/dist/web-host.d.ts.map +1 -1
  211. package/dist/web-host.js +6 -0
  212. package/dist/web-host.js.map +1 -1
  213. package/package.json +42 -14
  214. package/src/compiler.ts +0 -578
  215. package/src/extension-registry.ts +0 -33
  216. package/src/forge-extensions.ts +0 -223
  217. package/src/index.ts +0 -445
  218. package/src/lifecycle.ts +0 -171
  219. package/src/loader.ts +0 -394
  220. package/src/macro-engine.ts +0 -358
  221. package/src/payload-capture.ts +0 -85
  222. package/src/payload-command.ts +0 -138
  223. package/src/policy.ts +0 -42
  224. package/src/preset-command.ts +0 -280
  225. package/src/preview.ts +0 -226
  226. package/src/regex.ts +0 -500
  227. package/src/render-helpers.ts +0 -169
  228. package/src/runtime-state.ts +0 -40
  229. package/src/sillytavern-importer/items.ts +0 -98
  230. package/src/sillytavern-importer/macros.ts +0 -159
  231. package/src/sillytavern-importer/prompt-order.ts +0 -54
  232. package/src/sillytavern-importer/regex.ts +0 -270
  233. package/src/sillytavern-importer/report.ts +0 -202
  234. package/src/sillytavern-importer/types.ts +0 -120
  235. package/src/sillytavern-importer.ts +0 -152
  236. package/src/slot-renderers.ts +0 -414
  237. package/src/stack-migration.ts +0 -159
  238. package/src/storage.ts +0 -45
  239. package/src/types.ts +0 -209
  240. package/src/web-editor/index.ts +0 -2
  241. package/src/web-editor/page.ts +0 -3330
  242. package/src/web-editor/server.ts +0 -294
  243. package/src/web-editor/types.ts +0 -98
  244. package/src/web-host.ts +0 -232
package/CHANGELOG.md ADDED
@@ -0,0 +1,160 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+ In 0.x development, breaking changes may occur in minor releases and will be explicitly noted.
8
+
9
+ ## [Unreleased]
10
+
11
+ ## [0.4.0-beta.1] - 2026-07-18
12
+
13
+ ### Added
14
+
15
+ - **Main-agent profile discovery.** Added the no-egress `forge_subagent_profiles` tool. It returns loaded profile IDs, names, descriptions, declared model/thinking/stack metadata, ready/unavailable resolution diagnostics, and whether parent policy currently exposes `forge_subagent`, without preparing a child prompt or contacting a provider.
16
+ - **Approval-gated foreground subagents.** Added the model-callable `forge_subagent` tool and moved `/forge-agent run` onto the same prepare-review-execute path. Every run prepares an immutable exact plan before provider transport. `/forge-agent run` and the default tool path show a compact task/profile/provider/model/thinking/tool/boundary/fingerprint summary, permit on-demand inspection of the full provider-bound prompt, and require explicit interactive human approval.
17
+ - **Explicit unattended tool authorization.** Trusted projects may set `subagents.allowAgentInvocationWithoutApproval: true` in `.pi/forge/config.json` to let the parent agent invoke only the model-callable `forge_subagent` tool without per-run UI. Profile discovery exposes the active mode, result receipts record `trusted-project-config`, and missing, malformed, or untrusted-project settings fail closed.
18
+ - **Read-only Pi subprocess backend.** Added the experimental `pi-subprocess-readonly` backend as the extension default. It runs one sequential foreground Pi subprocess with a clean conversation and only stack-filtered `read`, `grep`, `find`, and `ls` tools; write, edit, shell, skills, templates, context files, and third-party extensions are disabled.
19
+ - **Inspectable subagent reports.** Foreground progress and bounded output now return through a normal Pi tool call result. Expandable result details retain the approval receipt, plan summary, normalized response, diagnostics, usage, bounded transcript tail, and tool calls/results while the full compiled prompt remains transient unless the user explicitly opens it before approval.
20
+ - **Explicit shared-user execution boundary.** Access receipts can now distinguish isolated execution from a shared-user subprocess. The latter cannot claim mount, symlink, process, or network isolation and documents that read-only model tools do not reduce the child process's operating-system permissions.
21
+ - **Public API classification.** Added a dedicated experimental `@zihanw/pi-forge/subagent` entry point and documented stable, experimental, and internal compatibility surfaces while preserving existing package-root exports.
22
+ - **Optional subagent backend registry.** Added empty-by-default validated backend registration, accepted-preflight binding, exact/backend-assisted preparation dispatch, execution and cancellation arbitration, host-abort timeout handling, failure normalization, and authorization-scoped trace routing. Deterministic fake-backend conformance tests cover the full adapter status and enforcement matrix.
23
+ - **Experimental isolated Pi SDK backend.** Added a pi-forge-owned, text-only `pi-sdk-isolated` adapter backed by an in-memory Pi `AgentSession`. It accepts only access `none`, advertises no agent tools or stored artifacts/traces, blocks provider transport until exact host preparation and immutable-plan validation complete, and cleans up temporary runtime state after execution or discard.
24
+ - **Human subagent test commands.** Added `/forge-agent backends`, `/forge-agent plan <profile> <task>`, and `/forge-agent run <profile> <task>`. Dry planning exercises the complete request pipeline without provider transport; TUI execution requires explicit provider-egress confirmation and returns a compact normalized response.
25
+
26
+ - **Native one-shot agent profiles.** Project profiles under `.pi/forge/agent-profiles` store an exact model, thinking level, and prompt-stack reference. `/profile use` preflights and applies once, `/profile save` captures the current runtime, and list/status/preview/validate/reload/forget commands cover diagnostics, drift, direct file editing, and branch-scoped provenance without automatic reapplication.
27
+ - **Profile resolution API.** Exported strict profile types, loading, validation, exact model/auth/thinking/stack resolution, fingerprints, provenance guards, and diagnostics for future subagent adapters without adding a runner dependency. Prompt stacks remain the single source of truth for tool policy and model-visible skill filtering.
28
+ - **Fresh-session profile auto-activation.** One profile may opt into `autoActivate: true` to apply its model, thinking level, and prompt stack once for each fresh session. Profile selection takes precedence over standalone stack autoload, restored branch state remains authoritative, and invalid or ambiguous startup profiles fail closed without producing a hybrid configuration.
29
+ - **Browser-level editor smoke coverage.** CI now launches the real localhost editor in headless Chrome and verifies load, metadata editing, validation, policy guidance, save, and browser-console behavior.
30
+ - **Runner-neutral subagent adapter contract.** Exported pure request, host-resolution, backend-preflight, backend-assisted preparation, execution-plan, enforcement-receipt, and discriminated response APIs. The contract includes custom macro/slot dependency receipts, effect-aware tool negotiation, protected task/media assembly, deterministic UTF-8 context budgeting, canonical `sha256:v1` fingerprints, and access/limit/status/artifact/trace validators without registering a backend or adding parent run tools.
31
+ - **Internal Pi SDK adapter spike.** Added an opt-in dry-run/execute harness that validates real profiles, exact lifecycle prompt preparation, in-memory sessions, no-access execution, timeout abort, media transport, and trusted custom registrations against Pi 0.80.6.
32
+
33
+ ### Fixed
34
+
35
+ - **Terminal subprocess cancellation.** Cancelled and timed-out registry responses now wait for backend execution to drain. The subprocess backend awaits child closure with bounded TERM-to-KILL escalation during cancellation and disposal, terminalizes pre-spawn failures, and removes temporary run data before the foreground result settles.
36
+ - **Bounded retained subagent transcripts.** Retained transcript strings are capped, base64-like text is redacted in addition to canonical image blocks, stderr is bounded, and report messages keep a 512 KiB rolling tail with explicit omission metadata. This prevents pathological textual output from recreating the TUI/session lag caused by the original inline-image transport.
37
+ - **Binary-safe subagent image reports.** The child no longer sends Pi's complete JSON lifecycle stream to the parent, where repeated inline image blocks could exceed the 8 MiB transport limit and make the TUI retain megabytes of base64. A dedicated sanitized report channel preserves images inside the child for vision-provider requests, emits only image metadata to the parent, and defensively sanitizes the retained tool details again.
38
+ - **Pi 0.80.10 subagent authentication.** Subagent preparation now reuses the parent `ModelRuntime` when creating its temporary `AgentSession`, preserving the parent's OAuth/API-key state instead of passing session options that Pi 0.80.10 ignores. An offline regression test covers the extension's real model-registry-only path.
39
+ - **Fail-closed subagent egress consent.** `/forge-agent run` and the default `forge_subagent` path refuse non-UI execution instead of treating the absence of an interactive confirmation surface as approval. Only the explicit trusted-project unattended setting bypasses the tool's per-run UI. Exact preparation remains behind a closed provider gate, and dry planning remains available without provider transport.
40
+ - **Cancellation before backend dispatch.** An external abort that wins before backend execution now discards the prepared backend state without calling `execute()`. Concrete Pi SDK cancellation and host-timeout tests verify `AgentSession` abort and temporary-runtime cleanup.
41
+ - **Web editor lifecycle refresh.** Reused editor servers now bind ordinary lifecycle contexts separately from snapshotted system-prompt options, so resource inventory and preview remain available after startup reload, tree navigation, compaction, and extension reinitialization.
42
+ - **Trusted extension disposal and reload.** Runtime shutdown unregisters owned custom macros and slots before replacement. Every ESM load receives a process-unique cache token, while CommonJS entry caches are cleared, so `.ts`, `.mjs`, CommonJS `.js`, and `.cjs` extension edits reload without duplicate registrations or stale entry code.
43
+ - **Strict prompt-stack input validation.** Behavior-changing booleans, enums, defaults, context fields, variables, and item shapes are diagnosed before recovery normalization. Malformed values can still be displayed for repair but can no longer become an automatically usable stack.
44
+ - **Immutable stack identity on save.** Existing stack IDs are read-only in the web editor, and the save API rejects body/URL ID mismatches without writing files or changing active selection. Fork remains the supported way to create a new ID.
45
+ - **Token-accounting payload visibility.** Provider payload redaction preserves known token limits, usage counters, budgets, and tokenizer metadata while continuing to hide generic and credential-shaped token fields.
46
+ - **Tool policy restoration and enforcement across Pi reload.** pi-forge now restores the pre-policy active tool set during extension shutdown, waits for other extensions to finish their startup tool configuration before recapturing it, and reapplies restrictive policy before input and turns. A tool-call guard blocks disallowed execution even if another extension later calls `setActiveTools()`. This prevents both missing built-ins after `/preset use none` and late-added extension tools bypassing an active stack policy.
47
+ - **Skill-policy semantics.** Validation, documentation, and editor guidance now state that skill policy filters model-visible pi-forge skill listings; it does not disable explicit skill invocation and is not a security boundary.
48
+
49
+ ### Changed
50
+
51
+ - The npm tarball no longer includes physical `src/` files and uses compiled runtime entries. Legacy `@zihanw/pi-forge/src/*` imports continue to resolve to compiled modules, while development documentation directs source modifications through a repository clone and explicit local TypeScript extension entry.
52
+ - The extension entry point is now a small composition root; prompt-stack state, one-shot profile activation, tool-policy/preview behavior, and shared web-editor lifecycle live in focused runtime modules.
53
+ - The web editor client is authored as strict TypeScript modules for API transport, DOM access, policy editing, regex editing, preview/payload inspection, and orchestration. A build-only esbuild step produces the self-contained script used by the localhost editor, and verification rejects stale generated output.
54
+ - The subagent contract implementation is split into focused type, canonicalization, request, preflight, tool, context, plan, response, and diagnostic modules. Existing package-root and `src/subagent-contract.ts` exports remain compatibility barrels with an exact import-surface test.
55
+ - Backend-assisted preparation now makes the adapter, rather than the caller, provide the complete runtime compiler inputs. The registry fingerprints and validates that runtime, invokes the host compiler exactly once, binds the resulting prompt/messages/tools to execution, routes discard through the owning backend, and rejects adapters or callers that bypass, alter, or refingerprint a substitute host result.
56
+ - Profile commands now consume shared typed repository, application, preview, provenance, and drift-status services, establishing one behavioral core for profile UI and future subagent preparation.
57
+ - Package metadata now declares Node.js 22.19+ and pins the Pi peer/runtime/development packages to exactly 0.80.10. Pi changed session runtime wiring within 0.80.x, so this beta no longer claims compatibility with 0.80.6–0.80.9 or unverified later 0.80.x releases.
58
+ - The roadmap now records the approval-gated foreground subprocess path and moves forward to sandboxing, staged writes, profile UI, and release hardening without adding background orchestration.
59
+
60
+ ## [0.3.2] - 2026-07-07
61
+
62
+ ### Added
63
+
64
+ - **Global forge extensions.** pi-forge now loads trusted macro/slot registration modules from `~/.pi/forge/extensions` before project-local `.pi/forge/extensions`, so users can keep personal custom macros and slots available across projects without importing `@zihanw/pi-forge`.
65
+
66
+ ### Changed
67
+
68
+ - `/preset list` now shows both global and project forge extension directories.
69
+ - Documentation and examples now describe global and project-local forge extension placement.
70
+ - No breaking changes.
71
+
72
+ ## [0.3.1] - 2026-07-07
73
+
74
+ ### Added
75
+
76
+ - **Parser-backed macro expansion.** Macros now support nested `{{...}}` expressions and split `::` arguments only at the current macro depth.
77
+ - **Macro filters and lazy conditionals.** Added `{{trim}}`, `{{upper}}`, `{{lower}}`, `{{json}}`, `{{xml}}`, plus lazy `{{ifvar}}`, `{{ifeq}}`, `{{iftools}}`, and `{{ifslot}}` conditionals. Skipped conditional branches are not expanded, so they cannot mutate variables.
78
+ - **Trusted custom macro and slot APIs.** Added `registerMacro`, `registerSlot`, `getRegisteredMacros`, `getRegisteredSlots`, shared render helpers, and process-global registries so trusted Pi extensions can add custom macros and slots without embedding executable code in stack JSON.
79
+ - **Project-local forge extensions.** Added trusted `.pi/forge/extensions` modules for project-local macro/slot registration. pi-forge loads them before stack validation, reloads them on `/preset reload`, and lists loaded files or load warnings in `/preset diagnostics`.
80
+ - **Example custom extension.** Added `examples/custom-system-status-extension`, which registers a `{{cpuLoad}}` macro and `machine-status` slot from a project-local forge extension module.
81
+ - **Slot registry and date-time option.** Built-in slots now use the public slot registry, and `date` / `date-cwd` slots support `includeTime: true`.
82
+ - **Web editor: new stack workflow.** The browser can create a stack even when no stack files exist yet. New stacks start from the default Pi prompt mirror layout so users can edit a complete working stack instead of a blank skeleton.
83
+ - **Web editor: policy resource picker.** The Policy tab now lists registered tools and loaded skills, marks active tools and hidden skills, hides exact selected names from the available list, supports removable selected-pattern chips, and includes a filter/autocomplete input for adding exact names while keeping wildcard/manual textarea editing.
84
+ - **Web editor shortcuts.** Added browser shortcuts for new stack, save, validate, preview, and closing dialogs/inspectors.
85
+ - **Web editor item actions.** Added direct Add block and Add slot actions.
86
+ - **Read-only web resource inventory API.** Added editor host support for listing known tools and skills for UI policy editing.
87
+
88
+ ### Fixed
89
+
90
+ - **Package install exports.** Installs now load compiled `dist` JavaScript instead of raw `.ts` files under `node_modules`, so `import { registerMacro, registerSlot } from "@zihanw/pi-forge"` works for reusable trusted extension packages without relying on Node TypeScript stripping. Git installs include the compiled output and do not require TypeScript during Pi's `npm install --omit=dev` step.
91
+ - **Preview policy simulation.** Web preview now compiles with the edited stack's tool policy applied to selected tools, snippets, and tool guidelines. This prevents preview from showing unrelated tool guidelines from the current Pi tool state.
92
+ - **Empty-project web editor UX.** Empty stack directories now show a create/import path instead of leaving the editor in a dead-end state.
93
+
94
+ ### Changed
95
+
96
+ - Documentation and feature inventory now describe the 0.3.1 web editor workflow.
97
+ - No breaking changes.
98
+
99
+ ## [0.3.0] - 2026-06-30
100
+
101
+ ### Breaking Changes
102
+
103
+ - **Tool/skill policy no longer allows mixed `allow` and `deny` lists.** Each resource policy (`tools`, `skills`) must use either `allow` **or** `deny`, not both. Stacks with non-empty mixed lists now produce validation errors. Previously, concrete `allow` patterns silently took priority over `deny`. Update your stack JSON to use one list per resource.
104
+ - Before: `{ "tools": { "allow": ["read", "bash"], "deny": ["*"] } }`
105
+ - After: `{ "tools": { "allow": ["read", "bash"] } }` or `{ "tools": { "deny": ["write"] } }`
106
+ - `PromptResourcePolicy` type changed from `{ allow?: string[]; deny?: string[] }` to a discriminated union: `{ allow?: string[]; deny?: never } | { allow?: never; deny?: string[] }`.
107
+
108
+ ### Added
109
+
110
+ - **Regex transforms.** Deterministic JavaScript `RegExp` find/replace on prompt text, ordered as stack-level `regex.rules`.
111
+ - `stage: "history"` — transforms messages inserted by the `chat-history` slot, with role filters, depth filters, `maxMessages`, and `maxChars`.
112
+ - `stage: "compiled"` — transforms final system prompt and/or message text before provider serialization, with `targets`, role filters, depth filters, `maxMessages`, and `maxChars`.
113
+ - `trimStrings` supports deterministic SillyTavern-style Trim Out behavior for expanded replacement matches/captures.
114
+ - `effect: "finalize"` — destructively rewrites completed assistant messages at `message_end`. Original model output is not preserved.
115
+ - Supported flags: `g`, `i`, `m`, `s`, `u`. Invalid patterns, duplicate IDs, and unsupported flags are rejected during validation.
116
+ - Runtime diagnostics report match counts and changed text segments.
117
+ - **Tool and skill policy.** Stack-level `tools.allow`/`tools.deny` and `skills.allow`/`skills.deny` with exact names and `*` wildcards. Tool policy is enforced through `pi.setActiveTools()` and restored when the stack is disabled or switched. Skill policy filters rendered `skills` slots and respects `disableModelInvocation`.
118
+ - **Web editor: Policy tab.** Structured editor for tool and skill policies with mode selector (Unrestricted / Allow / Deny), pattern textarea, duplicate detection, and live policy summaries.
119
+ - **Web editor: Payload inspector.** Arm the next provider request from the UI, display captures with collapsible JSON sections, redaction preserved, char/token estimates, and copy controls. Captures triggered by `/payload next` are also visible in the browser.
120
+ - **Web editor: Full-screen structured preview inspector.** Collapsible system/message sections, char/token estimates, and copy controls for full preview and individual sections.
121
+ - **Web editor: Structured editors** for stack `context` options, `variables`, tool/skill policy, and `regex.rules` with drag-and-drop reordering.
122
+ - **Web editor: Raw JSON recovery path.** View, copy, and apply raw stack JSON for advanced stack-level fields.
123
+ - **Compact prompt slot formats.** Opt-in `format: "plain"` for `tools`, `tool-guidelines`, `skills`, `project-context`, and `variables` slots. XML remains the default.
124
+ - **Chat-history controls.** `chat-history` slots can opt into `stripAssistantThinking: true`, summary omission, role filters, `toolMode: "drop"`, `maxMessages`, and `maxChars`. Filtering/trimming repairs dangling tool calls/results before model-bound history is sent.
125
+ - **Prompt-stack storage migration.** New stacks write to `.pi/forge/prompt-stacks/`; legacy `.pi/prompt-stacks/` remains readable and is shadowed by same-named forge files. `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` copies legacy stacks into forge storage.
126
+ - **SillyTavern regex import.** Safe `promptOnly` regex scripts are converted into pi-forge outgoing `history` regex rules during import, including `{{match}}` / `$0` full-match conversion, trim strings, depth fields, clear user/assistant placement mapping, and preserved `source.sillytavern` metadata. Display-only, mixed, JavaScript, DOM/browser, CSS/HTML decoration, and unsupported-placement scripts remain report-only with migration notes.
127
+ - **`/preset ui` server reuse.** Existing same-project editor servers are reclaimed after extension reinitialization from session navigation or new-session flows, preventing orphaned servers.
128
+ - **`/payload next [save=<path>]` command.** Displays and optionally saves the next redacted/truncated provider payload with char/token estimates.
129
+ - **`/preset migrate-stacks` command** with `--dry-run`, `--overwrite`, and `--delete-legacy` options.
130
+
131
+ ### Changed
132
+
133
+ - **Web editor architecture split.** `src/web-editor.ts` split into `src/web-editor/` module folder (`index.ts`, `types.ts`, `server.ts`, `page.ts`). `src/index.ts` split into `src/web-host.ts` (stack CRUD/web-editor host) and `src/payload-capture.ts` (provider payload redaction/capture).
134
+ - **Prompt state removed before 0.3.0 release.** pi-forge now keeps template variables and SillyTavern-style variable macros, but no longer exposes stack `state.definitions`, `/state`, `/preset vars`, `forge_state_set`, `forge_set_var`, state metadata rendering, or web runtime state editing.
135
+ - **Context rewrite** limited to the first provider request of each user-submitted turn, avoiding repeated injection after tool calls.
136
+ - **`/preset import-silly`** now detects `{{lastUserMessage}}` and configures chat history accordingly. SillyTavern `{{setvar}}`/`{{getvar}}` macros reported as handled instead of migration-needed.
137
+ - **`/preset reload`** preserves explicit disabled selection instead of reactivating `default.json`.
138
+ - SillyTavern import reports now include `extensions.regex_scripts` counts, prompt/display classification, script names, per-script conversion warnings, and migration notes.
139
+
140
+ ### Removed
141
+
142
+ - Implicit `allow`-takes-priority-over-`deny` behavior in resource policy evaluation.
143
+ - Prompt-state memory layer: `state.definitions`, `/state`, `/preset vars`, `forge_state_set`, `forge_set_var`, metadata/namespace/JSON prompt-state rendering, and web runtime state editing.
144
+
145
+ ## [0.2.0] - 2025-06-13
146
+
147
+ ### Added
148
+
149
+ - File-backed prompt stacks with `replace`, `append`, and `prepend` system prompt modes.
150
+ - Movable `chat-history` slot with optional omission of latest user message.
151
+ - Runtime slots: `tools`, `tool-guidelines`, `skills`, `project-context`, `append-system-prompt`, `date`, `cwd`, `date-cwd`, `active-model`, `pi-docs`, `variables`.
152
+ - Built-in macros: `{{cwd}}`, `{{date}}`, `{{time}}`, `{{lastUserMessage}}`, `{{selectedTools}}`, `{{tools}}`, `{{activeModel}}`.
153
+ - Turn/session/static variable lookup and mutation macros.
154
+ - Branch-aware macro session variable restoration during session tree navigation.
155
+ - `/preset` commands: `list`, `status`, `use`, `preview`, `validate`, `diagnostics`, `reload`, `vars`, `ui`.
156
+ - `/intercept` command for next provider payload inspection.
157
+ - `/preset import-silly` command for SillyTavern preset import with import reports.
158
+ - `/preset ui` local web editor for prompt-stack management.
159
+ - Node built-in test suite covering compiler, loader, importer, and command/event harness.
160
+ - Chinese README (`README.zh-CN.md`).
package/PUBLIC_API.md ADDED
@@ -0,0 +1,28 @@
1
+ # Public API Policy
2
+
3
+ pi-forge is pre-1.0. This document separates supported integration surfaces from experimental 0.4 work and compatibility paths that should not become permanent dependencies.
4
+
5
+ ## Stable
6
+
7
+ - The package default export is the Pi extension entry point declared by `pi.extensions`.
8
+ - Package-root macro and slot registration APIs (`registerMacro`, `registerSlot`, their registry readers, render contexts, and declarative definition types) are supported for trusted reusable extensions.
9
+ - `ForgeExtensionApi` and related registration types are supported for trusted project-local forge extensions.
10
+
11
+ Stable means changes should preserve source compatibility within the documented supported release range unless a changelog entry explicitly announces a breaking release.
12
+
13
+ ## Experimental
14
+
15
+ - Agent-profile repository, resolution, application, preview, provenance, and drift APIs are 0.4 experimental surfaces.
16
+ - The runner-neutral subagent contract, host-resolution helpers, optional empty-by-default backend registry, retained `PiSdkIsolatedBackend`, and default `PiSubprocessBackend` adapter are 0.4 experimental surfaces.
17
+ - New subagent integrations should import from `@zihanw/pi-forge/subagent`. The package root continues to re-export the current subagent names through the 0.4 prereleases for compatibility.
18
+
19
+ Experimental APIs are typed, tested, and documented, but may be revised before the 0.4 release as real adapter and parent-integration work exposes missing semantics. Changes should still be deliberate and recorded.
20
+
21
+ ## Internal compatibility paths
22
+
23
+ - `@zihanw/pi-forge/src/*` subpath exports exist for compatibility with earlier source-shaped imports. They resolve to compiled `dist` modules and are not a promise that every implementation module is a permanent public API.
24
+ - `src/subagent-contract.ts` is a compatibility barrel over the focused contract modules; it does not contain a second implementation.
25
+ - Physical `src/` files are not included in the npm tarball. Runtime installation and legacy `@zihanw/pi-forge/src/*` aliases use compiled `dist` modules; source inspection or modification requires a repository clone.
26
+ - `scripts/subagent-sdk-spike*.ts` are diagnostic development interfaces, not a supported runner API.
27
+
28
+ Before removing the compatibility subpaths, check known consumers, announce the change, and provide supported package entry points for legitimate integrations.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![pi-forge header](https://raw.githubusercontent.com/MacroSony/pi-forge/main/assets/pi-forge-header-concept-1.png)
6
6
 
7
- **pi-forge** lets you customize how Pi thinks and behaves. It gives you prompt stacks — JSON files that can replace, append to, or prepend Pi's default system prompt while controlling the AI's personality, visible tools, conversation history layout, template variables, and prompt transforms.
7
+ **pi-forge** lets you customize how Pi thinks and behaves. It gives you prompt stacks for prompt/tool policy and agent profiles that apply a model, thinking level, and prompt stack as a reusable one-shot preset.
8
8
 
9
9
  Think of it as a character sheet for your AI agent.
10
10
 
@@ -12,6 +12,7 @@ Think of it as a character sheet for your AI agent.
12
12
 
13
13
  - **Give Pi a personality** — turn it into a creative writer, a roleplay partner, a strict code reviewer, or anything in between.
14
14
  - **Switch contexts instantly** — one command to swap between "coding mode", "writing mode", and "translation mode".
15
+ - **Save complete agent presets** — capture the current model, thinking level, and prompt stack, then apply them together later.
15
16
  - **Control what the AI sees** — choose which tools, skills, and project context appear in each prompt.
16
17
  - **Limit tools and skills per stack** — enforce active tool policy and filter skill visibility for focused modes.
17
18
  - **Use template variables** — define static values such as `{{char}}` / `{{user}}`, and use ST-style turn/session variable macros inside prompt text.
@@ -24,9 +25,13 @@ Think of it as a character sheet for your AI agent.
24
25
  ### Install
25
26
 
26
27
  ```bash
27
- pi install npm:@zihanw/pi-forge
28
+ pi install npm:@zihanw/pi-forge@0.4.0-beta.1
28
29
  ```
29
30
 
31
+ The beta is published under npm's `next` channel rather than replacing the stable `latest` release. It requires Node.js 22.19 or newer and the exact `@earendil-works/pi-*` 0.80.10 packages used by Pi 0.80.10.
32
+
33
+ > **Pi version compatibility:** Pi changed session authentication/runtime wiring within the 0.80.x line. This build targets 0.80.10 exactly; 0.80.6–0.80.9 and later unverified 0.80.x releases are not claimed as compatible. After installing or rebuilding pi-forge, restart Pi so the extension and host SDK agree. If the parent agent can use a provider but subagent preparation reports `No API key found`, check for an older pi-forge build before using `/login`: a build using the pre-0.80.10 session API can lose the parent authentication during preparation, and logging in again does not fix that version mismatch.
34
+
30
35
  ### Your first prompt stack
31
36
 
32
37
  Create `.pi/forge/prompt-stacks/default.json` from [examples/default-prompt-stack.json](examples/default-prompt-stack.json).
@@ -50,11 +55,11 @@ Prefer clicking over typing JSON? pi-forge has a built-in web editor:
50
55
  /preset ui
51
56
  ```
52
57
 
53
- Drag, drop, create, edit, validate, inspect full previews and captured payloads, manage variables/context/regex rules in tabs, switch dark mode, recover through raw stack JSON, import, export, fork, and delete stacks — all in your browser. New stacks start from the default Pi prompt mirror layout. Stack metadata is collapsible so the active editor stays in view. The policy tab shows registered tools and loaded skills with selected-pattern chips and filtering, so allow/deny rules can be built from exact names while still supporting wildcards.
58
+ Drag, drop, create, edit, validate, inspect full previews and captured payloads, manage variables/context/regex rules in tabs, switch dark mode, recover through raw stack JSON, import, export, fork, and delete stacks — all in your browser. New stacks start from the default Pi prompt mirror layout. Existing stack IDs are immutable; use Fork to create a new ID without risking profile references or active selection. Stack metadata is collapsible so the active editor stays in view. The policy tab shows registered tools and loaded skills with selected-pattern chips and filtering, so allow/deny rules can be built from exact names while still supporting wildcards.
54
59
 
55
60
  Import accepts native pi-forge stack JSON and SillyTavern preset JSON. SillyTavern presets are converted to prompt stacks automatically; if a preset contains multiple `character_id` configs, the editor asks which one to use.
56
61
 
57
- The editor runs on an available `127.0.0.1` port with a session token, so multiple Pi instances can run editors at the same time. If Pi reinitializes the extension after session navigation or a new session, `/preset ui` reuses the existing editor URL for the same project instead of orphaning the old server. Writes require a trusted project and stay inside prompt-stack storage. New stacks are written to `.pi/forge/prompt-stacks`; existing legacy stacks under `.pi/prompt-stacks` remain readable and editable. Successful save, import, fork, and delete actions reload into the current Pi session. Use `/preset ui restart` or `/preset ui stop` when needed.
62
+ The editor runs on an available `127.0.0.1` port with a session token, so multiple Pi instances can run editors at the same time. If Pi reinitializes the extension after session navigation or a new session, `/preset ui` reuses the existing editor URL for the same project instead of orphaning the old server; resources and preview remain available across lifecycle refreshes. Writes require a trusted project and stay inside prompt-stack storage. New stacks are written to `.pi/forge/prompt-stacks`; existing legacy stacks under `.pi/prompt-stacks` remain readable and editable. Successful save, import, fork, and delete actions reload into the current Pi session. Use `/preset ui restart` or `/preset ui stop` when needed.
58
63
 
59
64
  To copy old stacks into the new location, run `/preset migrate-stacks`. Add `--dry-run` to preview, `--overwrite` to replace existing target files, and `--delete-legacy` to remove old files after successful copy.
60
65
 
@@ -68,6 +73,70 @@ To prefer a specific port, create `.pi/forge/config.json`. If that port is busy,
68
73
  }
69
74
  ```
70
75
 
76
+ ### Agent profiles
77
+
78
+ Agent profiles are project-local JSON files under `.pi/forge/agent-profiles`. The quickest way to create one is to configure Pi normally and capture the current model, thinking level, and prompt-stack selection:
79
+
80
+ ```text
81
+ /profile save reviewer
82
+ /profile use reviewer
83
+ ```
84
+
85
+ Profiles are applied once. They do not continuously own Pi's model or thinking level, so later manual changes are preserved until `/profile use reviewer` is run again. Prompt-stack tool policy remains strict for as long as that stack is active.
86
+
87
+ A profile can also be written directly:
88
+
89
+ ```json
90
+ {
91
+ "schemaVersion": 1,
92
+ "type": "pi-forge.agent-profile",
93
+ "id": "reviewer",
94
+ "name": "Reviewer",
95
+ "description": "Reviews code without making changes.",
96
+ "autoActivate": true,
97
+ "model": {
98
+ "provider": "provider-id",
99
+ "id": "model-id"
100
+ },
101
+ "thinkingLevel": "high",
102
+ "promptStack": "reviewer"
103
+ }
104
+ ```
105
+
106
+ `autoActivate: true` applies the complete profile once when Pi starts a fresh session. At most one profile may request auto-activation. An auto-activated profile takes precedence over standalone prompt-stack autoload, including when its `promptStack` is `null`; if no profile requests auto-activation, the existing `default.json`/`autoActivate` stack behavior remains the fallback. Restored branch selections take precedence over both mechanisms.
107
+
108
+ `promptStack` may be `null`. Tool names and skill lists do not belong in profile v1: the referenced prompt stack is the single source of truth for tool policy and model-visible skill filtering. Profile validation rejects unsupported fields rather than silently retaining inert generation or runner settings.
109
+
110
+ `/profile preview <id>` resolves the model, authentication, thinking-level support, prompt stack, and effective tools without changing runtime state. `/profile status` reports the last-applied profile and current drift; it deliberately does not describe a profile as active. Provenance follows the session branch for status purposes but never causes automatic reapplication during reload, resume, tree navigation, or compaction. Fresh-session auto-activation is still one-shot, so later manual changes are preserved.
111
+
112
+ ### Experimental foreground subagent
113
+
114
+ The 0.4 beta can run a stored profile as a separate, clean, one-shot Pi subprocess. The no-egress `forge_subagent_profiles` tool lets the main agent discover the currently loaded profile IDs, names, descriptions, declared model/thinking/stack, current resolution status, and approval mode. It should call that first when the user has not specified a profile, then invoke `forge_subagent`. A restrictive main-agent prompt stack must permit both tool names. The same execution path remains available to a human through commands:
115
+
116
+ ```text
117
+ /forge-agent backends
118
+ /forge-agent plan reviewer Review this API design for correctness.
119
+ /forge-agent run reviewer Review this API design for correctness.
120
+ ```
121
+
122
+ `plan` resolves the profile and stack, compiles the exact provider-bound prompt, validates an immutable execution plan, and then discards it without contacting the provider. `/forge-agent run` and, by default, `forge_subagent` prepare that same exact plan before showing an approval screen. The default screen shows the agent task, profile/stack, provider, model, thinking level, effective tools, working directory, security boundary, payload size, and execution fingerprint. Choose **View full prompt** to inspect the complete system prompt and ordered provider-bound messages before approving; any editor changes are ignored.
123
+
124
+ To deliberately let the parent agent invoke `forge_subagent` without per-run approval, set the following trusted-project option in `.pi/forge/config.json`:
125
+
126
+ ```json
127
+ {
128
+ "subagents": {
129
+ "allowAgentInvocationWithoutApproval": true
130
+ }
131
+ }
132
+ ```
133
+
134
+ This option affects only the model-callable `forge_subagent` tool; `/forge-agent run` remains interactively approved. The exact preflight and immutable-plan checks still run, and the tool result records `trusted-project-config` as its authorization source, but provider transport begins without showing the prompt to a human. Profile discovery reports the active approval mode. The setting is ignored for untrusted projects and malformed values fail closed. Treat the project config as authorization: do not enable or commit this option in a repository unless every parent agent allowed to use `forge_subagent` should be able to send the compiled prompt and readable file contents to the selected provider without asking again.
135
+
136
+ The child starts with a clean conversation and receives no parent history automatically. It runs in the foreground with the profile's exact model/thinking level and prompt stack. Its only candidate tools are `read`, `grep`, `find`, and `ls`, further restricted by the stack's tool policy; it receives no write/edit/shell tools, skills, prompt templates, context files, or third-party extensions. The final tool result contains a bounded model-visible report plus expandable human-visible execution details. Retained transcript strings are individually bounded, base64-like text is redacted, and the transcript keeps a 512 KiB rolling tail so the final report remains available without making the TUI retain an unbounded tool history. Inline image data stays inside the child long enough for the selected vision model to use it, but the dedicated report channel replaces binary payloads with MIME type and encoded-size metadata before anything is retained in the parent session.
137
+
138
+ Important: this first backend is **shared-user**, not an operating-system sandbox. Read-only is a model-tool policy: the subprocess retains the invoking user's OS permissions, and absolute paths readable by that user may be read, sent to the selected provider, and retained as text inside the parent tool-result details. Host timeout and cancellation are best effort. `/tree` removes the invocation and result from the active conversation branch, but abandoned entries can remain in Pi's on-disk session JSONL; deleting sensitive retained text requires deleting the relevant session data. `/tree` also cannot undo provider requests, billing, or external side effects. The default tool set intentionally provides no filesystem mutation path while a bubblewrap-style sandbox and staged write mode remain future work.
139
+
71
140
  ## Use cases
72
141
 
73
142
  ### 🎭 Roleplay & creative writing
@@ -156,7 +225,7 @@ See exactly what gets sent to the model:
156
225
  /payload next save=.pi/forge/payloads/last.json
157
226
  ```
158
227
 
159
- Or open `/preset ui`, click **Arm payload**, send the next Pi prompt, and inspect the redacted provider payload in the browser.
228
+ Or open `/preset ui`, click **Arm payload**, send the next Pi prompt, and inspect the redacted provider payload in the browser. Credential-shaped token fields remain hidden, while normal limits and accounting fields such as `max_tokens`, `input_tokens`, and `output_tokens` remain visible.
160
229
 
161
230
  Or preview your compiled prompt without sending anything:
162
231
 
@@ -220,6 +289,29 @@ Items are arranged in order. When the stack is active, pi-forge:
220
289
  | `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | Copy legacy `.pi/prompt-stacks` files into `.pi/forge/prompt-stacks` |
221
290
  | `/preset ui [stop\|restart]` | Open, stop, or restart the web editor |
222
291
 
292
+ ### Managing agent profiles
293
+
294
+ | Command | What it does |
295
+ |---------|-------------|
296
+ | `/profile list` | Show project profiles and resolution diagnostics |
297
+ | `/profile use <id>` | Preflight and apply a profile once |
298
+ | `/profile save <id> [--overwrite]` | Capture the current model, thinking level, and prompt stack |
299
+ | `/profile status` | Show current runtime, last-applied provenance, and drift |
300
+ | `/profile preview <id>` | Preview resolved effects and effective tools without applying |
301
+ | `/profile validate [id]` | Validate one profile, or all profiles when omitted |
302
+ | `/profile reload` | Reload profile files without applying them |
303
+ | `/profile forget` | Forget last-applied provenance without changing runtime state |
304
+
305
+ ### Experimental foreground subagent
306
+
307
+ | Command | What it does |
308
+ |---------|-------------|
309
+ | `/forge-agent backends` | Show the available experimental backend and its capabilities |
310
+ | `/forge-agent plan <profile> <task>` | Prepare, validate, display, and discard an exact plan without provider transport |
311
+ | `/forge-agent run <profile> <task>` | Review the exact plan and run one foreground read-only text task after approval |
312
+
313
+ The model-callable tools are `forge_subagent_profiles` for local metadata discovery and `forge_subagent` for execution. Discovery needs no approval and performs no provider request or subagent prompt preparation. Invocation requires the current main-agent tool policy to permit it; execution then requires either an interactive approval UI or the explicit trusted-project unattended option described above.
314
+
223
315
  ### Import & debug
224
316
 
225
317
  | Command | What it does |
@@ -422,7 +514,7 @@ The default Pi mirror uses a few extra slot options:
422
514
 
423
515
  ### Tool and skill policy
424
516
 
425
- Prompt stacks can constrain tools and skills with stack-level `allow` or `deny` lists. Patterns are exact by default and support `*` wildcards.
517
+ Prompt stacks can constrain active tools and filter model-visible skills with stack-level `allow` or `deny` lists. Patterns are exact by default and support `*` wildcards.
426
518
 
427
519
  ```json
428
520
  {
@@ -435,11 +527,11 @@ Prompt stacks can constrain tools and skills with stack-level `allow` or `deny`
435
527
  }
436
528
  ```
437
529
 
438
- Use `allow` when only matching tools or skills should remain active. Use `deny` when everything except matching tools or skills should remain active. A single resource policy cannot contain both non-empty lists; mixed `allow` and `deny` entries are validation errors.
530
+ For tools, use `allow` when only matching active tools should remain and `deny` when matching active tools should be removed. For skills, the same patterns control which skills remain visible in pi-forge's rendered `skills` slots. A single resource policy cannot contain both non-empty lists; mixed `allow` and `deny` entries are validation errors.
439
531
 
440
- Tool policy is enforced through Pi's active tool list while the stack is active. pi-forge remembers the previous active tools and restores them when prompt stacks are disabled or switched to an unrestricted stack.
532
+ Tool policy is enforced through Pi's active tool list while the stack is active. On startup and reload, pi-forge waits for other extensions to finish their `session_start` tool configuration before capturing the baseline and applying the stack policy. It reasserts the policy before user input and turns, and a tool-call guard blocks disallowed model tool execution even if another extension later calls `setActiveTools()`. External tool additions are preserved in the restorable baseline, which is restored when prompt stacks are disabled or switched to an unrestricted stack.
441
533
 
442
- Skill policy filters skills rendered by pi-forge's `skills` slot. If a stack uses `mode: "append"` or `"prepend"`, Pi's base prompt may already contain unfiltered skills; use `mode: "replace"` when skill visibility must be controlled.
534
+ Skill policy filters skills rendered by pi-forge's `skills` slot. It does not disable explicit skill invocation and is not a capability or security boundary. If a stack uses `mode: "append"` or `"prepend"`, Pi's base prompt may already contain unfiltered skills; use `mode: "replace"` when model-visible skill listings must be controlled.
443
535
 
444
536
  ### Regex transforms
445
537
 
@@ -509,20 +601,46 @@ SillyTavern imports convert deterministic prompt-only `{{match}}` / `$0` full-ma
509
601
  ## Package setup for development
510
602
 
511
603
  ```bash
512
- git clone <repo>
604
+ git clone https://github.com/MacroSony/pi-forge.git
513
605
  cd pi-forge
514
606
  npm install
515
607
  npm run build
516
- # .pi/settings.json already points at the package root
608
+ # .pi/settings.json loads the package's built dist/index.js
517
609
  pi # start Pi, trust the project, /reload if needed
518
610
  ```
519
611
 
612
+ The npm package intentionally omits physical `src/` files and loads compiled `dist/` output at runtime. To inspect or modify pi-forge itself, clone or fork the repository instead of editing `node_modules` or generated `dist/` files. A clone preserves your changes in Git and includes the development dependencies, tests, and source-to-dist consistency checks.
613
+
614
+ For release-like local testing, register the cloned package directory. Its package manifest loads the tracked `dist/index.js`:
615
+
616
+ ```json
617
+ {
618
+ "packages": ["../pi-forge"]
619
+ }
620
+ ```
621
+
622
+ For live source development, remove that pi-forge package entry and load the TypeScript extension directly from `.pi/settings.json`:
623
+
624
+ ```json
625
+ {
626
+ "extensions": ["../pi-forge/src/index.ts"]
627
+ }
628
+ ```
629
+
630
+ You can also run `pi -e ../pi-forge/src/index.ts` for a one-off source-level smoke test. Do not load the package and source entry simultaneously or pi-forge will initialize twice. Browser-client source changes additionally require `npm run build:client` because the local editor serves its generated browser bundle.
631
+
520
632
  Run tests:
521
633
 
522
634
  ```bash
523
635
  npm test
524
636
  ```
525
637
 
638
+ Run the real-browser editor smoke test (set `CHROME_PATH` if Chrome is not in a standard location):
639
+
640
+ ```bash
641
+ npm run test:browser
642
+ ```
643
+
526
644
  Typecheck:
527
645
 
528
646
  ```bash
@@ -535,6 +653,14 @@ Build package output:
535
653
  npm run build
536
654
  ```
537
655
 
656
+ Run the full repository verification, including a clean temporary build that checks tracked `dist/` byte-for-byte against `src/`:
657
+
658
+ ```bash
659
+ npm run verify
660
+ ```
661
+
662
+ The same verification runs in CI. When source changes affect generated output, run `npm run build` and commit the matching `dist/` changes with the source changes.
663
+
538
664
  ## License
539
665
 
540
666
  MIT