@zihanw/pi-forge 0.4.1 → 0.5.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 (372) hide show
  1. package/CHANGELOG.md +79 -1
  2. package/README.md +12 -11
  3. package/README.zh-CN.md +3 -5
  4. package/SUBAGENT_ADAPTER_CONTRACT.md +3 -1
  5. package/dist/agent-profile.d.ts +18 -62
  6. package/dist/agent-profile.d.ts.map +1 -1
  7. package/dist/agent-profile.js +27 -249
  8. package/dist/agent-profile.js.map +1 -1
  9. package/dist/codecs/agent-profile.d.ts +53 -0
  10. package/dist/codecs/agent-profile.d.ts.map +1 -0
  11. package/dist/codecs/agent-profile.js +176 -0
  12. package/dist/codecs/agent-profile.js.map +1 -0
  13. package/dist/codecs/index.d.ts +5 -0
  14. package/dist/codecs/index.d.ts.map +1 -0
  15. package/dist/codecs/index.js +3 -0
  16. package/dist/codecs/index.js.map +1 -0
  17. package/dist/codecs/prompt-stack.d.ts +18 -0
  18. package/dist/codecs/prompt-stack.d.ts.map +1 -0
  19. package/dist/codecs/prompt-stack.js +479 -0
  20. package/dist/codecs/prompt-stack.js.map +1 -0
  21. package/dist/compile-cycle.d.ts +18 -0
  22. package/dist/compile-cycle.d.ts.map +1 -0
  23. package/dist/compile-cycle.js +13 -0
  24. package/dist/compile-cycle.js.map +1 -0
  25. package/dist/compiler.d.ts +10 -4
  26. package/dist/compiler.d.ts.map +1 -1
  27. package/dist/compiler.js +53 -19
  28. package/dist/compiler.js.map +1 -1
  29. package/dist/context-diff-history.d.ts +61 -0
  30. package/dist/context-diff-history.d.ts.map +1 -0
  31. package/dist/context-diff-history.js +84 -0
  32. package/dist/context-diff-history.js.map +1 -0
  33. package/dist/context-diff-snapshot.d.ts +19 -0
  34. package/dist/context-diff-snapshot.d.ts.map +1 -0
  35. package/dist/context-diff-snapshot.js +146 -0
  36. package/dist/context-diff-snapshot.js.map +1 -0
  37. package/dist/context-diff.d.ts +70 -0
  38. package/dist/context-diff.d.ts.map +1 -0
  39. package/dist/context-diff.js +259 -0
  40. package/dist/context-diff.js.map +1 -0
  41. package/dist/extension-registry.d.ts.map +1 -1
  42. package/dist/extension-registry.js +5 -2
  43. package/dist/extension-registry.js.map +1 -1
  44. package/dist/forge-config.d.ts +0 -105
  45. package/dist/forge-config.d.ts.map +1 -1
  46. package/dist/forge-config.js +1 -313
  47. package/dist/forge-config.js.map +1 -1
  48. package/dist/forge-v1/analyzer.d.ts +3 -0
  49. package/dist/forge-v1/analyzer.d.ts.map +1 -0
  50. package/dist/forge-v1/analyzer.js +50 -0
  51. package/dist/forge-v1/analyzer.js.map +1 -0
  52. package/dist/forge-v1/index.d.ts +6 -0
  53. package/dist/forge-v1/index.d.ts.map +1 -0
  54. package/dist/forge-v1/index.js +13 -0
  55. package/dist/forge-v1/index.js.map +1 -0
  56. package/dist/forge-v1/parser.d.ts +3 -0
  57. package/dist/forge-v1/parser.d.ts.map +1 -0
  58. package/dist/forge-v1/parser.js +186 -0
  59. package/dist/forge-v1/parser.js.map +1 -0
  60. package/dist/forge-v1/renderer.d.ts +9 -0
  61. package/dist/forge-v1/renderer.d.ts.map +1 -0
  62. package/dist/forge-v1/renderer.js +181 -0
  63. package/dist/forge-v1/renderer.js.map +1 -0
  64. package/dist/forge-v1/types.d.ts +87 -0
  65. package/dist/forge-v1/types.d.ts.map +1 -0
  66. package/dist/forge-v1/types.js +4 -0
  67. package/dist/forge-v1/types.js.map +1 -0
  68. package/dist/index.d.ts +12 -12
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +54 -83
  71. package/dist/index.js.map +1 -1
  72. package/dist/lifecycle.d.ts +8 -5
  73. package/dist/lifecycle.d.ts.map +1 -1
  74. package/dist/lifecycle.js +45 -112
  75. package/dist/lifecycle.js.map +1 -1
  76. package/dist/loader.d.ts +5 -8
  77. package/dist/loader.d.ts.map +1 -1
  78. package/dist/loader.js +10 -467
  79. package/dist/loader.js.map +1 -1
  80. package/dist/macro-engine.d.ts +9 -14
  81. package/dist/macro-engine.d.ts.map +1 -1
  82. package/dist/macro-engine.js +5 -238
  83. package/dist/macro-engine.js.map +1 -1
  84. package/dist/payload-capture.d.ts +10 -0
  85. package/dist/payload-capture.d.ts.map +1 -1
  86. package/dist/payload-capture.js +39 -9
  87. package/dist/payload-capture.js.map +1 -1
  88. package/dist/payload-command.d.ts +8 -6
  89. package/dist/payload-command.d.ts.map +1 -1
  90. package/dist/payload-command.js +36 -6
  91. package/dist/payload-command.js.map +1 -1
  92. package/dist/payload-state.d.ts +19 -0
  93. package/dist/payload-state.d.ts.map +1 -0
  94. package/dist/payload-state.js +19 -0
  95. package/dist/payload-state.js.map +1 -0
  96. package/dist/preset-command.d.ts +4 -4
  97. package/dist/preset-command.d.ts.map +1 -1
  98. package/dist/preset-command.js +33 -104
  99. package/dist/preset-command.js.map +1 -1
  100. package/dist/preview.d.ts +4 -4
  101. package/dist/preview.d.ts.map +1 -1
  102. package/dist/preview.js +34 -11
  103. package/dist/preview.js.map +1 -1
  104. package/dist/profile-command.d.ts +2 -2
  105. package/dist/profile-command.d.ts.map +1 -1
  106. package/dist/profile-command.js +15 -14
  107. package/dist/profile-command.js.map +1 -1
  108. package/dist/profile-service.d.ts.map +1 -1
  109. package/dist/profile-service.js +23 -39
  110. package/dist/profile-service.js.map +1 -1
  111. package/dist/prompt-analysis.d.ts +24 -0
  112. package/dist/prompt-analysis.d.ts.map +1 -0
  113. package/dist/prompt-analysis.js +84 -0
  114. package/dist/prompt-analysis.js.map +1 -0
  115. package/dist/prompt-runtime.d.ts +19 -0
  116. package/dist/prompt-runtime.d.ts.map +1 -0
  117. package/dist/prompt-runtime.js +30 -0
  118. package/dist/prompt-runtime.js.map +1 -0
  119. package/dist/regex.js +6 -12
  120. package/dist/regex.js.map +1 -1
  121. package/dist/render-helpers.d.ts +2 -10
  122. package/dist/render-helpers.d.ts.map +1 -1
  123. package/dist/render-helpers.js +3 -53
  124. package/dist/render-helpers.js.map +1 -1
  125. package/dist/repositories/agent-profile.d.ts +36 -0
  126. package/dist/repositories/agent-profile.d.ts.map +1 -0
  127. package/dist/repositories/agent-profile.js +153 -0
  128. package/dist/repositories/agent-profile.js.map +1 -0
  129. package/dist/repositories/index.d.ts +3 -0
  130. package/dist/repositories/index.d.ts.map +1 -0
  131. package/dist/repositories/index.js +3 -0
  132. package/dist/repositories/index.js.map +1 -0
  133. package/dist/repositories/prompt-stack.d.ts +57 -0
  134. package/dist/repositories/prompt-stack.d.ts.map +1 -0
  135. package/dist/repositories/prompt-stack.js +175 -0
  136. package/dist/repositories/prompt-stack.js.map +1 -0
  137. package/dist/runtime/profile-runtime.d.ts +2 -2
  138. package/dist/runtime/profile-runtime.d.ts.map +1 -1
  139. package/dist/runtime/profile-runtime.js +13 -10
  140. package/dist/runtime/profile-runtime.js.map +1 -1
  141. package/dist/runtime/prompt-stack-runtime.d.ts +4 -3
  142. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
  143. package/dist/runtime/prompt-stack-runtime.js +42 -57
  144. package/dist/runtime/prompt-stack-runtime.js.map +1 -1
  145. package/dist/runtime/tool-policy-runtime.d.ts +2 -2
  146. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
  147. package/dist/runtime/tool-policy-runtime.js +16 -6
  148. package/dist/runtime/tool-policy-runtime.js.map +1 -1
  149. package/dist/runtime/web-editor-runtime.d.ts +2 -1
  150. package/dist/runtime/web-editor-runtime.d.ts.map +1 -1
  151. package/dist/runtime/web-editor-runtime.js +8 -3
  152. package/dist/runtime/web-editor-runtime.js.map +1 -1
  153. package/dist/session-adapter.d.ts +17 -0
  154. package/dist/session-adapter.d.ts.map +1 -0
  155. package/dist/session-adapter.js +57 -0
  156. package/dist/session-adapter.js.map +1 -0
  157. package/dist/slot-renderers.d.ts +16 -3
  158. package/dist/slot-renderers.d.ts.map +1 -1
  159. package/dist/slot-renderers.js +15 -63
  160. package/dist/slot-renderers.js.map +1 -1
  161. package/dist/stack-migration.d.ts +6 -0
  162. package/dist/stack-migration.d.ts.map +1 -1
  163. package/dist/stack-migration.js +49 -52
  164. package/dist/stack-migration.js.map +1 -1
  165. package/dist/subagent/fingerprints.d.ts +24 -0
  166. package/dist/subagent/fingerprints.d.ts.map +1 -0
  167. package/dist/subagent/fingerprints.js +81 -0
  168. package/dist/subagent/fingerprints.js.map +1 -0
  169. package/dist/subagent/host-port.d.ts +296 -0
  170. package/dist/subagent/host-port.d.ts.map +1 -0
  171. package/dist/subagent/host-port.js +560 -0
  172. package/dist/subagent/host-port.js.map +1 -0
  173. package/dist/subagent/index.d.ts +10 -10
  174. package/dist/subagent/index.d.ts.map +1 -1
  175. package/dist/subagent/index.js +9 -10
  176. package/dist/subagent/index.js.map +1 -1
  177. package/dist/subagent-host.d.ts +99 -18
  178. package/dist/subagent-host.d.ts.map +1 -1
  179. package/dist/subagent-host.js +143 -146
  180. package/dist/subagent-host.js.map +1 -1
  181. package/dist/template-render.d.ts +18 -0
  182. package/dist/template-render.d.ts.map +1 -0
  183. package/dist/template-render.js +232 -0
  184. package/dist/template-render.js.map +1 -0
  185. package/dist/types.d.ts +40 -27
  186. package/dist/types.d.ts.map +1 -1
  187. package/dist/types.js.map +1 -1
  188. package/dist/ui-contribution/contrib-port.d.ts +170 -0
  189. package/dist/ui-contribution/contrib-port.d.ts.map +1 -0
  190. package/dist/ui-contribution/contrib-port.js +640 -0
  191. package/dist/ui-contribution/contrib-port.js.map +1 -0
  192. package/dist/ui-contribution/index.d.ts +3 -0
  193. package/dist/ui-contribution/index.d.ts.map +1 -0
  194. package/dist/ui-contribution/index.js +2 -0
  195. package/dist/ui-contribution/index.js.map +1 -0
  196. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  197. package/dist/web-editor/client-script.generated.js +1 -1
  198. package/dist/web-editor/client-script.generated.js.map +1 -1
  199. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  200. package/dist/web-editor/client-styles.generated.js +1 -1
  201. package/dist/web-editor/client-styles.generated.js.map +1 -1
  202. package/dist/web-editor/contrib-service.d.ts +41 -0
  203. package/dist/web-editor/contrib-service.d.ts.map +1 -0
  204. package/dist/web-editor/contrib-service.js +174 -0
  205. package/dist/web-editor/contrib-service.js.map +1 -0
  206. package/dist/web-editor/line-diff.d.ts +28 -0
  207. package/dist/web-editor/line-diff.d.ts.map +1 -0
  208. package/dist/web-editor/line-diff.js +216 -0
  209. package/dist/web-editor/line-diff.js.map +1 -0
  210. package/dist/web-editor/schema-form.d.ts +63 -0
  211. package/dist/web-editor/schema-form.d.ts.map +1 -0
  212. package/dist/web-editor/schema-form.js +213 -0
  213. package/dist/web-editor/schema-form.js.map +1 -0
  214. package/dist/web-editor/server.d.ts.map +1 -1
  215. package/dist/web-editor/server.js +72 -74
  216. package/dist/web-editor/server.js.map +1 -1
  217. package/dist/web-editor/styles.d.ts.map +1 -1
  218. package/dist/web-editor/styles.js +201 -21
  219. package/dist/web-editor/styles.js.map +1 -1
  220. package/dist/web-editor/types.d.ts +12 -35
  221. package/dist/web-editor/types.d.ts.map +1 -1
  222. package/dist/web-host.d.ts +6 -2
  223. package/dist/web-host.d.ts.map +1 -1
  224. package/dist/web-host.js +33 -103
  225. package/dist/web-host.js.map +1 -1
  226. package/dist/workspace.d.ts +74 -0
  227. package/dist/workspace.d.ts.map +1 -0
  228. package/dist/workspace.js +351 -0
  229. package/dist/workspace.js.map +1 -0
  230. package/docs/README.md +7 -4
  231. package/docs/concepts/agent-profiles.md +1 -1
  232. package/docs/concepts/prompt-stacks.md +5 -5
  233. package/docs/design/0.5.1-plan.md +237 -0
  234. package/docs/design/README.md +21 -3
  235. package/docs/design/architecture-0.5.md +222 -0
  236. package/docs/design/archive/0.5-full-proposal/0.5-consumer-audit.md +62 -0
  237. package/docs/design/archive/0.5-full-proposal/0.5-inventory.md +208 -0
  238. package/docs/design/archive/0.5-full-proposal/0.5-phase0-decision-drafts.md +237 -0
  239. package/docs/design/archive/0.5-full-proposal/README.md +12 -0
  240. package/docs/design/archive/0.5-full-proposal/architecture-0.5.md +423 -0
  241. package/docs/design/archive/0.5-full-proposal/host-discovery-spike.md +103 -0
  242. package/docs/design/archive/0.5-full-proposal/template-language-spike.md +156 -0
  243. package/docs/design/context-diff-plan.md +78 -0
  244. package/docs/design/decision-template.md +33 -0
  245. package/docs/design/roadmap-0.4-archive.md +1 -1
  246. package/docs/design/subagents/interface-design.md +1 -1
  247. package/docs/development/architecture-rules.md +148 -0
  248. package/docs/development/release.md +7 -1
  249. package/docs/development/roadmap.md +37 -5
  250. package/docs/development/scoped-global-profiles-stacks.md +1 -1
  251. package/docs/development/setup.md +6 -4
  252. package/docs/getting-started.md +5 -4
  253. package/docs/guides/custom-macros-and-slots.md +8 -7
  254. package/docs/guides/debugging.md +1 -1
  255. package/docs/guides/delegation.md +18 -22
  256. package/docs/guides/migrating-to-0.5.md +107 -0
  257. package/docs/guides/use-cases.md +7 -11
  258. package/docs/guides/web-editor.md +6 -10
  259. package/docs/reference/commands.md +4 -3
  260. package/docs/reference/configuration.md +17 -18
  261. package/docs/reference/features.md +34 -80
  262. package/docs/reference/macros-and-slots.md +70 -49
  263. package/docs/reference/public-api.md +76 -17
  264. package/docs/reference/stack-schema.md +15 -10
  265. package/docs/reference/subagent-host-port.md +49 -0
  266. package/docs/reference/ui-contribution-port.md +51 -0
  267. package/docs/zh-CN/README.md +3 -3
  268. package/docs/zh-CN/concepts/agent-profiles.md +1 -1
  269. package/docs/zh-CN/concepts/prompt-stacks.md +5 -5
  270. package/docs/zh-CN/getting-started.md +3 -2
  271. package/docs/zh-CN/guides/delegation.md +10 -12
  272. package/docs/zh-CN/guides/migrating-to-0.5.md +92 -0
  273. package/docs/zh-CN/guides/web-editor.md +4 -4
  274. package/docs/zh-CN/reference/commands.md +3 -2
  275. package/examples/custom-system-status-extension/README.md +3 -3
  276. package/examples/custom-system-status-extension/index.ts +2 -1
  277. package/examples/custom-system-status-extension/prompt-stack.json +4 -3
  278. package/examples/default-prompt-stack.json +9 -4
  279. package/examples/image-reader-prompt-stack.json +16 -26
  280. package/examples/reviewer-prompt-stack.json +13 -24
  281. package/package.json +106 -120
  282. package/dist/runtime/subagent-runtime.d.ts +0 -45
  283. package/dist/runtime/subagent-runtime.d.ts.map +0 -1
  284. package/dist/runtime/subagent-runtime.js +0 -343
  285. package/dist/runtime/subagent-runtime.js.map +0 -1
  286. package/dist/runtime-state.d.ts +0 -30
  287. package/dist/runtime-state.d.ts.map +0 -1
  288. package/dist/runtime-state.js +0 -17
  289. package/dist/runtime-state.js.map +0 -1
  290. package/dist/sillytavern-importer/items.d.ts +0 -3
  291. package/dist/sillytavern-importer/items.d.ts.map +0 -1
  292. package/dist/sillytavern-importer/items.js +0 -88
  293. package/dist/sillytavern-importer/items.js.map +0 -1
  294. package/dist/sillytavern-importer/macros.d.ts +0 -15
  295. package/dist/sillytavern-importer/macros.d.ts.map +0 -1
  296. package/dist/sillytavern-importer/macros.js +0 -141
  297. package/dist/sillytavern-importer/macros.js.map +0 -1
  298. package/dist/sillytavern-importer/prompt-order.d.ts +0 -6
  299. package/dist/sillytavern-importer/prompt-order.d.ts.map +0 -1
  300. package/dist/sillytavern-importer/prompt-order.js +0 -38
  301. package/dist/sillytavern-importer/prompt-order.js.map +0 -1
  302. package/dist/sillytavern-importer/regex.d.ts +0 -3
  303. package/dist/sillytavern-importer/regex.d.ts.map +0 -1
  304. package/dist/sillytavern-importer/regex.js +0 -275
  305. package/dist/sillytavern-importer/regex.js.map +0 -1
  306. package/dist/sillytavern-importer/report.d.ts +0 -21
  307. package/dist/sillytavern-importer/report.d.ts.map +0 -1
  308. package/dist/sillytavern-importer/report.js +0 -166
  309. package/dist/sillytavern-importer/report.js.map +0 -1
  310. package/dist/sillytavern-importer/types.d.ts +0 -106
  311. package/dist/sillytavern-importer/types.d.ts.map +0 -1
  312. package/dist/sillytavern-importer/types.js +0 -2
  313. package/dist/sillytavern-importer/types.js.map +0 -1
  314. package/dist/sillytavern-importer.d.ts +0 -5
  315. package/dist/sillytavern-importer.d.ts.map +0 -1
  316. package/dist/sillytavern-importer.js +0 -117
  317. package/dist/sillytavern-importer.js.map +0 -1
  318. package/dist/subagent/canonical.d.ts +0 -22
  319. package/dist/subagent/canonical.d.ts.map +0 -1
  320. package/dist/subagent/canonical.js +0 -24
  321. package/dist/subagent/canonical.js.map +0 -1
  322. package/dist/subagent/context.d.ts +0 -8
  323. package/dist/subagent/context.d.ts.map +0 -1
  324. package/dist/subagent/context.js +0 -125
  325. package/dist/subagent/context.js.map +0 -1
  326. package/dist/subagent/contract.d.ts +0 -10
  327. package/dist/subagent/contract.d.ts.map +0 -1
  328. package/dist/subagent/contract.js +0 -10
  329. package/dist/subagent/contract.js.map +0 -1
  330. package/dist/subagent/plan.d.ts +0 -18
  331. package/dist/subagent/plan.d.ts.map +0 -1
  332. package/dist/subagent/plan.js +0 -157
  333. package/dist/subagent/plan.js.map +0 -1
  334. package/dist/subagent/preflight.d.ts +0 -4
  335. package/dist/subagent/preflight.d.ts.map +0 -1
  336. package/dist/subagent/preflight.js +0 -108
  337. package/dist/subagent/preflight.js.map +0 -1
  338. package/dist/subagent/request.d.ts +0 -4
  339. package/dist/subagent/request.d.ts.map +0 -1
  340. package/dist/subagent/request.js +0 -154
  341. package/dist/subagent/request.js.map +0 -1
  342. package/dist/subagent/response.d.ts +0 -8
  343. package/dist/subagent/response.d.ts.map +0 -1
  344. package/dist/subagent/response.js +0 -155
  345. package/dist/subagent/response.js.map +0 -1
  346. package/dist/subagent/tools.d.ts +0 -4
  347. package/dist/subagent/tools.d.ts.map +0 -1
  348. package/dist/subagent/tools.js +0 -42
  349. package/dist/subagent/tools.js.map +0 -1
  350. package/dist/subagent/types.d.ts +0 -272
  351. package/dist/subagent/types.d.ts.map +0 -1
  352. package/dist/subagent/types.js +0 -3
  353. package/dist/subagent/types.js.map +0 -1
  354. package/dist/subagent/validation.d.ts +0 -35
  355. package/dist/subagent/validation.d.ts.map +0 -1
  356. package/dist/subagent/validation.js +0 -314
  357. package/dist/subagent/validation.js.map +0 -1
  358. package/dist/subagent-command.d.ts +0 -5
  359. package/dist/subagent-command.d.ts.map +0 -1
  360. package/dist/subagent-command.js +0 -249
  361. package/dist/subagent-command.js.map +0 -1
  362. package/dist/subagent-profile-tool.d.ts +0 -49
  363. package/dist/subagent-profile-tool.d.ts.map +0 -1
  364. package/dist/subagent-profile-tool.js +0 -125
  365. package/dist/subagent-profile-tool.js.map +0 -1
  366. package/dist/subagent-tool.d.ts +0 -77
  367. package/dist/subagent-tool.d.ts.map +0 -1
  368. package/dist/subagent-tool.js +0 -559
  369. package/dist/subagent-tool.js.map +0 -1
  370. package/docs/guides/sillytavern-import.md +0 -47
  371. package/docs/reference/subagent-adapter.md +0 -204
  372. package/examples/sillytavern-dm-writer-prompt-stack.json +0 -190
@@ -0,0 +1,423 @@
1
+ # pi-forge 0.5.0 architecture plan
2
+
3
+ [Documentation](../../../README.md) · [Development rules](../../../development/architecture-rules.md) · [Roadmap](../../../development/roadmap.md)
4
+
5
+ Status: proposed
6
+
7
+ Date: 2026-08-17
8
+
9
+ 0.5 is a deliberately breaking stabilization release. Its purpose is to make the extension understandable and evolvable before adding more features. Compatibility is preserved only where it has a demonstrated consumer and does not compromise the target boundaries.
10
+
11
+ ## Problem statement
12
+
13
+ The 0.4 implementation is well tested, but feature throughput has outpaced architectural consolidation. Prompt stacks, profiles, web editing, mutable variables, imports, payload debugging, and subagents share state and orchestration paths. Several adapters perform application or persistence work directly, and internal file-shaped exports constrain reorganization.
14
+
15
+ The problem is not primarily file size. It is unclear ownership and too many ways to load, validate, mutate, compile, or present the same resources.
16
+
17
+ ## Release goals
18
+
19
+ 0.5 will:
20
+
21
+ - establish a one-directional architecture with explicit domain, application, port, infrastructure, and adapter layers;
22
+ - make a `ForgeWorkspace` the owner of coherent prompt-stack/profile resource state;
23
+ - unify stack/profile persistence behind scoped repositories and codecs while keeping their domain models separate;
24
+ - make prompt compilation deterministic over a normalized immutable environment;
25
+ - remove mutable turn/session variables and render-time variable mutation;
26
+ - replace the macro implementation only through an explicit template-engine contract, preserving a legacy reader only when migration requires it;
27
+ - extract optional subagent integration from the main extension through a versioned host port;
28
+ - remove or sharply reduce SillyTavern-specific functionality;
29
+ - replace wildcard internal exports with intentional package entry points;
30
+ - simplify commands and the web editor into adapters over shared application services.
31
+
32
+ ## Non-goals
33
+
34
+ 0.5 will not add orchestration, background agents, pipelines, retries, queues, new regex modes, richer imports, or new editor product surfaces. Sandbox and staged-write work remains deferred until the package and host boundaries are stable.
35
+
36
+ The refactor does not merge profiles, stacks, and compilation into one domain object. They share infrastructure and an application facade, but retain distinct responsibilities.
37
+
38
+ ## Accepted architectural decisions
39
+
40
+ ### Breaking cleanup is preferred to indefinite compatibility
41
+
42
+ 0.5 may change JSON schema, public TypeScript APIs, commands, package exports, and internal storage coordination. Every user-visible break must have an explicit migration note; not every 0.4 feature requires a compatibility implementation.
43
+
44
+ ### Mutable variables are removed
45
+
46
+ The following 0.4 behavior is removed from the 0.5 core design:
47
+
48
+ - turn and session variable stores;
49
+ - `setvar`, `setturnvar`, `setsessionvar`, and clear-variable macros;
50
+ - variable persistence in Pi session entries;
51
+ - the `variables` slot;
52
+ - render-time mutation through custom macro/slot contexts.
53
+
54
+ Templates receive an immutable context containing built-in runtime values. Static reusable values are retained as an immutable `parameters` object in stack schema v2; the v1 `stack.variables` string/JSON inconsistency is resolved by the v2 codec.
55
+
56
+ ### SillyTavern is not a core architecture driver
57
+
58
+ The current fidelity-oriented importer, regex translation, report surface, command, guide, and dedicated example are removed from the core 0.5 scope.
59
+
60
+ Decision: **complete removal**. 0.4 is documented as the last supported conversion path. A richer converter can later live in a separate package without shaping the prompt compiler.
61
+
62
+ ### Subagents become optional integration
63
+
64
+ The main extension retains profile/stack resolution and prompt preparation. A separate `pi-forge-subagents` extension owns delegation configuration, tools, commands, approval/progress UI, execution adaptation, and its dependency on `@zihanw/pi-subagent-runtime`.
65
+
66
+ The extraction must use a versioned Forge host port. It may not import internal runtime state, duplicate the active resource workspace, or make ordinary stack/profile usage depend on a subagent package.
67
+
68
+ Confirmed decisions:
69
+
70
+ - `@zihanw/pi-forge/subagent` remains a main-package entry point, but is cleaned into a versioned host port / host-neutral contract rather than re-exporting internal host preparation modules.
71
+ - The main package removes the hard dependency on `@zihanw/pi-subagent-runtime`; that dependency moves to `pi-forge-subagents` or becomes an optional peer dependency.
72
+ - The optional package may depend on the main package only through documented public ports.
73
+
74
+ ### Schemas and public APIs restart deliberately
75
+
76
+ Prompt-stack schema v2 describes the cleaned compiler and template model. Agent-profile v2 is introduced only if its stored shape must change. The package no longer exports implementation modules through `src/*`; public surfaces are explicit entry points with documented stability.
77
+
78
+ ## Confirmed 0.5.0 planning decisions
79
+
80
+ The following decisions were confirmed while this plan was in proposed status. Items still open are marked explicitly.
81
+
82
+ ### Architecture direction
83
+
84
+ - A1: Target diagrams use port dependencies: `PromptStackService` / `AgentProfileService` depend on repository/host ports; `StackRepo` / `ProfileRepo` implement those ports.
85
+ - A2: Add an automatic dependency-direction check (`check:architecture`) during Phase 1/2.
86
+ - A3: When `src/*` exports are removed, update `scripts/check-package.mjs`, `docs/reference/public-api.md`, and public-API tests in the same change.
87
+ - A4: The release is referred to consistently as 0.5.0.
88
+
89
+ ### Component ownership
90
+
91
+ - B1: `@zihanw/pi-forge/subagent` remains in the main package as a versioned host port / host-neutral contract, but its internal implementation surface is cleaned.
92
+ - B2: Remove the main package hard dependency on `@zihanw/pi-subagent-runtime`.
93
+ - B3: Forge extension loading/unloading and registry coordination are owned by `ForgeWorkspace`.
94
+ - B4: Tool-policy synchronization is defined as a port (`ToolPolicyPort`), called by `PromptStackService`; Pi adapter implements it.
95
+ - B5: Debug/payload/browser presentation state is a separate state slice, not part of the `ForgeWorkspace` resource snapshot.
96
+
97
+ ### Schema and feature decisions
98
+
99
+ - B6: SillyTavern is removed completely from 0.5.0 core; 0.4 is the last supported conversion path.
100
+ - B7: Template language is still open; it will be decided after a spike.
101
+ - B8: Static reusable values are retained as immutable `parameters` in stack schema v2; the v1 `variables` codec inconsistency is fixed in v2.
102
+ - B9: Cross-extension host discovery will be decided after a focused spike; no final mechanism is assumed yet.
103
+
104
+ ### Process decisions
105
+
106
+ - C1: Phase 0 produces an explicit inventory deliverable (for example `docs/design/0.5-inventory.md` or a comparable checklist).
107
+ - C2: Chinese documentation is updated for user-facing breaking changes; internal architecture documentation is not required to be fully synchronized.
108
+ - C3: No formal owner field is used; maintainer and agents together drive and review decisions.
109
+
110
+ ## Current 0.4 architecture
111
+
112
+ ```mermaid
113
+ flowchart TB
114
+ Pi["Pi host"] --> Entry["index.ts composition root"]
115
+ Entry --> Lifecycle["Lifecycle"]
116
+ Entry --> StackRuntime["Stack runtime"]
117
+ Entry --> ProfileRuntime["Profile runtime"]
118
+ Entry --> PolicyRuntime["Policy runtime"]
119
+ Entry --> WebRuntime["Web-editor runtime"]
120
+ Entry --> SubRuntime["Subagent runtime"]
121
+
122
+ State[("Shared PiForgeRuntimeState")]
123
+ Lifecycle --> State
124
+ StackRuntime --> State
125
+ ProfileRuntime --> State
126
+ PolicyRuntime --> State
127
+ WebRuntime --> State
128
+ SubRuntime --> State
129
+
130
+ StackRuntime --> StackLoader["Stack loader + validation"]
131
+ ProfileRuntime --> ProfileLoader["Profile loader + resolution"]
132
+ ProfileRuntime --> StackRuntime
133
+ StackRuntime --> ProfileRuntime
134
+
135
+ Lifecycle --> Compiler["Compiler"]
136
+ Compiler --> Macros["Stateful macros + variables"]
137
+ Compiler --> Slots["Slot registry"]
138
+ Compiler --> Regex["Regex transforms"]
139
+
140
+ WebRuntime --> WebHost["Web host"]
141
+ WebHost --> DirectIO["Direct stack filesystem mutations"]
142
+ WebHost --> ProfileService["Profile service"]
143
+ WebHost --> SubRuntime
144
+
145
+ SubRuntime --> SubHost["Forge host preparation"]
146
+ SubHost --> Compiler
147
+ SubRuntime --> ExternalRuntime["pi-subagent-runtime"]
148
+ ```
149
+
150
+ The high-risk connections are shared state ownership, circular stack/profile coordination, direct persistence in adapters, and optional subagent concerns reaching the core editor and composition root.
151
+
152
+ ## Target package and component architecture
153
+
154
+ ```mermaid
155
+ flowchart TB
156
+ subgraph Main["@zihanw/pi-forge"]
157
+ PiAdapters["Pi lifecycle + command adapters"]
158
+ WebAdapters["HTTP + browser adapters"]
159
+ Workspace["ForgeWorkspace"]
160
+ StackService["PromptStackService"]
161
+ ProfileService["AgentProfileService"]
162
+ PiPorts["Pi runtime/environment adapters"]
163
+
164
+ PiAdapters --> Workspace
165
+ WebAdapters --> Workspace
166
+ Workspace --> StackService
167
+ Workspace --> ProfileService
168
+ ProfileService --> StackService
169
+ end
170
+
171
+ subgraph Core["@zihanw/pi-forge-core"]
172
+ ResourceCore["Scoped resources + catalogs"]
173
+ StackDomain["Prompt-stack schema + codec"]
174
+ ProfileDomain["Agent-profile schema + codec"]
175
+ Compiler["PromptCompiler"]
176
+ Templates["TemplateEngine registry"]
177
+ Diagnostics["Common diagnostics"]
178
+ Ports["Repository + host ports"]
179
+
180
+ Compiler --> StackDomain
181
+ Compiler --> Templates
182
+ StackDomain --> ResourceCore
183
+ ProfileDomain --> ResourceCore
184
+ end
185
+
186
+ subgraph Infra["Main extension infrastructure"]
187
+ StackRepo["PromptStackRepository"]
188
+ ProfileRepo["AgentProfileRepository"]
189
+ AtomicFiles["Atomic scoped file store"]
190
+
191
+ StackRepo --> AtomicFiles
192
+ ProfileRepo --> AtomicFiles
193
+ end
194
+
195
+ StackService --> StackDomain
196
+ StackService --> Compiler
197
+ StackService --> Ports
198
+ ProfileService --> ProfileDomain
199
+ ProfileService --> Ports
200
+ PiPorts --> Ports
201
+ StackRepo -.->|implements| Ports
202
+ ProfileRepo -.->|implements| Ports
203
+
204
+ subgraph Optional["pi-forge-subagents"]
205
+ SubAdapters["Commands + tools + approval UI"]
206
+ SubHost["ForgeHostPort client"]
207
+ SubRuntime["pi-subagent-runtime"]
208
+
209
+ SubAdapters --> SubHost
210
+ SubAdapters --> SubRuntime
211
+ end
212
+
213
+ Workspace -. "versioned host capability" .-> SubHost
214
+ ```
215
+
216
+ `pi-forge-core` is host-neutral: it does not import the Pi extension API, HTTP, browser, TUI, or subagent runtime. If physical package extraction would delay boundary work, the same structure may land first as enforced internal modules and become a package before the subagent split.
217
+
218
+ ## Target responsibilities
219
+
220
+ ### ForgeWorkspace
221
+
222
+ - Own one immutable workspace snapshot containing scoped stack/profile catalogs and active selection/provenance references.
223
+ - Own Forge extension loading/unloading and registry coordination; coordinate resource reload and snapshot publication without circular runtime callbacks.
224
+ - Expose application services and resource-change subscriptions to adapters.
225
+ - Keep payload debugging and browser presentation state outside the resource snapshot.
226
+
227
+ ### PromptStackService
228
+
229
+ - List, resolve, validate, create, update, fork, delete, activate, preview, and compile stacks.
230
+ - Own auto-activation selection and active-stack state transitions.
231
+ - Coordinate tool-policy changes through a `ToolPolicyPort` rather than calling UI, Pi API, or persistence code directly.
232
+
233
+ ### AgentProfileService
234
+
235
+ - List, resolve, validate, create, update, delete, preflight, apply, and report provenance/drift.
236
+ - Apply model, thinking, and stack transactionally through a runtime-controller port.
237
+ - Resolve stack references through the workspace catalog, not through a separate loader.
238
+
239
+ ### Repositories and codecs
240
+
241
+ - Repositories implement scoped discovery and safe mutation.
242
+ - Codecs are the only schema parsing, normalization, validation, serialization, and fingerprint source.
243
+ - Updates/deletes carry expected fingerprints to prevent overwriting unseen external changes.
244
+ - Filesystem writes use atomic replacement where the platform permits it.
245
+
246
+ ### PromptCompiler and TemplateEngine
247
+
248
+ - Consume a normalized immutable `PromptEnvironment`, not a live Pi context.
249
+ - Return system prompt, prepared messages, sources, diagnostics, template dependencies, and an explicit variable/parameter receipt if parameters are retained.
250
+ - Keep history placement, structured runtime slots, tool/skill selection, and outgoing deterministic transforms as separate compiler stages.
251
+ - Use an engine contract with parse, analyze, and render operations. A restricted Jinja-like engine is a candidate, not yet an accepted dependency.
252
+
253
+ ### Adapters
254
+
255
+ - Parse external input and render typed service results.
256
+ - Contain no resource persistence or duplicated schema validation.
257
+ - Browser view models and HTTP status mapping remain outside application/domain state.
258
+
259
+ ## Proposed source layout
260
+
261
+ The exact filenames may evolve, but ownership should converge on:
262
+
263
+ ```text
264
+ packages/
265
+ core/
266
+ src/resources/
267
+ src/prompt-stacks/
268
+ src/profiles/
269
+ src/compiler/
270
+ src/templates/
271
+ src/ports/
272
+ pi-forge/
273
+ src/application/
274
+ src/infrastructure/
275
+ src/adapters/pi/
276
+ src/adapters/commands/
277
+ src/adapters/web/
278
+ pi-forge-subagents/
279
+ src/host/
280
+ src/runtime/
281
+ src/adapters/commands/
282
+ src/adapters/tools/
283
+ ```
284
+
285
+ Moving to a workspace is an implementation choice, not permission to move files before their interfaces and ownership are characterized.
286
+
287
+ ## Feature disposition
288
+
289
+ | 0.4 capability | 0.5 disposition |
290
+ |---|---|
291
+ | Ordered prompt blocks and runtime slots | Keep and move into the v2 compiler |
292
+ | Scoped global/project resources | Keep behind common repositories/catalogs |
293
+ | Tool policy and model-visible skill filtering | Keep stack-owned |
294
+ | One-shot profiles, transactional apply, provenance, drift | Keep in `AgentProfileService` |
295
+ | Web stack/profile editor | Keep as adapters over services; simplify during migration |
296
+ | Prompt preview and redacted payload debugging | Keep; isolate debugging state |
297
+ | Turn/session variables and mutation macros | Remove |
298
+ | Static stack variables | Keep as immutable `parameters` in schema v2; fix the v1 string/JSON codec inconsistency |
299
+ | Current custom macro API | Break and replace with the template/slot extension contract |
300
+ | SillyTavern fidelity importer and regex emulation | Remove completely; 0.4 is the last supported conversion path |
301
+ | Regex history/compiled transforms | Keep initially; no new modes during 0.5 |
302
+ | Destructive finalized-transcript regex | Audit separately before schema v2 is frozen |
303
+ | Foreground subagent integration | Move to optional `pi-forge-subagents`; `@zihanw/pi-forge/subagent` remains as a versioned host port/contract |
304
+ | `src/*` package exports | Remove; update `check-package.mjs`, public API docs/tests in the same change |
305
+ | Legacy prompt-stack storage migration command | Remove after documenting the required pre-0.5 migration path |
306
+
307
+ ## Implementation phases
308
+
309
+ ### Phase 0: freeze and characterize
310
+
311
+ - Announce the 0.5 feature freeze in repository guidance and roadmap.
312
+ - Produce an explicit inventory deliverable covering public exports, persisted entries, commands, schemas, examples, and real internal consumers.
313
+ - Add characterization tests around any behavior that will move before changing ownership.
314
+ - Run the template-language spike and cross-extension host-discovery spike; record their findings before the affected phases start.
315
+ - Decide the remaining implementation gates listed under open decisions.
316
+
317
+ Exit: the removal/migration inventory is reviewed, and no unplanned feature work is in flight.
318
+
319
+ ### Phase 1: resource core and repositories
320
+
321
+ - Introduce common diagnostic and loaded-resource envelopes.
322
+ - Extract stack/profile codecs.
323
+ - Implement repository ports and guarded filesystem repositories.
324
+ - Add the automatic dependency-direction check (`check:architecture`) so adapter/domain boundaries are enforced from this phase onward.
325
+ - Move all stack mutations out of `web-host.ts` and import commands.
326
+
327
+ Exit: every domain resource mutation uses a repository and has consistent stale-write/path-safety behavior.
328
+
329
+ ### Phase 2: application services and workspace
330
+
331
+ - Consolidate stack operations into `PromptStackService`.
332
+ - Consolidate profile operations into `AgentProfileService`.
333
+ - Introduce `ForgeWorkspace` and publish coherent reload snapshots.
334
+ - Split debug/browser state away from resource state into a separate state slice.
335
+ - Replace circular stack/profile runtime wiring with workspace-owned services and ports.
336
+
337
+ Exit: commands, lifecycle, and web host use services; `PiForgeRuntimeState` is removed or reduced to adapter-owned state with no domain ownership.
338
+
339
+ ### Phase 3: compiler and schema v2
340
+
341
+ - Define normalized `PromptEnvironment`, compiler result, and template-engine contracts.
342
+ - Remove mutable variables and session variable persistence.
343
+ - Select and implement the v2 template syntax.
344
+ - Make template dependency analysis authoritative.
345
+ - Decide the retained regex surface and freeze prompt-stack schema v2.
346
+
347
+ Exit: compilation is deterministic over immutable inputs, previews and runtime use the same entry point, and v1-to-v2 migration behavior is documented and tested.
348
+
349
+ ### Phase 4: adapter cleanup
350
+
351
+ - Reduce Pi lifecycle modules to event adaptation.
352
+ - Reduce commands and HTTP handlers to parsing/result rendering.
353
+ - Split web view-model construction from application workflows.
354
+ - Remove SillyTavern surfaces from commands, web editor, docs, examples, and tests; update Chinese user docs for user-facing breaking changes.
355
+
356
+ Exit: dependency checks show adapters pointing inward with no direct resource persistence.
357
+
358
+ ### Phase 5: subagent extraction and packages
359
+
360
+ - Validate cross-extension capability discovery with a focused spike.
361
+ - Publish the versioned Forge host port and clean `@zihanw/pi-forge/subagent` into that stable surface.
362
+ - Remove the main package hard dependency on `@zihanw/pi-subagent-runtime`.
363
+ - Move subagent configuration, commands, tools, UI, and runtime adaptation into `pi-forge-subagents`.
364
+ - Ensure main pi-forge installs and runs without subagent dependencies.
365
+ - Remove subagent UI/configuration from the core web editor unless an explicit contribution port is accepted.
366
+
367
+ Exit: ordinary stacks/profiles have no dependency on the optional package, and the optional extension consumes only documented public ports.
368
+
369
+ ### Phase 6: public surface and release
370
+
371
+ - Replace root re-export sprawl with explicit package entry points.
372
+ - Remove `src/*` aliases and 0.4 compatibility barrels; update `check-package.mjs`, public API docs, and public API tests in the same change.
373
+ - Complete migration guide, changelog, package checks, and documentation rewrite; use 0.5.0 naming consistently.
374
+ - Run packed-install tests against supported Pi versions with and without `pi-forge-subagents`.
375
+
376
+ Exit: all release gates below pass.
377
+
378
+ ## Open implementation-gate decisions
379
+
380
+ These are the remaining decisions that must be resolved before their affected implementation phases begin:
381
+
382
+ 1. **Template language (spike completed; decision pending):** the Phase-0 [template-language spike](template-language-spike.md) rejects a broad Jinja-like engine and recommends a closed `forge-v1` AST grammar. Accept the exact grammar, environment schema, filter/condition set, extension-port disposition, schema representation, and migration behavior before Phase 3.
383
+ 2. **Static parameters (decided):** retain a JSON-compatible immutable `parameters` object in stack schema v2; do not remove static reusable values.
384
+ 3. **SillyTavern migration (decided):** complete removal; 0.4 is the last supported conversion path. No converter is retained in 0.5.0 core.
385
+ 4. **Cross-extension host discovery (spike completed; decision pending):** the Phase-0 [Pi host-discovery spike](host-discovery-spike.md) validated Pi's shared in-process event bus across both extension load orders. It recommends a versioned, session-scoped event-bus RPC port with explicit duplicate-host detection and disposal; accept the protocol, operation catalogue, and package versioning before Phase 5.
386
+ 5. **Pi session custom-entry versioning (open):** define explicit version, restoration, branch-navigation, malformed-entry, and migration semantics for prompt-stack selection and profile provenance entries. Define how removed variable entries are handled without recreating mutable state. Resolve before Phase 2/3 changes session restoration.
387
+ 6. **Configuration ownership after subagent extraction (open):** `webEditor.*` remains owned by the main package. Decide whether `subagents.*`, which must be owned and written only by `pi-forge-subagents`, remains a namespaced section of `.pi/forge/config.json` or moves to dedicated optional-package configuration files; include migration and behavior when the optional package is absent. Resolve before Phase 4/5 changes configuration adapters.
388
+ 7. **Final public-surface classification (open):** before Phase 6, use the Phase-0 inventory to classify every root and subpath surface as stable, experimental, internal, or removed; record named consumers, target entry points, and migration notices. Phase 6 must implement this accepted register rather than decide exports during removal.
389
+ 8. **Pi compatibility policy (open):** define the minimum supported Pi version and rolling tested-version release matrix separately from wildcard host peers. Include packed main-only and main-plus-optional-package tests, plus a release-time npm `latest` probe. Resolve before Phase 1 establishes the supported CI matrix.
390
+
391
+ ## Migration policy
392
+
393
+ - Provide a v1-to-v2 stack migration command or standalone script for mechanically convertible fields.
394
+ - Mutable variable behavior that cannot be preserved becomes an explicit migration diagnostic, not a silent approximation.
395
+ - Recommend running the final 0.4 release to convert legacy `.pi/prompt-stacks` storage before upgrading if 0.5 removes that migration command.
396
+ - Agent profiles retain IDs and scoped stack references where possible; migration rewrites only schema fields that actually change.
397
+ - SillyTavern users must convert with 0.4 before upgrading; 0.5.0 core does not retain a converter.
398
+ - No compatibility shim is accepted without a named consumer, test, warning/removal version, and owner.
399
+
400
+ ## Release gates
401
+
402
+ 0.5 is ready only when:
403
+
404
+ - dependency direction is checked automatically;
405
+ - all resource persistence is repository-owned;
406
+ - workspace reload and profile application have transactional/integration coverage;
407
+ - runtime and preview compilation share one compiler entry point;
408
+ - mutable variables and their persisted entries are removed or explicitly migrated;
409
+ - schema v2 and public entry points are documented without `src/*` exports;
410
+ - main pi-forge passes verification without installing the subagent extension/runtime;
411
+ - the optional subagent package passes host-version, preparation, approval, cancellation, and packed-install tests;
412
+ - current and target architecture diagrams match the implementation;
413
+ - English user documentation is updated and Chinese user-facing documentation is updated for breaking changes (internal architecture docs are not required to be fully synchronized);
414
+ - `npm run verify` and packed-install smoke tests pass on the documented Pi compatibility range.
415
+
416
+ ## Deferred until after 0.5
417
+
418
+ - New prompt composition features.
419
+ - New import formats or high-fidelity external-preset emulation.
420
+ - Sandbox and staged subagent writes.
421
+ - Background/resumable agents, chains, queues, or orchestration.
422
+ - New web-editor surfaces unrelated to the migration.
423
+ - Additional regex or transcript-rewriting behavior.
@@ -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.