@zihanw/pi-forge 0.4.1 → 0.5.0
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.
- package/CHANGELOG.md +41 -1
- package/README.md +11 -11
- package/README.zh-CN.md +3 -5
- package/SUBAGENT_ADAPTER_CONTRACT.md +3 -1
- package/dist/agent-profile.d.ts +18 -62
- package/dist/agent-profile.d.ts.map +1 -1
- package/dist/agent-profile.js +27 -249
- package/dist/agent-profile.js.map +1 -1
- package/dist/codecs/agent-profile.d.ts +53 -0
- package/dist/codecs/agent-profile.d.ts.map +1 -0
- package/dist/codecs/agent-profile.js +176 -0
- package/dist/codecs/agent-profile.js.map +1 -0
- package/dist/codecs/index.d.ts +5 -0
- package/dist/codecs/index.d.ts.map +1 -0
- package/dist/codecs/index.js +3 -0
- package/dist/codecs/index.js.map +1 -0
- package/dist/codecs/prompt-stack.d.ts +18 -0
- package/dist/codecs/prompt-stack.d.ts.map +1 -0
- package/dist/codecs/prompt-stack.js +479 -0
- package/dist/codecs/prompt-stack.js.map +1 -0
- package/dist/compile-cycle.d.ts +18 -0
- package/dist/compile-cycle.d.ts.map +1 -0
- package/dist/compile-cycle.js +13 -0
- package/dist/compile-cycle.js.map +1 -0
- package/dist/compiler.d.ts +10 -4
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +53 -19
- package/dist/compiler.js.map +1 -1
- package/dist/extension-registry.d.ts.map +1 -1
- package/dist/extension-registry.js +5 -2
- package/dist/extension-registry.js.map +1 -1
- package/dist/forge-config.d.ts +0 -105
- package/dist/forge-config.d.ts.map +1 -1
- package/dist/forge-config.js +1 -313
- package/dist/forge-config.js.map +1 -1
- package/dist/forge-v1/analyzer.d.ts +3 -0
- package/dist/forge-v1/analyzer.d.ts.map +1 -0
- package/dist/forge-v1/analyzer.js +50 -0
- package/dist/forge-v1/analyzer.js.map +1 -0
- package/dist/forge-v1/index.d.ts +6 -0
- package/dist/forge-v1/index.d.ts.map +1 -0
- package/dist/forge-v1/index.js +13 -0
- package/dist/forge-v1/index.js.map +1 -0
- package/dist/forge-v1/parser.d.ts +3 -0
- package/dist/forge-v1/parser.d.ts.map +1 -0
- package/dist/forge-v1/parser.js +186 -0
- package/dist/forge-v1/parser.js.map +1 -0
- package/dist/forge-v1/renderer.d.ts +9 -0
- package/dist/forge-v1/renderer.d.ts.map +1 -0
- package/dist/forge-v1/renderer.js +181 -0
- package/dist/forge-v1/renderer.js.map +1 -0
- package/dist/forge-v1/types.d.ts +87 -0
- package/dist/forge-v1/types.d.ts.map +1 -0
- package/dist/forge-v1/types.js +4 -0
- package/dist/forge-v1/types.js.map +1 -0
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -81
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +6 -5
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +43 -112
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts +5 -8
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +10 -467
- package/dist/loader.js.map +1 -1
- package/dist/macro-engine.d.ts +9 -14
- package/dist/macro-engine.d.ts.map +1 -1
- package/dist/macro-engine.js +5 -238
- package/dist/macro-engine.js.map +1 -1
- package/dist/payload-command.d.ts +6 -6
- package/dist/payload-command.d.ts.map +1 -1
- package/dist/payload-command.js.map +1 -1
- package/dist/payload-state.d.ts +16 -0
- package/dist/payload-state.d.ts.map +1 -0
- package/dist/payload-state.js +14 -0
- package/dist/payload-state.js.map +1 -0
- package/dist/preset-command.d.ts +4 -4
- package/dist/preset-command.d.ts.map +1 -1
- package/dist/preset-command.js +33 -104
- package/dist/preset-command.js.map +1 -1
- package/dist/preview.d.ts +4 -4
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +17 -8
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.d.ts +2 -2
- package/dist/profile-command.d.ts.map +1 -1
- package/dist/profile-command.js +15 -14
- package/dist/profile-command.js.map +1 -1
- package/dist/profile-service.d.ts.map +1 -1
- package/dist/profile-service.js +23 -39
- package/dist/profile-service.js.map +1 -1
- package/dist/prompt-analysis.d.ts +24 -0
- package/dist/prompt-analysis.d.ts.map +1 -0
- package/dist/prompt-analysis.js +84 -0
- package/dist/prompt-analysis.js.map +1 -0
- package/dist/prompt-runtime.d.ts +19 -0
- package/dist/prompt-runtime.d.ts.map +1 -0
- package/dist/prompt-runtime.js +30 -0
- package/dist/prompt-runtime.js.map +1 -0
- package/dist/regex.js +6 -12
- package/dist/regex.js.map +1 -1
- package/dist/render-helpers.d.ts +2 -10
- package/dist/render-helpers.d.ts.map +1 -1
- package/dist/render-helpers.js +3 -53
- package/dist/render-helpers.js.map +1 -1
- package/dist/repositories/agent-profile.d.ts +36 -0
- package/dist/repositories/agent-profile.d.ts.map +1 -0
- package/dist/repositories/agent-profile.js +153 -0
- package/dist/repositories/agent-profile.js.map +1 -0
- package/dist/repositories/index.d.ts +3 -0
- package/dist/repositories/index.d.ts.map +1 -0
- package/dist/repositories/index.js +3 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/repositories/prompt-stack.d.ts +57 -0
- package/dist/repositories/prompt-stack.d.ts.map +1 -0
- package/dist/repositories/prompt-stack.js +175 -0
- package/dist/repositories/prompt-stack.js.map +1 -0
- package/dist/runtime/profile-runtime.d.ts +2 -2
- package/dist/runtime/profile-runtime.d.ts.map +1 -1
- package/dist/runtime/profile-runtime.js +13 -10
- package/dist/runtime/profile-runtime.js.map +1 -1
- package/dist/runtime/prompt-stack-runtime.d.ts +4 -3
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
- package/dist/runtime/prompt-stack-runtime.js +42 -57
- package/dist/runtime/prompt-stack-runtime.js.map +1 -1
- package/dist/runtime/tool-policy-runtime.d.ts +2 -2
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
- package/dist/runtime/tool-policy-runtime.js +3 -3
- package/dist/runtime/tool-policy-runtime.js.map +1 -1
- package/dist/session-adapter.d.ts +17 -0
- package/dist/session-adapter.d.ts.map +1 -0
- package/dist/session-adapter.js +57 -0
- package/dist/session-adapter.js.map +1 -0
- package/dist/slot-renderers.d.ts +16 -3
- package/dist/slot-renderers.d.ts.map +1 -1
- package/dist/slot-renderers.js +15 -63
- package/dist/slot-renderers.js.map +1 -1
- package/dist/stack-migration.d.ts +6 -0
- package/dist/stack-migration.d.ts.map +1 -1
- package/dist/stack-migration.js +49 -52
- package/dist/stack-migration.js.map +1 -1
- package/dist/subagent/fingerprints.d.ts +24 -0
- package/dist/subagent/fingerprints.d.ts.map +1 -0
- package/dist/subagent/fingerprints.js +81 -0
- package/dist/subagent/fingerprints.js.map +1 -0
- package/dist/subagent/host-port.d.ts +296 -0
- package/dist/subagent/host-port.d.ts.map +1 -0
- package/dist/subagent/host-port.js +560 -0
- package/dist/subagent/host-port.js.map +1 -0
- package/dist/subagent/index.d.ts +10 -10
- package/dist/subagent/index.d.ts.map +1 -1
- package/dist/subagent/index.js +9 -10
- package/dist/subagent/index.js.map +1 -1
- package/dist/subagent-host.d.ts +99 -18
- package/dist/subagent-host.d.ts.map +1 -1
- package/dist/subagent-host.js +143 -146
- package/dist/subagent-host.js.map +1 -1
- package/dist/template-render.d.ts +18 -0
- package/dist/template-render.d.ts.map +1 -0
- package/dist/template-render.js +232 -0
- package/dist/template-render.js.map +1 -0
- package/dist/types.d.ts +40 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/web-editor/client-script.generated.d.ts.map +1 -1
- package/dist/web-editor/client-script.generated.js +1 -1
- package/dist/web-editor/client-script.generated.js.map +1 -1
- package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
- package/dist/web-editor/client-styles.generated.js +1 -1
- package/dist/web-editor/client-styles.generated.js.map +1 -1
- package/dist/web-editor/server.d.ts.map +1 -1
- package/dist/web-editor/server.js +1 -68
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts.map +1 -1
- package/dist/web-editor/styles.js +13 -0
- package/dist/web-editor/styles.js.map +1 -1
- package/dist/web-editor/types.d.ts +0 -35
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +4 -2
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +32 -103
- package/dist/web-host.js.map +1 -1
- package/dist/workspace.d.ts +74 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +351 -0
- package/dist/workspace.js.map +1 -0
- package/docs/README.md +6 -4
- package/docs/concepts/agent-profiles.md +1 -1
- package/docs/concepts/prompt-stacks.md +5 -5
- package/docs/design/README.md +21 -3
- package/docs/design/architecture-0.5.md +211 -0
- package/docs/design/archive/0.5-full-proposal/0.5-consumer-audit.md +62 -0
- package/docs/design/archive/0.5-full-proposal/0.5-inventory.md +208 -0
- package/docs/design/archive/0.5-full-proposal/0.5-phase0-decision-drafts.md +237 -0
- package/docs/design/archive/0.5-full-proposal/README.md +12 -0
- package/docs/design/archive/0.5-full-proposal/architecture-0.5.md +423 -0
- package/docs/design/archive/0.5-full-proposal/host-discovery-spike.md +103 -0
- package/docs/design/archive/0.5-full-proposal/template-language-spike.md +156 -0
- package/docs/design/context-diff-plan.md +72 -0
- package/docs/design/decision-template.md +33 -0
- package/docs/design/roadmap-0.4-archive.md +1 -1
- package/docs/design/subagents/interface-design.md +1 -1
- package/docs/development/architecture-rules.md +148 -0
- package/docs/development/roadmap.md +37 -5
- package/docs/development/scoped-global-profiles-stacks.md +1 -1
- package/docs/development/setup.md +6 -4
- package/docs/getting-started.md +5 -4
- package/docs/guides/custom-macros-and-slots.md +8 -7
- package/docs/guides/debugging.md +1 -1
- package/docs/guides/delegation.md +18 -22
- package/docs/guides/migrating-to-0.5.md +107 -0
- package/docs/guides/use-cases.md +7 -11
- package/docs/guides/web-editor.md +5 -9
- package/docs/reference/commands.md +4 -3
- package/docs/reference/configuration.md +17 -18
- package/docs/reference/features.md +34 -80
- package/docs/reference/macros-and-slots.md +70 -49
- package/docs/reference/public-api.md +64 -17
- package/docs/reference/stack-schema.md +14 -9
- package/docs/reference/subagent-host-port.md +49 -0
- package/docs/zh-CN/README.md +3 -3
- package/docs/zh-CN/concepts/agent-profiles.md +1 -1
- package/docs/zh-CN/concepts/prompt-stacks.md +4 -4
- package/docs/zh-CN/getting-started.md +3 -2
- package/docs/zh-CN/guides/delegation.md +10 -12
- package/docs/zh-CN/guides/migrating-to-0.5.md +92 -0
- package/docs/zh-CN/guides/web-editor.md +4 -4
- package/docs/zh-CN/reference/commands.md +3 -2
- package/examples/custom-system-status-extension/README.md +3 -3
- package/examples/custom-system-status-extension/index.ts +2 -1
- package/examples/custom-system-status-extension/prompt-stack.json +4 -3
- package/examples/default-prompt-stack.json +9 -4
- package/examples/image-reader-prompt-stack.json +16 -26
- package/examples/reviewer-prompt-stack.json +13 -24
- package/package.json +101 -120
- package/dist/runtime/subagent-runtime.d.ts +0 -45
- package/dist/runtime/subagent-runtime.d.ts.map +0 -1
- package/dist/runtime/subagent-runtime.js +0 -343
- package/dist/runtime/subagent-runtime.js.map +0 -1
- package/dist/runtime-state.d.ts +0 -30
- package/dist/runtime-state.d.ts.map +0 -1
- package/dist/runtime-state.js +0 -17
- package/dist/runtime-state.js.map +0 -1
- package/dist/sillytavern-importer/items.d.ts +0 -3
- package/dist/sillytavern-importer/items.d.ts.map +0 -1
- package/dist/sillytavern-importer/items.js +0 -88
- package/dist/sillytavern-importer/items.js.map +0 -1
- package/dist/sillytavern-importer/macros.d.ts +0 -15
- package/dist/sillytavern-importer/macros.d.ts.map +0 -1
- package/dist/sillytavern-importer/macros.js +0 -141
- package/dist/sillytavern-importer/macros.js.map +0 -1
- package/dist/sillytavern-importer/prompt-order.d.ts +0 -6
- package/dist/sillytavern-importer/prompt-order.d.ts.map +0 -1
- package/dist/sillytavern-importer/prompt-order.js +0 -38
- package/dist/sillytavern-importer/prompt-order.js.map +0 -1
- package/dist/sillytavern-importer/regex.d.ts +0 -3
- package/dist/sillytavern-importer/regex.d.ts.map +0 -1
- package/dist/sillytavern-importer/regex.js +0 -275
- package/dist/sillytavern-importer/regex.js.map +0 -1
- package/dist/sillytavern-importer/report.d.ts +0 -21
- package/dist/sillytavern-importer/report.d.ts.map +0 -1
- package/dist/sillytavern-importer/report.js +0 -166
- package/dist/sillytavern-importer/report.js.map +0 -1
- package/dist/sillytavern-importer/types.d.ts +0 -106
- package/dist/sillytavern-importer/types.d.ts.map +0 -1
- package/dist/sillytavern-importer/types.js +0 -2
- package/dist/sillytavern-importer/types.js.map +0 -1
- package/dist/sillytavern-importer.d.ts +0 -5
- package/dist/sillytavern-importer.d.ts.map +0 -1
- package/dist/sillytavern-importer.js +0 -117
- package/dist/sillytavern-importer.js.map +0 -1
- package/dist/subagent/canonical.d.ts +0 -22
- package/dist/subagent/canonical.d.ts.map +0 -1
- package/dist/subagent/canonical.js +0 -24
- package/dist/subagent/canonical.js.map +0 -1
- package/dist/subagent/context.d.ts +0 -8
- package/dist/subagent/context.d.ts.map +0 -1
- package/dist/subagent/context.js +0 -125
- package/dist/subagent/context.js.map +0 -1
- package/dist/subagent/contract.d.ts +0 -10
- package/dist/subagent/contract.d.ts.map +0 -1
- package/dist/subagent/contract.js +0 -10
- package/dist/subagent/contract.js.map +0 -1
- package/dist/subagent/plan.d.ts +0 -18
- package/dist/subagent/plan.d.ts.map +0 -1
- package/dist/subagent/plan.js +0 -157
- package/dist/subagent/plan.js.map +0 -1
- package/dist/subagent/preflight.d.ts +0 -4
- package/dist/subagent/preflight.d.ts.map +0 -1
- package/dist/subagent/preflight.js +0 -108
- package/dist/subagent/preflight.js.map +0 -1
- package/dist/subagent/request.d.ts +0 -4
- package/dist/subagent/request.d.ts.map +0 -1
- package/dist/subagent/request.js +0 -154
- package/dist/subagent/request.js.map +0 -1
- package/dist/subagent/response.d.ts +0 -8
- package/dist/subagent/response.d.ts.map +0 -1
- package/dist/subagent/response.js +0 -155
- package/dist/subagent/response.js.map +0 -1
- package/dist/subagent/tools.d.ts +0 -4
- package/dist/subagent/tools.d.ts.map +0 -1
- package/dist/subagent/tools.js +0 -42
- package/dist/subagent/tools.js.map +0 -1
- package/dist/subagent/types.d.ts +0 -272
- package/dist/subagent/types.d.ts.map +0 -1
- package/dist/subagent/types.js +0 -3
- package/dist/subagent/types.js.map +0 -1
- package/dist/subagent/validation.d.ts +0 -35
- package/dist/subagent/validation.d.ts.map +0 -1
- package/dist/subagent/validation.js +0 -314
- package/dist/subagent/validation.js.map +0 -1
- package/dist/subagent-command.d.ts +0 -5
- package/dist/subagent-command.d.ts.map +0 -1
- package/dist/subagent-command.js +0 -249
- package/dist/subagent-command.js.map +0 -1
- package/dist/subagent-profile-tool.d.ts +0 -49
- package/dist/subagent-profile-tool.d.ts.map +0 -1
- package/dist/subagent-profile-tool.js +0 -125
- package/dist/subagent-profile-tool.js.map +0 -1
- package/dist/subagent-tool.d.ts +0 -77
- package/dist/subagent-tool.d.ts.map +0 -1
- package/dist/subagent-tool.js +0 -559
- package/dist/subagent-tool.js.map +0 -1
- package/docs/guides/sillytavern-import.md +0 -47
- package/docs/reference/subagent-adapter.md +0 -204
- package/examples/sillytavern-dm-writer-prompt-stack.json +0 -190
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Pi cross-extension host-discovery spike
|
|
2
|
+
|
|
3
|
+
[Design index](../../README.md) · [0.5 architecture plan](../../architecture-0.5.md) · [0.5 migration inventory](0.5-inventory.md)
|
|
4
|
+
|
|
5
|
+
Status: completed Phase 0 spike; architecture decision pending
|
|
6
|
+
|
|
7
|
+
Date: 2026-08-17
|
|
8
|
+
|
|
9
|
+
## Question
|
|
10
|
+
|
|
11
|
+
Can a separately installed `pi-forge-subagents` Pi extension reliably discover
|
|
12
|
+
and use the active main `pi-forge` extension without importing its internal
|
|
13
|
+
runtime state or relying on a process-global registry?
|
|
14
|
+
|
|
15
|
+
## Environment and method
|
|
16
|
+
|
|
17
|
+
- Tested against the repository's installed
|
|
18
|
+
`@earendil-works/pi-coding-agent` 0.83.0 fixture.
|
|
19
|
+
- Used Pi's exported `createEventBus`, `createExtensionRuntime`, and actual
|
|
20
|
+
`loadExtensionFromFactory` loader. The factories used only `pi.events`.
|
|
21
|
+
- This was an in-memory Phase-0 harness, not a shipped extension or production
|
|
22
|
+
host-port implementation.
|
|
23
|
+
|
|
24
|
+
The harness covered both extension load orders, compatible and incompatible
|
|
25
|
+
versions, and unregistering a host listener. All cases passed:
|
|
26
|
+
|
|
27
|
+
| Case | Result |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Host factory loads before client factory | Client discovery receives one compatible host reply |
|
|
30
|
+
| Client factory loads before host factory | Client's availability listener receives the later host announcement |
|
|
31
|
+
| Client requires an unsupported version | No host is accepted |
|
|
32
|
+
| Host unregisters its listener | A subsequent discovery request receives no reply |
|
|
33
|
+
|
|
34
|
+
## Observations
|
|
35
|
+
|
|
36
|
+
1. `ExtensionAPI.events` is a shared event bus across extension factories
|
|
37
|
+
loaded into the same Pi runtime.
|
|
38
|
+
2. The bus exposes only `emit(channel, data)` and `on(channel, handler)`, with
|
|
39
|
+
an unsubscribe function. It does not expose a service registry, request
|
|
40
|
+
return values, sender identity, serialization, timeout, version negotiation,
|
|
41
|
+
duplicate-host handling, or lifecycle ownership.
|
|
42
|
+
3. Pi wraps each event handler in an asynchronous error boundary. `emit()` is
|
|
43
|
+
therefore fire-and-forget; callers must not depend on handler order or a
|
|
44
|
+
synchronous reply, even though a handler with no initial `await` may appear
|
|
45
|
+
to reply synchronously in a simple test.
|
|
46
|
+
4. The bus is in-process. It can coordinate packages loaded into one Pi
|
|
47
|
+
invocation, but it is not a cross-process, remote, or security boundary.
|
|
48
|
+
5. A direct import of a module-level workspace singleton remains unsuitable:
|
|
49
|
+
Pi package installation can produce independent package instances, and that
|
|
50
|
+
mechanism provides no duplicate-host or reload semantics.
|
|
51
|
+
|
|
52
|
+
## Recommended decision candidate
|
|
53
|
+
|
|
54
|
+
Use Pi's event bus as the transport for a **versioned, session-scoped Forge host
|
|
55
|
+
RPC protocol**. Do not use a process registry or a direct reference to
|
|
56
|
+
`ForgeWorkspace`.
|
|
57
|
+
|
|
58
|
+
The port must use plain, validated data messages rather than function callbacks
|
|
59
|
+
or the return value of `emit()`. A minimal protocol has these message families:
|
|
60
|
+
|
|
61
|
+
| Channel family | Direction | Required behavior |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `@zihanw/pi-forge/host/v1/discover` | Client → host | Carries request ID, client identity/version, and supported protocol range |
|
|
64
|
+
| `@zihanw/pi-forge/host/v1/available` | Host → clients | Announces host ID, protocol version, capability set, and lifecycle generation after discovery listener registration |
|
|
65
|
+
| `@zihanw/pi-forge/host/v1/reply` | Host → client | Correlates discovery or operation result with request ID; carries typed success/failure data |
|
|
66
|
+
| `@zihanw/pi-forge/host/v1/request` | Client → host | Invokes only documented operations using validated request data |
|
|
67
|
+
| `@zihanw/pi-forge/host/v1/update` | Host → client | Optional bounded progress/resource-change events correlated to subscription or run IDs |
|
|
68
|
+
| `@zihanw/pi-forge/host/v1/unavailable` | Host → clients | Invalidates host ID/generation during disposal or replacement |
|
|
69
|
+
|
|
70
|
+
The final operation catalogue is still open, but must expose results and
|
|
71
|
+
snapshots—not Pi contexts, `ForgeWorkspace`, loaded resource objects, web-editor
|
|
72
|
+
state, callbacks, or internal registries. Cancellation must be a request by
|
|
73
|
+
run ID; it must not transfer `AbortSignal` objects through the port.
|
|
74
|
+
|
|
75
|
+
## Required protocol rules before implementation
|
|
76
|
+
|
|
77
|
+
- Clients subscribe to reply, availability, update, and unavailable events
|
|
78
|
+
before announcing/discovering; they use a bounded timeout and clean up all
|
|
79
|
+
listeners.
|
|
80
|
+
- A host registers discovery/request listeners before sending `available`.
|
|
81
|
+
- Host and client validate every message and ignore unknown protocol versions,
|
|
82
|
+
malformed payloads, stale generations, and unrelated request IDs.
|
|
83
|
+
- More than one live compatible host is an explicit `host.duplicate` failure;
|
|
84
|
+
the client must not silently choose a host by load order. Incompatible hosts
|
|
85
|
+
are reported distinctly.
|
|
86
|
+
- `ForgeWorkspace` owns host registration, generation, and disposal. On Pi
|
|
87
|
+
session shutdown/reload it sends `unavailable`, unregisters listeners, and
|
|
88
|
+
rejects new work; clients invalidate outstanding handles and report a clear
|
|
89
|
+
unavailable diagnostic.
|
|
90
|
+
- The port is an integration contract, not a trust boundary. Pi extensions
|
|
91
|
+
already execute in the same trusted process; the host must not transmit raw
|
|
92
|
+
credentials, arbitrary live contexts, or undeclared project data.
|
|
93
|
+
- The optional package must remain usable as an ordinary Pi extension only when
|
|
94
|
+
the main host is present and protocol-compatible. Its absence must leave the
|
|
95
|
+
main pi-forge extension fully functional.
|
|
96
|
+
|
|
97
|
+
## Limits and follow-up
|
|
98
|
+
|
|
99
|
+
This validates the event-bus transport in Pi 0.83.0 only. The Phase-0 Pi
|
|
100
|
+
compatibility gate still needs a documented range and packed-install matrix that
|
|
101
|
+
includes the release-time Pi version. The protocol, public operations, package
|
|
102
|
+
versioning, configuration ownership, and migration remain architecture decisions
|
|
103
|
+
to be accepted before Phase 5 implementation.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Template-language and compiler spike
|
|
2
|
+
|
|
3
|
+
[Design index](README.md) · [0.5 architecture plan](architecture-0.5.md) · [0.5 migration inventory](0.5-inventory.md)
|
|
4
|
+
|
|
5
|
+
Status: completed Phase 0 spike; architecture decision pending
|
|
6
|
+
|
|
7
|
+
Date: 2026-08-17
|
|
8
|
+
|
|
9
|
+
## Question
|
|
10
|
+
|
|
11
|
+
Which template language can replace 0.4 macros while keeping prompt compilation
|
|
12
|
+
deterministic over immutable inputs, statically analyzable, migrationable, and
|
|
13
|
+
free of arbitrary evaluation or template loading?
|
|
14
|
+
|
|
15
|
+
## Characterized 0.4 surface
|
|
16
|
+
|
|
17
|
+
The current macro language mixes four separate concerns:
|
|
18
|
+
|
|
19
|
+
| Concern | 0.4 behavior | 0.5 direction |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Immutable runtime values | Latest user message, date/time, cwd, selected tools, active model | Keep as explicit values in `PromptEnvironment` |
|
|
22
|
+
| Static reusable values | `stack.variables`, referenced as `{{name}}` | Keep as JSON-compatible immutable `parameters` |
|
|
23
|
+
| Text transforms | `trim`, `upper`, `lower`, `json`, `xml`, including nesting | Retain only as a finite, pure filter set if accepted |
|
|
24
|
+
| Control flow | `ifvar`, `ifeq`, `iftools`, `ifslot`, with lazy branches | Replace only with a parsed, side-effect-free conditional form if accepted |
|
|
25
|
+
| Mutable state | Turn/session variables plus set/get/clear macros and `variables` slot | Remove; emit migration diagnostics |
|
|
26
|
+
| Executable extension code | Trusted custom macro and slot renderers receive live runtime objects | Replace only through a separately accepted, immutable template/slot port |
|
|
27
|
+
|
|
28
|
+
The current examples demonstrate simple parameter and runtime interpolation;
|
|
29
|
+
the image-reader and SillyTavern examples also depend on nested filters,
|
|
30
|
+
conditionals, and mutable variables. SillyTavern is already removed from 0.5
|
|
31
|
+
scope. Any remaining non-mechanical construct must be diagnosed by migration,
|
|
32
|
+
not silently approximated.
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
The v2 engine must provide one `parse → analyze → render` contract and meet all
|
|
37
|
+
of the following:
|
|
38
|
+
|
|
39
|
+
- parsing has no filesystem, network, process, clock, environment, or Pi access;
|
|
40
|
+
- rendering receives only a frozen normalized environment and parsed template;
|
|
41
|
+
- undefined paths, invalid filters, invalid conditions, parse errors, recursion,
|
|
42
|
+
and output-limit breaches are typed errors, never silent mutation or ambient
|
|
43
|
+
fallback;
|
|
44
|
+
- analysis returns source-spanned dependencies on environment paths, filters,
|
|
45
|
+
control predicates, and registered template/slot capabilities;
|
|
46
|
+
- no includes, extends, imports, macros, function calls, loops, arbitrary
|
|
47
|
+
property traversal, or general expression evaluation;
|
|
48
|
+
- whitespace is preserved unless a deliberately documented syntax construct
|
|
49
|
+
changes it; rendering has a bounded output size;
|
|
50
|
+
- preview, parent runtime, and subagent preparation invoke the same engine and
|
|
51
|
+
receive recorded environment/provenance values.
|
|
52
|
+
|
|
53
|
+
## Candidate comparison
|
|
54
|
+
|
|
55
|
+
| Candidate | Parse/analyze/render fit | Restriction and determinism | Migration fit | Result |
|
|
56
|
+
|---|---|---|---|---|
|
|
57
|
+
| General Jinja-like engine (Nunjucks) | Has parsing/rendering and strict-undefined option | Fails the trust requirement: its own documentation says it does not sandbox user-defined templates; it supports loaders, includes, extensions, async behavior, and a rich expression language | Familiar delimiters, but an unsafe/surplus language would need a fragile denylist | Reject |
|
|
58
|
+
| Restricted LiquidJS wrapper | Provides parsed templates and documented static analysis | Better parser option, but its Liquid tags, includes, filters, and plugin model would still require a security-sensitive allowlist/wrapper; syntax is not Jinja-compatible | Requires a new Liquid migration plus wrapper-specific dependency semantics | Do not adopt for 0.5 |
|
|
59
|
+
| Small Forge AST grammar | Contract is designed exactly for parse/analyze/render and the allowed syntax is closed | No ambient capabilities or loaders by construction; all values and filters are explicit | Breaking but small, predictable, and mechanically migrates common interpolation | Recommended candidate |
|
|
60
|
+
|
|
61
|
+
Nunjucks documents both its lack of sandboxing and its extensible loaders,
|
|
62
|
+
includes, custom tags, and asynchronous behavior. [Nunjucks API](https://mozilla.github.io/nunjucks/api.html)
|
|
63
|
+
LiquidJS documents parsed-template reuse and static analysis, but is a broader
|
|
64
|
+
Liquid language with tags and plugins rather than the deliberately closed v2
|
|
65
|
+
language. [LiquidJS static analysis](https://liquidjs.com/tutorials/static-analysis.html)
|
|
66
|
+
|
|
67
|
+
## Recommended decision candidate: `forge-v1`
|
|
68
|
+
|
|
69
|
+
Adopt a small parsed Forge template grammar. It resembles Jinja only at the
|
|
70
|
+
delimiter level; it must not claim Jinja compatibility.
|
|
71
|
+
|
|
72
|
+
### Closed grammar
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
text := any text outside delimiters
|
|
76
|
+
output := "{{" path filters? "}}"
|
|
77
|
+
filters := ("|" filterName)*
|
|
78
|
+
if-block := "{% if" predicate "%}" template
|
|
79
|
+
("{% else %}" template)? "{% endif %}"
|
|
80
|
+
path := identifier ("." identifier)*
|
|
81
|
+
predicate := path | path "==" json-string | path "!=" json-string
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The only initially proposed paths are `parameters.*` and documented
|
|
85
|
+
`runtime.*` fields. No bracket access, method invocation, object construction,
|
|
86
|
+
numeric arithmetic, loops, user-defined functions, imports, includes, extends,
|
|
87
|
+
macro definitions, or arbitrary expressions are in the grammar.
|
|
88
|
+
|
|
89
|
+
The initially proposed filters are `trim`, `upper`, `lower`, `json`, and `xml`.
|
|
90
|
+
They are pure, unary, versioned built-ins; unknown filters are errors. Tool and
|
|
91
|
+
slot conditions, if retained, must be represented as documented boolean values
|
|
92
|
+
in the environment rather than callable helpers. The exact v2 environment field
|
|
93
|
+
names remain part of the architecture decision.
|
|
94
|
+
|
|
95
|
+
### Engine contract
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
interface TemplateEngine {
|
|
99
|
+
readonly id: "forge-v1";
|
|
100
|
+
readonly version: 1;
|
|
101
|
+
parse(source: string): TemplateParseResult;
|
|
102
|
+
analyze(ast: TemplateAst): readonly TemplateDependency[];
|
|
103
|
+
render(ast: TemplateAst, environment: PromptEnvironment): TemplateRenderResult;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`PromptEnvironment` is a frozen, JSON-compatible snapshot. It must carry an
|
|
108
|
+
explicit timestamp and timezone/formatting policy, cwd, model identity, selected
|
|
109
|
+
tool facts, latest-user-message data, static parameters, and the Pi-derived
|
|
110
|
+
inputs required by slots as separate structured values. The compiler—not the
|
|
111
|
+
engine—owns history placement, structured slots, tool/skill policy, base-system
|
|
112
|
+
prompt handling, message assembly, and regex stages.
|
|
113
|
+
|
|
114
|
+
The render receipt must identify engine ID/version, template dependencies,
|
|
115
|
+
environment/provenance fingerprint, diagnostics, and output size. Dependencies
|
|
116
|
+
are authoritative for preview and subagent preparation; no consumer may
|
|
117
|
+
re-parse syntax independently.
|
|
118
|
+
|
|
119
|
+
### Extension boundary implication
|
|
120
|
+
|
|
121
|
+
The current `registerMacro()` API cannot cross this boundary unchanged because
|
|
122
|
+
it receives live runtime objects and can mutate or observe ambient state. The
|
|
123
|
+
template decision does not yet authorize a replacement API. If custom template
|
|
124
|
+
values, filters, or slots remain in 0.5, a separate accepted port must give them
|
|
125
|
+
only frozen input, declared dependency/capability metadata, bounded output, and
|
|
126
|
+
a pure-rendering contract. Trusted extension code is not a security boundary;
|
|
127
|
+
the core engine nevertheless must remain deterministic when no such extension
|
|
128
|
+
port participates.
|
|
129
|
+
|
|
130
|
+
## Migration disposition
|
|
131
|
+
|
|
132
|
+
| 0.4 construct | Candidate v2 migration | Result when not mechanical |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `{{name}}` for a known static value | `{{ parameters.name }}` | Warn when name could be a custom macro or ambiguous |
|
|
135
|
+
| `{{lastUserMessage}}`, date/time, cwd, model, selected tools | Corresponding documented `runtime.*` path | Mechanical only after field names are accepted |
|
|
136
|
+
| Nested value filters | Equivalent output plus pipeline where semantics match | Diagnose when nested arguments or behavior differ |
|
|
137
|
+
| `ifvar` / `ifeq` | Parsed `if` predicate where semantics match | Diagnose `iftools`/`ifslot` until boolean environment fields are accepted |
|
|
138
|
+
| Custom macros and slots | New port only after its decision | Diagnose; no compatibility execution shim |
|
|
139
|
+
| Set/get/clear variable macros and `variables` slot | None | Error-level migration diagnostic; removed behavior |
|
|
140
|
+
| Unknown macros / unresolved-policy behavior | None | Error-level diagnostic in v2; no keep/warn rendering policy |
|
|
141
|
+
|
|
142
|
+
The migration tool must preserve the original source, produce a field/item-level
|
|
143
|
+
report, and refuse a partly transformed file unless the user explicitly accepts
|
|
144
|
+
diagnostics. It must not rewrite SillyTavern inputs in 0.5.
|
|
145
|
+
|
|
146
|
+
## Required acceptance and implementation evidence
|
|
147
|
+
|
|
148
|
+
Before Phase 3 implementation, accept the grammar, exact environment schema,
|
|
149
|
+
filter/condition set, undefined/error semantics, output limits, engine ID in
|
|
150
|
+
stack schema v2, extension-port disposition, and migration behavior.
|
|
151
|
+
|
|
152
|
+
Implementation then needs characterization and conformance coverage for parser
|
|
153
|
+
errors, source spans, strict undefined values, filters, nested/else conditionals,
|
|
154
|
+
whitespace, output limits, deterministic repeated render, dependency receipts,
|
|
155
|
+
preview/runtime identity, and migration diagnostics for every removed mutable or
|
|
156
|
+
custom-macro construct.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Context Diff — design plan (post-0.5.0)
|
|
2
|
+
|
|
3
|
+
Status: planned. Target release: 0.5.1 (first feature release after 0.5.0).
|
|
4
|
+
Owner of truth: this document; discussion record lives in the 0.5.x review thread.
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Per-turn observability for prompt changes so users can optimize KV-cache reuse:
|
|
9
|
+
|
|
10
|
+
- Mark which blocks of the prompt changed after each turn.
|
|
11
|
+
- Show how many tokens were added/removed/modified (delta vs the previous turn).
|
|
12
|
+
- Mark where the KV-cache prefix survives ("cache boundary").
|
|
13
|
+
|
|
14
|
+
Secondary goal: merge with live preview — while editing a stack, debounce-compile and diff against the previous compile, so edits show their prompt/token impact immediately.
|
|
15
|
+
|
|
16
|
+
## Existing building blocks
|
|
17
|
+
|
|
18
|
+
- `src/payload-capture.ts` — captures the real provider request payload (secret-redacted), with `approxTokens` (chars/4) estimation. `SAFE_TOKEN_METADATA_KEYS` already whitelists `cached_tokens` etc., so real cache-hit numbers can be surfaced if response usage ever becomes available.
|
|
19
|
+
- `src/preview.ts` — edit-time compile output split into sections (system + per-message), each with chars/approxTokens.
|
|
20
|
+
- Legacy editor already polls payload state every 2s.
|
|
21
|
+
|
|
22
|
+
## Two data sources
|
|
23
|
+
|
|
24
|
+
| Scenario | Source | Question answered |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| Edit time (live preview merge point) | debounced compile vs previous compile | "what does this edit change, how many tokens" |
|
|
27
|
+
| Run time (KV-cache truth) | diff of consecutive real payloads | "where did the cache break, how many extra tokens this turn" |
|
|
28
|
+
|
|
29
|
+
## Core engine: `src/context-diff.ts` (host-neutral pure functions)
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
TurnSnapshot { turnId, capturedAt, stackId, blocks: Block[] }
|
|
33
|
+
Block { key, role, text, chars, approxTokens, hash }
|
|
34
|
+
TurnDiff { blocks: DiffBlock[], prefixTokens, prefixRatio, deltaTokens, summary }
|
|
35
|
+
DiffBlock { status: same|added|removed|modified, before?, after?, tokenDelta }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Cache-boundary algorithm: KV-cache hits depend on the longest common prefix of the serialized request. Walk the block arrays in order while hashes match; at the first mismatch, trim a char-level common prefix inside that block and convert to tokens. Render a boundary marker: "cache valid up to ~18,204 tokens (63% of prompt)". No Myers diff needed — prefix + block classification suffices.
|
|
39
|
+
|
|
40
|
+
Honesty note: tokens are chars/4 estimates. Relative deltas are accurate; absolute boundary claims must be labeled "approx" in UI and in promo material.
|
|
41
|
+
|
|
42
|
+
## UI
|
|
43
|
+
|
|
44
|
+
Promote the Preview modal into a dockable right-side panel with two tabs:
|
|
45
|
+
|
|
46
|
+
- **Compiled** — current preview content, auto-refresh with 500ms debounce while editing (this is the live preview).
|
|
47
|
+
- **Diff** — top summary strip (`Turn N · +412 tokens vs previous · cache boundary ~63% · 2 blocks changed`), block list with green/red/yellow gutters and per-block token chips, scissor-line boundary marker.
|
|
48
|
+
|
|
49
|
+
Run-time mode: payload poll captures a new payload → store in rolling history (last 20 turns) → auto-compute diff.
|
|
50
|
+
Edit mode: diff current edited compile vs the active on-disk version.
|
|
51
|
+
|
|
52
|
+
Implementation constraint: write the panel as a self-contained Vue component bridged in via the vue-host mechanism. Do NOT add more imperative code to `legacy-editor.ts`. Do NOT refactor the legacy editor in the same lane.
|
|
53
|
+
|
|
54
|
+
## Phases / estimate
|
|
55
|
+
|
|
56
|
+
| Phase | Content | Effort |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| 0 | Design freeze + golden fixtures (turn payload sets) | 0.5d |
|
|
59
|
+
| 1 | `context-diff.ts` engine + unit tests (prefix/add/remove/modify/token rollups) | 1d |
|
|
60
|
+
| 2 | Server endpoint + rolling snapshot state on the web host | 0.5d |
|
|
61
|
+
| 3 | Web UI: preview dock + Diff view (self-contained Vue, bridged) | 1.5d |
|
|
62
|
+
| 4 | Browser tests + docs + changelog | 0.5–1d |
|
|
63
|
+
|
|
64
|
+
Total ~4–5 working days; ~1 calendar week with review. Descope option (~3d): run-time diff only, live preview reduced to plain auto-refresh without edit-time diffing.
|
|
65
|
+
|
|
66
|
+
## Release narrative
|
|
67
|
+
|
|
68
|
+
Do not fold into 0.5.0 — 0.5.0 ships as the architecture-split release; context diff headlines 0.5.1 as "observability". The promo video leads with this feature (money shot: edit one system-prompt line, watch the cache-boundary marker jump to the top).
|
|
69
|
+
|
|
70
|
+
## Promo video pipeline (reference: AIGC/VIDEO_PRODUCTION ep02)
|
|
71
|
+
|
|
72
|
+
Reuse the ep02 pipeline: `PLAN.md` → script draft → `narration.json` (production source of truth) → roughcut → review. Terminology follows the ep02 rule: say it in plain words first, name the formal term once ("KV cache" on first mention, then "prefix cache / cache reuse region").
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Architecture decision: title
|
|
2
|
+
|
|
3
|
+
[Design index](README.md)
|
|
4
|
+
|
|
5
|
+
Status: proposed
|
|
6
|
+
|
|
7
|
+
Date: YYYY-MM-DD
|
|
8
|
+
|
|
9
|
+
Owners: maintainer names or roles
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
Describe the concrete problem, current constraints, and evidence that a decision is needed.
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
State the chosen behavior and ownership boundary precisely. Include a small interface or diagram when it makes the boundary easier to verify.
|
|
18
|
+
|
|
19
|
+
## Consequences
|
|
20
|
+
|
|
21
|
+
Describe what becomes easier, what becomes harder or impossible, and which compatibility or operational costs are accepted.
|
|
22
|
+
|
|
23
|
+
## Migration
|
|
24
|
+
|
|
25
|
+
List the implementation order, compatibility period if any, user migration, and removal condition for temporary shims.
|
|
26
|
+
|
|
27
|
+
## Alternatives considered
|
|
28
|
+
|
|
29
|
+
Record the serious alternatives and why they were rejected. Do not use this section to restate obviously inferior options.
|
|
30
|
+
|
|
31
|
+
## Verification
|
|
32
|
+
|
|
33
|
+
Define the tests, dependency checks, documentation, and release evidence that prove the decision was implemented.
|
|
@@ -10,7 +10,7 @@ This file was the forward-looking product roadmap during 0.4 development. Comple
|
|
|
10
10
|
- [Feature inventory](../reference/features.md): implemented profile, prompt-stack, web-editor, payload, extension, packaging, and experimental subagent behavior.
|
|
11
11
|
- [Changelog](../../CHANGELOG.md): release and unreleased change history.
|
|
12
12
|
- [Subagent interface design](subagents/interface-design.md): accepted request/response architecture, context model, responsibility boundaries, and implementation history.
|
|
13
|
-
-
|
|
13
|
+
- Subagent adapter contract: the 0.4 exported contract documented the execution surface that moved to `@zihanw/pi-forge-subagents` in 0.5; see the [subagent host port contract](../reference/subagent-host-port.md) for the current boundary.
|
|
14
14
|
- [SDK spike findings](subagents/sdk-spike-findings.md): historical real Pi SDK findings for model/auth resolution, exact prompt preparation, dynamic tools, media, timeout, and cleanup.
|
|
15
15
|
- [Subagent design review](subagents/design-review.md): issues that drove resolution, preflight, enforcement, task-preservation, fingerprint, and response revisions.
|
|
16
16
|
- [Public API policy](../reference/public-api.md): stable, experimental, and internal compatibility surfaces.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Subagent request/response design
|
|
2
2
|
|
|
3
|
-
Status: historical design and implementation record for the completed 0.4 path. Execution ownership (backend registry, preflight binding, plan sealing, conversation/execution fingerprints, lifecycle, and the fresh-process `pi-subprocess-readonly`/`pi-rpc-readonly` backends) lives in `@zihanw/pi-subagent-runtime`; the former in-package registry and `pi-sdk-isolated` compatibility backend were removed in that migration. The broader Pi SDK spike is recorded in the [SDK spike findings](sdk-spike-findings.md) (harness since removed), and the
|
|
3
|
+
Status: historical design and implementation record for the completed 0.4 path. Execution ownership (backend registry, preflight binding, plan sealing, conversation/execution fingerprints, lifecycle, and the fresh-process `pi-subprocess-readonly`/`pi-rpc-readonly` backends) lives in `@zihanw/pi-subagent-runtime`; the former in-package registry and `pi-sdk-isolated` compatibility backend were removed in that migration. The broader Pi SDK spike is recorded in the [SDK spike findings](sdk-spike-findings.md) (harness since removed), and the 0.5 boundary is documented in the [subagent host port contract](../../reference/subagent-host-port.md).
|
|
4
4
|
|
|
5
5
|
## Goals
|
|
6
6
|
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Architecture and development rules
|
|
2
|
+
|
|
3
|
+
[Documentation](../README.md) · [0.5 architecture plan](../design/architecture-0.5.md)
|
|
4
|
+
|
|
5
|
+
These rules keep implementation throughput from outrunning architectural understanding. They apply to humans and coding agents. The intent is not to slow local implementation; it is to make boundary changes scarce, explicit, and reviewable.
|
|
6
|
+
|
|
7
|
+
## Decision authority
|
|
8
|
+
|
|
9
|
+
Implementation may move quickly inside an accepted boundary. A change to a boundary, persistent model, public contract, or product concept requires an explicit design decision before implementation.
|
|
10
|
+
|
|
11
|
+
Agents may draft decisions, diagrams, interfaces, migration plans, and implementation slices. A human maintainer accepts the decision and its tradeoffs.
|
|
12
|
+
|
|
13
|
+
## Development mode for 0.5
|
|
14
|
+
|
|
15
|
+
Until the 0.5 release gates are complete:
|
|
16
|
+
|
|
17
|
+
- Feature development is frozen unless the feature is explicitly added to the 0.5 plan.
|
|
18
|
+
- Only one boundary-changing initiative should be active at a time.
|
|
19
|
+
- Simplification and removal are preferred over compatibility layers without a demonstrated consumer.
|
|
20
|
+
- A completed slice must leave the repository in a coherent, documented, verified state; partial architecture migrations must not silently become permanent.
|
|
21
|
+
|
|
22
|
+
## Required dependency direction
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
flowchart LR
|
|
26
|
+
Adapters["Adapters<br/>Pi lifecycle · commands · HTTP · browser"]
|
|
27
|
+
Application["Application<br/>ForgeWorkspace · stack/profile services"]
|
|
28
|
+
Domain["Domain/core<br/>schemas · catalogs · compiler · templates"]
|
|
29
|
+
Ports["Ports<br/>repositories · runtime controller · host capabilities"]
|
|
30
|
+
Infrastructure["Infrastructure<br/>filesystem · Pi SDK · process registry"]
|
|
31
|
+
|
|
32
|
+
Adapters --> Application
|
|
33
|
+
Application --> Domain
|
|
34
|
+
Application --> Ports
|
|
35
|
+
Infrastructure --> Ports
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Infrastructure implements inward-facing ports. Domain/core code must not import adapters or infrastructure implementations.
|
|
39
|
+
|
|
40
|
+
Until the target directory/package structure exists, apply the rule to logical ownership rather than relying on current file locations.
|
|
41
|
+
|
|
42
|
+
## Component rules
|
|
43
|
+
|
|
44
|
+
### Domain and compiler
|
|
45
|
+
|
|
46
|
+
- Domain types contain no command, HTTP, browser, TUI, or filesystem behavior.
|
|
47
|
+
- Prompt compilation consumes a normalized, immutable prompt environment rather than a live Pi context.
|
|
48
|
+
- Compilation returns prompt output, diagnostics, dependencies, and any explicit state transition. Renderers must not silently mutate shared state.
|
|
49
|
+
- Template dependency analysis is part of the template-engine contract; subagents and previews must not reverse-engineer template syntax independently.
|
|
50
|
+
- Tool policy remains stack-owned. Profiles may reference a stack but must not duplicate the policy.
|
|
51
|
+
|
|
52
|
+
### Application services
|
|
53
|
+
|
|
54
|
+
- `ForgeWorkspace` owns a coherent workspace snapshot and coordinates resource reloads.
|
|
55
|
+
- `PromptStackService` owns stack resolution, mutation, activation, validation, and preview/compile entry points.
|
|
56
|
+
- `AgentProfileService` owns profile resolution, mutation, preflight, transactional application, provenance, and drift.
|
|
57
|
+
- Services expose typed results. Adapters translate those results into command messages, HTTP statuses, and UI view models.
|
|
58
|
+
|
|
59
|
+
### Persistence
|
|
60
|
+
|
|
61
|
+
- All profile and stack reads/writes/deletes go through repositories.
|
|
62
|
+
- Repositories use codecs as the single source of parsing, normalization, validation, and serialization.
|
|
63
|
+
- Mutations validate scope and containment. No adapter may call `writeFileSync` or `unlinkSync` for a domain resource.
|
|
64
|
+
- **Lean 0.5.0 interim:** repositories and codecs are introduced in minimal form. Expected-fingerprint writes, fingerprinting in codecs, and guaranteed atomic file replacement are 0.5.x work. Current replacement semantics remain characterized by tests until then.
|
|
65
|
+
|
|
66
|
+
### State
|
|
67
|
+
|
|
68
|
+
- Every mutable value has one named owner.
|
|
69
|
+
- Debug payload capture, browser presentation state, prompt resource state, and session provenance are separate state slices.
|
|
70
|
+
- Reload produces a complete snapshot before publishing it. Consumers must not observe a half-reloaded stack/profile graph.
|
|
71
|
+
- New session-persisted state requires a version, restoration semantics, migration behavior, and an architecture decision.
|
|
72
|
+
|
|
73
|
+
### Adapters and optional packages
|
|
74
|
+
|
|
75
|
+
- Commands and HTTP handlers parse input, invoke an application service, and render a result; they do not implement domain workflows.
|
|
76
|
+
- Browser view models must not leak into core runtime state.
|
|
77
|
+
- Optional extensions use versioned host ports and fail clearly when the required host version is unavailable.
|
|
78
|
+
- `pi-forge-subagents` must not load an independent conflicting copy of the active Forge workspace or reach into pi-forge internals.
|
|
79
|
+
|
|
80
|
+
### Public APIs
|
|
81
|
+
|
|
82
|
+
- Public API is an allowlist of package entry points, not a side effect of file placement.
|
|
83
|
+
- The 0.5 release removes the broad `src/*` compatibility surface.
|
|
84
|
+
- A public type should describe a stable domain or port, not an internal runtime object.
|
|
85
|
+
- Breaking changes belong in the changelog and the 0.5 migration guide.
|
|
86
|
+
|
|
87
|
+
## Change classification
|
|
88
|
+
|
|
89
|
+
### Local change
|
|
90
|
+
|
|
91
|
+
A local change stays within one accepted component and preserves schemas, state ownership, dependency direction, and public behavior. It needs focused tests and ordinary review.
|
|
92
|
+
|
|
93
|
+
Examples include fixing a renderer, improving a view mapper, or extracting a private helper within one service.
|
|
94
|
+
|
|
95
|
+
### Boundary-affecting change
|
|
96
|
+
|
|
97
|
+
A boundary-affecting change moves responsibility, adds a dependency across components, changes an application port, or introduces a new state owner. It requires an accepted architecture decision or an amendment to the 0.5 plan.
|
|
98
|
+
|
|
99
|
+
### Product-affecting change
|
|
100
|
+
|
|
101
|
+
A product-affecting change adds/removes a feature, changes a schema, alters persistence or trust semantics, or changes a public API/package. It requires an accepted decision, migration notes, documentation updates, and explicit human review.
|
|
102
|
+
|
|
103
|
+
## Architecture-decision triggers
|
|
104
|
+
|
|
105
|
+
An architecture decision is required when changing any of the following:
|
|
106
|
+
|
|
107
|
+
- package or extension boundaries;
|
|
108
|
+
- JSON schemas or persisted session entries;
|
|
109
|
+
- public exports or compatibility promises;
|
|
110
|
+
- `ForgeWorkspace` or another state owner;
|
|
111
|
+
- compiler/template semantics;
|
|
112
|
+
- filesystem repository guarantees;
|
|
113
|
+
- trust, approval, tool-policy, or provider-egress boundaries;
|
|
114
|
+
- cross-extension discovery;
|
|
115
|
+
- removal or addition of a product-level feature.
|
|
116
|
+
|
|
117
|
+
Use the [architecture decision template](../design/decision-template.md). Small decisions can amend the active 0.5 plan instead of creating a separate document if the alternatives and consequences remain clear.
|
|
118
|
+
|
|
119
|
+
## Pull-request requirements
|
|
120
|
+
|
|
121
|
+
During lean 0.5.0, every pull request states summary, breaking impact, and verification, as in the repository template. Boundary- or product-affecting changes must link to the accepted decision in the [lean 0.5 plan](../design/architecture-0.5.md); a separate decision document is not required for decisions already accepted there.
|
|
122
|
+
|
|
123
|
+
For full-target 0.5.x work, pull requests additionally state change classification, affected components, dependency-direction/state/schema/public-API impact, and the linked decision.
|
|
124
|
+
|
|
125
|
+
## Definition of done
|
|
126
|
+
|
|
127
|
+
A slice is complete when:
|
|
128
|
+
|
|
129
|
+
1. Ownership and dependency direction match the accepted architecture.
|
|
130
|
+
2. Behavior is covered at the narrowest useful level; cross-adapter behavior has integration coverage.
|
|
131
|
+
3. No domain persistence remains in command, HTTP, or browser-host adapters.
|
|
132
|
+
4. Public and persisted changes include migration notes.
|
|
133
|
+
5. Current and target documentation reflect any moved boundary.
|
|
134
|
+
6. Generated artifacts are synchronized.
|
|
135
|
+
7. `npm run verify` passes for release-sized or cross-cutting work.
|
|
136
|
+
|
|
137
|
+
## Review stop conditions
|
|
138
|
+
|
|
139
|
+
Stop and request architectural review when an implementation needs to:
|
|
140
|
+
|
|
141
|
+
- import an adapter from domain/application code;
|
|
142
|
+
- access `PiForgeRuntimeState` from a new component;
|
|
143
|
+
- add mutable template variables or render-time side effects;
|
|
144
|
+
- write a resource outside a repository;
|
|
145
|
+
- add a wildcard export;
|
|
146
|
+
- duplicate profile/stack loading in another extension;
|
|
147
|
+
- retain a compatibility layer with no named consumer or removal date;
|
|
148
|
+
- introduce a second boundary-changing initiative before the current one is complete.
|
|
@@ -4,6 +4,37 @@
|
|
|
4
4
|
|
|
5
5
|
This file contains forward-looking product work only. Completed capability belongs in the [feature inventory](../reference/features.md), release history in the root [changelog](../../CHANGELOG.md), and completed investigation in the [design archive](../design/README.md).
|
|
6
6
|
|
|
7
|
+
## 0.5.0 breaking cleanup (lean)
|
|
8
|
+
|
|
9
|
+
0.5.0 is a deliberately breaking cleanup release plus the minimum foundation for 0.5.x. Net-new feature work is frozen.
|
|
10
|
+
|
|
11
|
+
The authoritative scope, accepted decisions, implementation lanes, and release gates are in the [lean 0.5 architecture plan](../design/architecture-0.5.md). The original six-phase architecture target remains the long-term goal and is archived in the [full proposal](../design/archive/0.5-full-proposal/README.md).
|
|
12
|
+
|
|
13
|
+
Implementation order:
|
|
14
|
+
|
|
15
|
+
0. Documentation convergence: archive the full proposal and make the lean plan active.
|
|
16
|
+
1a. Removals only: remove SillyTavern, mutable variable state/macros/slot, variable session entries, and regex `display`/`both`.
|
|
17
|
+
1b. Compiler, schema v2, and extension contract: implement `forge-v1`, frozen `PromptEnvironment`, immutable `parameters`, and the redesigned trusted extension port; retain `finalize` under lifecycle-adapter ownership.
|
|
18
|
+
1c. Migration and documentation: v1-to-v2 utility, example migration, and English/Chinese breaking notes.
|
|
19
|
+
1d. Compiler/extension conformance: pure slot contract symmetry, slot dependency resolution, shared dependency analysis/compilation context, lazy extension evaluation, nested conditionals, parser fixes, and focused conformance tests.
|
|
20
|
+
2a. Minimal repositories and codecs: make repositories/codecs the only stack/profile read/write path; defer fingerprint and atomic writes.
|
|
21
|
+
2b. ForgeWorkspace and host port v1: minimal snapshot owner plus `/subagent` discovery, profile listing/snapshot, and prepare with mandatory lifecycle semantics.
|
|
22
|
+
3. Subagent extraction: move subagent code into `pi-forge-subagents`; remove the main-package hard dependency and delegation UI; optional package owns dedicated `subagents.json` files.
|
|
23
|
+
3.5. Host-neutrality hardening: host-neutral prompt compiler, `ForgeWorkspace` as the single resource-state owner, optional-package docs/config alignment, and portable packed smoke.
|
|
24
|
+
4. Public surface and release: (4a) Forge-native host contract — main drops the runtime dependency and the synthetic preparation model, and the 0.4 execution contract moves to the optional package; (4b) public-surface cut — root default, root named extension API, and `/subagent` only, `src/*` aliases removed, package checks flipped to the allowlist; (4c) optional-package packed smoke over a loopback transport; (4d) migration notes and English/Chinese docs; (4e) packed-install verification and the 0.5.0 release.
|
|
25
|
+
|
|
26
|
+
Only one lane is active at a time. Sandbox, staged writes, new prompt features, richer imports, and the remaining full-plan architecture work remain deferred until after this sequence.
|
|
27
|
+
|
|
28
|
+
## 0.5.x continuation
|
|
29
|
+
|
|
30
|
+
After 0.5.0, continue toward the archived full target in small increments:
|
|
31
|
+
|
|
32
|
+
- expected-fingerprint writes, codec fingerprinting, and atomic persistence;
|
|
33
|
+
- full `PromptStackService` / `AgentProfileService` / `ForgeWorkspace` ownership;
|
|
34
|
+
- physical `pi-forge-core` boundaries and dependency-direction checking;
|
|
35
|
+
- complete host RPC catalogue, progress events, and optional subagent UI;
|
|
36
|
+
- public-surface classification and rolling Pi compatibility matrix.
|
|
37
|
+
|
|
7
38
|
## 0.4 baseline
|
|
8
39
|
|
|
9
40
|
The profile UI, foreground-delegation dogfooding, dependency compatibility work, and documentation reorganization are complete and merged to `main`. Runtime beta.2 is published, and the packed 0.4.0 extension passes the full verification surface against the documented Pi versions.
|
|
@@ -12,25 +43,26 @@ The 0.4.1 release adds scoped global profiles and prompt stacks with project-ove
|
|
|
12
43
|
|
|
13
44
|
Stable 0.4 does not imply that the subagent adapter or runtime has become stable. Prompt stacks and ordinary profile use remain independent of delegation.
|
|
14
45
|
|
|
15
|
-
##
|
|
46
|
+
## Deferred candidates
|
|
16
47
|
|
|
17
48
|
### Sandbox and staged writes
|
|
18
49
|
|
|
19
50
|
Evaluate an optional backend that can honestly enforce roots, process behavior, symlink containment, and requested network policy. Keep shared-user as an explicit compatibility boundary. Design writes as a separately approved staged patch/change set; do not add write/edit/shell tools directly to the shared-user child.
|
|
20
51
|
|
|
21
|
-
###
|
|
52
|
+
### History and prompt diagnostics
|
|
22
53
|
|
|
23
|
-
|
|
54
|
+
Candidate history controls need concrete use cases and dangling tool-pair tests. Provider-payload rewriting and display-only streaming regex remain deferred until a stable, previewable lifecycle hook exists. SillyTavern fidelity is no longer a core roadmap goal; 0.5 removes it.
|
|
24
55
|
|
|
25
56
|
## Product guardrails
|
|
26
57
|
|
|
27
58
|
- Prompt-stack JSON stays declarative; executable customization stays in trusted extensions/packages.
|
|
59
|
+
- Prompt rendering moves toward immutable inputs and explicit outputs; do not add mutable variable behavior during 0.5.
|
|
28
60
|
- Profiles remain one-shot presets, not continuous runtime owners.
|
|
29
61
|
- Tool and skill policy stays in prompt stacks, not profiles.
|
|
30
62
|
- Skill filtering is model-visible prompt filtering, not an invocation or security boundary.
|
|
31
|
-
- Delegation remains opt-in, foreground, clean-context, and fail-closed on missing capabilities.
|
|
63
|
+
- Delegation remains opt-in, foreground, clean-context, and fail-closed on missing capabilities, and lives in the optional package.
|
|
32
64
|
- Do not report shared-user read-only policy as an OS sandbox.
|
|
33
|
-
- New editor workflows
|
|
65
|
+
- New editor product workflows are frozen; migration changes retain real-browser coverage.
|
|
34
66
|
- Run the full verification and package checks before release.
|
|
35
67
|
|
|
36
68
|
The detailed completed 0.4 plan is retained in the [historical roadmap](../design/roadmap-0.4-archive.md).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[Documentation](../README.md) · [Roadmap](roadmap.md)
|
|
4
4
|
|
|
5
|
-
Status: accepted design; implementation complete for 0.4.1 (identity, catalogs, scoped stacks/profiles, persistence, auto-activation, delegation, zh-CN docs, and web-editor global create/fork/import with explicit scope).
|
|
5
|
+
Status: accepted design; implementation complete for 0.4.1 (identity, catalogs, scoped stacks/profiles, persistence, auto-activation, delegation, zh-CN docs, and web-editor global create/fork/import with explicit scope). Historical record: the delegation-policy references to `.pi/forge/config.json` `subagents.*` below are superseded in 0.5 — delegation configuration moved to the optional package's dedicated `subagents.json` files (see the [0.5 migration guide](../guides/migrating-to-0.5.md)).
|
|
6
6
|
|
|
7
7
|
## Confirmed design decisions
|
|
8
8
|
|
|
@@ -14,6 +14,8 @@ pi
|
|
|
14
14
|
|
|
15
15
|
Trust the project in Pi and use `/reload` when needed.
|
|
16
16
|
|
|
17
|
+
Before making structural changes, read the [architecture and development rules](architecture-rules.md) and the active [0.5 architecture plan](../design/architecture-0.5.md). Boundary, schema, persistence, public API, and product changes require an accepted architecture decision before implementation.
|
|
18
|
+
|
|
17
19
|
The npm package loads compiled `dist/index.js` and intentionally omits physical `src/` files. Clone or fork the repository to inspect or modify source; do not edit generated files in `node_modules`.
|
|
18
20
|
|
|
19
21
|
## Load the extension
|
|
@@ -67,9 +69,9 @@ Document the tested range separately from peer constraints. Pi-coupled experimen
|
|
|
67
69
|
|
|
68
70
|
## Package boundaries
|
|
69
71
|
|
|
70
|
-
- `@zihanw/pi-forge` is the Pi extension and stable macro/slot registration surface.
|
|
71
|
-
- `@zihanw/pi-forge/subagent` is the
|
|
72
|
-
- `@zihanw/pi-
|
|
73
|
-
-
|
|
72
|
+
- `@zihanw/pi-forge` is the Pi extension (default export) and the stable macro/slot registration surface; no other root exports or `src/*` aliases exist.
|
|
73
|
+
- `@zihanw/pi-forge/subagent` is the experimental versioned host-port entry point (wire DTOs, validators, transport, client/host lifecycle, canonical fingerprints).
|
|
74
|
+
- `@zihanw/pi-forge-subagents` is the optional package owning subagent execution, configuration, and the 0.4 execution contract.
|
|
75
|
+
- `@zihanw/pi-subagent-runtime` owns execution lifecycle and fresh-process backends (a dependency of the optional package, not of the main package).
|
|
74
76
|
|
|
75
77
|
See the [public API policy](../reference/public-api.md).
|