@osolmaz/pi-workflows 0.16.2 → 0.16.3

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 (315) hide show
  1. package/README.md +41 -41
  2. package/dist/builtins/monitor.workflow.d.ts +1 -1
  3. package/dist/builtins/monitor.workflow.js +8 -8
  4. package/dist/builtins/pi-agent-group.js +3 -3
  5. package/dist/builtins/pi-agent-group.js.map +1 -1
  6. package/dist/channels/adapter-entry.js +14 -14
  7. package/dist/channels/adapter-entry.js.map +1 -1
  8. package/dist/client/client.d.ts +6 -6
  9. package/dist/client/client.js +27 -27
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/protocol.d.ts +4 -1
  12. package/dist/client/protocol.js +17 -11
  13. package/dist/client/protocol.js.map +1 -1
  14. package/dist/client/resolver.d.ts +4 -4
  15. package/dist/client/view.d.ts +1 -1
  16. package/dist/extension/index.d.ts +1 -1
  17. package/dist/extension/index.js +32 -32
  18. package/dist/extension/index.js.map +1 -1
  19. package/dist/extension/recorder.d.ts +1 -1
  20. package/dist/extension/recorder.js +1 -1
  21. package/dist/extension/recorder.js.map +1 -1
  22. package/dist/extension/remote-recorder-store.d.ts +1 -1
  23. package/dist/extension/remote-recorder-store.js +2 -2
  24. package/dist/extension/remote-recorder-store.js.map +1 -1
  25. package/dist/extension/{controller-command.d.ts → resource-manager-command.d.ts} +6 -6
  26. package/dist/extension/{controller-command.js → resource-manager-command.js} +7 -7
  27. package/dist/extension/resource-manager-command.js.map +1 -0
  28. package/dist/extension/session-delivery.d.ts +1 -1
  29. package/dist/extension/session-delivery.js +2 -2
  30. package/dist/extension/session-delivery.js.map +1 -1
  31. package/dist/extension/session-view.d.ts +1 -1
  32. package/dist/extension/session-view.js +1 -1
  33. package/dist/extension/session-view.js.map +1 -1
  34. package/dist/extension/workflow-message-coordinator.d.ts +1 -1
  35. package/dist/extension/workflow-message-coordinator.js +6 -6
  36. package/dist/extension/workflow-message-coordinator.js.map +1 -1
  37. package/dist/resource-managers/conditions.d.ts +6 -0
  38. package/dist/{controllers → resource-managers}/conditions.js +3 -3
  39. package/dist/resource-managers/conditions.js.map +1 -0
  40. package/dist/resource-managers/definition.d.ts +6 -0
  41. package/dist/resource-managers/definition.js +45 -0
  42. package/dist/resource-managers/definition.js.map +1 -0
  43. package/dist/resource-managers/effects.d.ts +15 -0
  44. package/dist/{controllers → resource-managers}/effects.js +2 -2
  45. package/dist/resource-managers/effects.js.map +1 -0
  46. package/dist/resource-managers/errors.d.ts +12 -0
  47. package/dist/resource-managers/errors.js +25 -0
  48. package/dist/resource-managers/errors.js.map +1 -0
  49. package/dist/resource-managers/index.d.ts +12 -0
  50. package/dist/resource-managers/index.js +12 -0
  51. package/dist/resource-managers/index.js.map +1 -0
  52. package/dist/resource-managers/json.js.map +1 -0
  53. package/dist/resource-managers/loader.d.ts +23 -0
  54. package/dist/resource-managers/loader.js +75 -0
  55. package/dist/resource-managers/loader.js.map +1 -0
  56. package/dist/resource-managers/results.d.ts +5 -0
  57. package/dist/resource-managers/results.js.map +1 -0
  58. package/dist/resource-managers/runtime.d.ts +59 -0
  59. package/dist/{controllers/manager.js → resource-managers/runtime.js} +57 -57
  60. package/dist/resource-managers/runtime.js.map +1 -0
  61. package/dist/{controllers → resource-managers}/sqlite.d.ts +44 -44
  62. package/dist/{controllers → resource-managers}/sqlite.js +139 -130
  63. package/dist/resource-managers/sqlite.js.map +1 -0
  64. package/dist/{controllers → resource-managers}/store.d.ts +33 -33
  65. package/dist/{controllers → resource-managers}/store.js.map +1 -1
  66. package/dist/{controllers → resource-managers}/types.d.ts +41 -41
  67. package/dist/{controllers → resource-managers}/types.js.map +1 -1
  68. package/dist/resource-managers/workflows.d.ts +34 -0
  69. package/dist/{controllers → resource-managers}/workflows.js +15 -15
  70. package/dist/resource-managers/workflows.js.map +1 -0
  71. package/dist/server/channel-effects.js.map +1 -0
  72. package/dist/{host → server}/channel-supervisor.d.ts +6 -6
  73. package/dist/{host → server}/channel-supervisor.js +3 -3
  74. package/dist/server/channel-supervisor.js.map +1 -0
  75. package/dist/{host/child-worker-supervisor.d.ts → server/child-runner-supervisor.d.ts} +15 -13
  76. package/dist/{host/child-worker-supervisor.js → server/child-runner-supervisor.js} +6 -5
  77. package/dist/server/child-runner-supervisor.js.map +1 -0
  78. package/dist/{host → server}/processes.d.ts +3 -3
  79. package/dist/{host → server}/processes.js +3 -3
  80. package/dist/server/processes.js.map +1 -0
  81. package/dist/{host → server}/resolver-entry.d.ts +6 -6
  82. package/dist/{host → server}/resolver-entry.js +14 -14
  83. package/dist/server/resolver-entry.js.map +1 -0
  84. package/dist/server/resource-runner-entry.d.ts +2 -0
  85. package/dist/{host/controller-worker-entry.js → server/resource-runner-entry.js} +33 -33
  86. package/dist/server/resource-runner-entry.js.map +1 -0
  87. package/dist/server/resource-runner-protocol.d.ts +36 -0
  88. package/dist/server/resource-runner-protocol.js +49 -0
  89. package/dist/server/resource-runner-protocol.js.map +1 -0
  90. package/dist/server/resource-runner-supervisor.d.ts +21 -0
  91. package/dist/{host/worker-supervisor.js → server/resource-runner-supervisor.js} +17 -17
  92. package/dist/server/resource-runner-supervisor.js.map +1 -0
  93. package/dist/{host → server}/rpc-bridge.d.ts +3 -3
  94. package/dist/{host → server}/rpc-bridge.js +3 -3
  95. package/dist/server/rpc-bridge.js.map +1 -0
  96. package/dist/{host → server}/rpc-executor.d.ts +1 -1
  97. package/dist/{host → server}/rpc-executor.js +3 -3
  98. package/dist/server/rpc-executor.js.map +1 -0
  99. package/dist/{host/host-entry.js → server/server-entry.js} +6 -6
  100. package/dist/server/server-entry.js.map +1 -0
  101. package/dist/{host/runner.d.ts → server/server.d.ts} +39 -38
  102. package/dist/{host/runner.js → server/server.js} +408 -374
  103. package/dist/server/server.js.map +1 -0
  104. package/dist/{host → server}/state.d.ts +25 -25
  105. package/dist/{host → server}/state.js +49 -49
  106. package/dist/server/state.js.map +1 -0
  107. package/dist/{host → server}/view.d.ts +7 -7
  108. package/dist/{host → server}/view.js +13 -13
  109. package/dist/server/view.js.map +1 -0
  110. package/dist/server/workflow-runner-content.d.ts +6 -0
  111. package/dist/server/workflow-runner-content.js +96 -0
  112. package/dist/server/workflow-runner-content.js.map +1 -0
  113. package/dist/{host/worker-entry.d.ts → server/workflow-runner-entry.d.ts} +3 -3
  114. package/dist/{host/worker-entry.js → server/workflow-runner-entry.js} +68 -35
  115. package/dist/server/workflow-runner-entry.js.map +1 -0
  116. package/dist/server/workflow-runner-protocol.d.ts +69 -0
  117. package/dist/server/workflow-runner-protocol.js +176 -0
  118. package/dist/server/workflow-runner-protocol.js.map +1 -0
  119. package/dist/{host/worker-store.d.ts → server/workflow-runner-store.d.ts} +11 -11
  120. package/dist/{host/worker-store.js → server/workflow-runner-store.js} +8 -8
  121. package/dist/server/workflow-runner-store.js.map +1 -0
  122. package/dist/server/workflow-runner-supervisor.d.ts +22 -0
  123. package/dist/server/workflow-runner-supervisor.js +56 -0
  124. package/dist/server/workflow-runner-supervisor.js.map +1 -0
  125. package/dist/state/prune.d.ts +1 -1
  126. package/dist/state/prune.js +17 -10
  127. package/dist/state/prune.js.map +1 -1
  128. package/dist/state/schema.js +2 -2
  129. package/dist/state/workflow-messages.d.ts +1 -1
  130. package/dist/state/workflow-messages.js +1 -1
  131. package/dist/state/workflow-messages.js.map +1 -1
  132. package/dist/viewer/backup.js +1 -1
  133. package/dist/viewer/backup.js.map +1 -1
  134. package/dist/viewer/cli.d.ts +2 -2
  135. package/dist/viewer/cli.js +46 -32
  136. package/dist/viewer/cli.js.map +1 -1
  137. package/dist/viewer/tui.d.ts +1 -1
  138. package/dist/viewer/tui.js +1 -1
  139. package/dist/viewer/tui.js.map +1 -1
  140. package/dist/workflows/command-batch.js +2 -2
  141. package/dist/workflows/engine.js +14 -15
  142. package/dist/workflows/engine.js.map +1 -1
  143. package/dist/workflows/store.d.ts +12 -11
  144. package/dist/workflows/store.js +24 -18
  145. package/dist/workflows/store.js.map +1 -1
  146. package/dist/workflows/types.d.ts +2 -2
  147. package/docs/2026-08-20-durable-workflow-launch-plan.md +12 -12
  148. package/docs/2026-08-25-workflow-follow-ups.md +7 -7
  149. package/docs/2026-08-25-workflow-settings.md +3 -3
  150. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
  151. package/docs/2026-09-01-restore-session-delivery-controls-plan.md +5 -5
  152. package/docs/2026-09-01-unified-workflow-client-plan.md +6 -6
  153. package/docs/2026-09-02-installed-live-e2e-plan.md +3 -3
  154. package/docs/2026-09-02-unify-workflow-messages-plan.md +8 -8
  155. package/docs/2026-09-04-workflow-run-state-plan.md +6 -6
  156. package/docs/DEFERRED_TURNS.md +7 -7
  157. package/docs/DESIGN_PHILOSOPHY.md +1 -1
  158. package/docs/HUMAN_DECISIONS.md +11 -11
  159. package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -4
  160. package/docs/MONITOR.md +1 -1
  161. package/docs/RESOURCE_MANAGERS.md +221 -0
  162. package/docs/SQLITE_STATE.md +35 -33
  163. package/docs/WORKFLOW_COMPOSITION.md +1 -1
  164. package/docs/{WORKFLOW_HOST.md → WORKFLOW_SERVER.md} +125 -119
  165. package/docs/WORKFLOW_STEP_MESSAGES.md +18 -18
  166. package/docs/WORKFLOW_UPDATES.md +16 -16
  167. package/docs/development.md +15 -14
  168. package/docs/live-replay-protocol.md +20 -20
  169. package/docs/plans/2026-08-04-controller-runtime-plan.md +25 -25
  170. package/docs/plans/2026-08-05-always-on-workflows-plan.md +8 -8
  171. package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +2 -2
  172. package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +1 -1
  173. package/docs/plans/2026-08-16-workflow-updates-plan.md +5 -5
  174. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  175. package/docs/plans/2026-08-20-bounded-command-batches-plan.md +1 -1
  176. package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +3 -3
  177. package/docs/plans/2026-08-21-sanity-check-plan.md +2 -2
  178. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +5 -5
  179. package/docs/plans/2026-08-23-sqlite-state-plan.md +25 -25
  180. package/docs/plans/2026-08-25-live-workflow-settings-plan.md +4 -4
  181. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +3 -3
  182. package/docs/plans/2026-09-04-workflow-runner-resume-state-plan.md +318 -0
  183. package/docs/plans/piw-viewer-experience-implementation-plan.md +1 -1
  184. package/docs/tui-viewer.md +9 -9
  185. package/docs/workflows.md +72 -66
  186. package/examples/{controllers/pull-request.controller.ts → resource-managers/pull-request.resource-manager.ts} +12 -12
  187. package/herdr-plugin.toml +1 -1
  188. package/package.json +5 -5
  189. package/protocol/client.v1.schema.json +7 -7
  190. package/protocol/fixtures/client-v1.json +1 -1
  191. package/src/builtins/monitor.workflow.ts +9 -9
  192. package/src/builtins/pi-agent-group.ts +3 -3
  193. package/src/channels/adapter-entry.ts +14 -14
  194. package/src/client/client.ts +33 -32
  195. package/src/client/protocol.ts +16 -11
  196. package/src/client/resolver.ts +4 -4
  197. package/src/client/view.ts +1 -1
  198. package/src/extension/index.ts +44 -34
  199. package/src/extension/recorder.ts +1 -1
  200. package/src/extension/remote-recorder-store.ts +2 -2
  201. package/src/extension/resource-manager-command.ts +45 -0
  202. package/src/extension/session-delivery.ts +2 -2
  203. package/src/extension/session-view.ts +1 -1
  204. package/src/extension/workflow-message-coordinator.ts +6 -6
  205. package/src/{controllers → resource-managers}/conditions.ts +23 -23
  206. package/src/resource-managers/definition.ts +71 -0
  207. package/src/{controllers → resource-managers}/effects.ts +9 -9
  208. package/src/resource-managers/errors.ts +27 -0
  209. package/src/resource-managers/index.ts +88 -0
  210. package/src/resource-managers/loader.ts +111 -0
  211. package/src/{controllers → resource-managers}/results.ts +4 -4
  212. package/src/{controllers/manager.ts → resource-managers/runtime.ts} +95 -92
  213. package/src/{controllers → resource-managers}/sqlite.ts +198 -186
  214. package/src/{controllers → resource-managers}/store.ts +46 -38
  215. package/src/{controllers → resource-managers}/types.ts +50 -41
  216. package/src/{controllers → resource-managers}/workflows.ts +43 -41
  217. package/src/{host → server}/channel-supervisor.ts +8 -8
  218. package/src/{host/child-worker-supervisor.ts → server/child-runner-supervisor.ts} +22 -18
  219. package/src/{host → server}/processes.ts +3 -3
  220. package/src/{host → server}/resolver-entry.ts +28 -25
  221. package/src/{host/controller-worker-entry.ts → server/resource-runner-entry.ts} +67 -65
  222. package/src/server/resource-runner-protocol.ts +103 -0
  223. package/src/server/resource-runner-supervisor.ts +76 -0
  224. package/src/{host → server}/rpc-bridge.ts +3 -3
  225. package/src/{host → server}/rpc-executor.ts +4 -4
  226. package/src/{host/host-entry.ts → server/server-entry.ts} +5 -5
  227. package/src/{host/runner.ts → server/server.ts} +526 -461
  228. package/src/{host → server}/state.ts +78 -67
  229. package/src/{host → server}/view.ts +15 -15
  230. package/src/server/workflow-runner-content.ts +119 -0
  231. package/src/{host/worker-entry.ts → server/workflow-runner-entry.ts} +98 -57
  232. package/src/server/workflow-runner-protocol.ts +241 -0
  233. package/src/{host/worker-store.ts → server/workflow-runner-store.ts} +18 -20
  234. package/src/server/workflow-runner-supervisor.ts +79 -0
  235. package/src/state/prune.ts +27 -9
  236. package/src/state/schema.ts +2 -2
  237. package/src/state/workflow-messages.ts +1 -1
  238. package/src/viewer/backup.ts +1 -1
  239. package/src/viewer/cli.ts +50 -36
  240. package/src/viewer/tui.ts +1 -1
  241. package/src/workflows/command-batch.ts +2 -2
  242. package/src/workflows/engine.ts +14 -15
  243. package/src/workflows/store.ts +31 -28
  244. package/src/workflows/types.ts +2 -2
  245. package/dist/controllers/conditions.d.ts +0 -6
  246. package/dist/controllers/conditions.js.map +0 -1
  247. package/dist/controllers/definition.d.ts +0 -6
  248. package/dist/controllers/definition.js +0 -45
  249. package/dist/controllers/definition.js.map +0 -1
  250. package/dist/controllers/effects.d.ts +0 -15
  251. package/dist/controllers/effects.js.map +0 -1
  252. package/dist/controllers/errors.d.ts +0 -12
  253. package/dist/controllers/errors.js +0 -25
  254. package/dist/controllers/errors.js.map +0 -1
  255. package/dist/controllers/index.d.ts +0 -12
  256. package/dist/controllers/index.js +0 -12
  257. package/dist/controllers/index.js.map +0 -1
  258. package/dist/controllers/json.js.map +0 -1
  259. package/dist/controllers/loader.d.ts +0 -23
  260. package/dist/controllers/loader.js +0 -74
  261. package/dist/controllers/loader.js.map +0 -1
  262. package/dist/controllers/manager.d.ts +0 -59
  263. package/dist/controllers/manager.js.map +0 -1
  264. package/dist/controllers/results.d.ts +0 -5
  265. package/dist/controllers/results.js.map +0 -1
  266. package/dist/controllers/sqlite.js.map +0 -1
  267. package/dist/controllers/workflows.d.ts +0 -34
  268. package/dist/controllers/workflows.js.map +0 -1
  269. package/dist/extension/controller-command.js.map +0 -1
  270. package/dist/host/channel-effects.js.map +0 -1
  271. package/dist/host/channel-supervisor.js.map +0 -1
  272. package/dist/host/child-worker-supervisor.js.map +0 -1
  273. package/dist/host/controller-worker-entry.d.ts +0 -2
  274. package/dist/host/controller-worker-entry.js.map +0 -1
  275. package/dist/host/controller-worker-protocol.d.ts +0 -36
  276. package/dist/host/controller-worker-protocol.js +0 -49
  277. package/dist/host/controller-worker-protocol.js.map +0 -1
  278. package/dist/host/controller-worker-supervisor.d.ts +0 -21
  279. package/dist/host/controller-worker-supervisor.js +0 -54
  280. package/dist/host/controller-worker-supervisor.js.map +0 -1
  281. package/dist/host/host-entry.js.map +0 -1
  282. package/dist/host/processes.js.map +0 -1
  283. package/dist/host/resolver-entry.js.map +0 -1
  284. package/dist/host/rpc-bridge.js.map +0 -1
  285. package/dist/host/rpc-executor.js.map +0 -1
  286. package/dist/host/runner.js.map +0 -1
  287. package/dist/host/state.js.map +0 -1
  288. package/dist/host/view.js.map +0 -1
  289. package/dist/host/worker-entry.js.map +0 -1
  290. package/dist/host/worker-protocol.d.ts +0 -46
  291. package/dist/host/worker-protocol.js +0 -122
  292. package/dist/host/worker-protocol.js.map +0 -1
  293. package/dist/host/worker-store.js.map +0 -1
  294. package/dist/host/worker-supervisor.d.ts +0 -22
  295. package/dist/host/worker-supervisor.js.map +0 -1
  296. package/docs/CONTROLLERS.md +0 -217
  297. package/src/controllers/definition.ts +0 -65
  298. package/src/controllers/errors.ts +0 -27
  299. package/src/controllers/index.ts +0 -88
  300. package/src/controllers/loader.ts +0 -104
  301. package/src/extension/controller-command.ts +0 -45
  302. package/src/host/controller-worker-protocol.ts +0 -104
  303. package/src/host/controller-worker-supervisor.ts +0 -79
  304. package/src/host/worker-protocol.ts +0 -176
  305. package/src/host/worker-supervisor.ts +0 -74
  306. /package/dist/{controllers → resource-managers}/json.d.ts +0 -0
  307. /package/dist/{controllers → resource-managers}/json.js +0 -0
  308. /package/dist/{controllers → resource-managers}/results.js +0 -0
  309. /package/dist/{controllers → resource-managers}/store.js +0 -0
  310. /package/dist/{controllers → resource-managers}/types.js +0 -0
  311. /package/dist/{host → server}/channel-effects.d.ts +0 -0
  312. /package/dist/{host → server}/channel-effects.js +0 -0
  313. /package/dist/{host/host-entry.d.ts → server/server-entry.d.ts} +0 -0
  314. /package/src/{controllers → resource-managers}/json.ts +0 -0
  315. /package/src/{host → server}/channel-effects.ts +0 -0
@@ -1,34 +1,34 @@
1
- # Workflow host
1
+ # Workflow server
2
2
 
3
- Status: the out-of-process host, unified live client, workflow-message contract, and restored session behavior are implemented. [Unify workflow run state](2026-09-04-workflow-run-state-plan.md) records the approved refactor for turn ownership, managed effects, restarts, terminal data, cancellation, and worker recovery. [Unify workflow messages and restore hosted behavior](2026-09-02-unify-workflow-messages-plan.md), [run workflows outside Pi](2026-08-30-out-of-process-workflow-host-plan.md), [restore workflow session delivery and controls](2026-09-01-restore-session-delivery-controls-plan.md), and [unify live workflow clients](2026-09-01-unified-workflow-client-plan.md) record the earlier design and implementation plans.
3
+ Status: the out-of-process server, unified live client, workflow-message contract, and restored session behavior are implemented. [Unify workflow run state](2026-09-04-workflow-run-state-plan.md) records the approved refactor for turn ownership, managed effects, restarts, terminal data, cancellation, and runner recovery. [Unify workflow messages and restore hosted behavior](2026-09-02-unify-workflow-messages-plan.md), [run workflows outside Pi](2026-08-30-out-of-process-workflow-host-plan.md), [restore workflow session delivery and controls](2026-09-01-restore-session-delivery-controls-plan.md), and [unify live workflow clients](2026-09-01-unified-workflow-client-plan.md) record the earlier design and implementation plans.
4
4
 
5
5
  ## Purpose
6
6
 
7
- The workflow host keeps durable workflow state correct when Pi, a workflow, or the host stops unexpectedly. It owns the workflow database and supervises a separate process for each active run. Pi remains the user interface and performs interactive model turns through its documented extension APIs.
7
+ The workflow server keeps durable workflow state correct when Pi, a workflow, or the server stops unexpectedly. It owns the workflow database and supervises a separate process for each active run. Pi remains the user interface and performs interactive model turns through its documented extension APIs.
8
8
 
9
- The host solves two different failures:
9
+ The server solves two different failures:
10
10
 
11
11
  - A busy workflow cannot block the process that renews run claims.
12
12
  - A crashed or stale runner cannot leave contradictory state or continue writing after another runner takes over.
13
13
 
14
14
  ## Terms
15
15
 
16
- - **Host:** The single user-level process that owns workflow state, claims, commands, and worker supervision.
17
- - **Client:** A Pi extension instance or command-line process connected to the host.
18
- - **Worker:** A child process that loads one workflow and executes one active run generation.
16
+ - **Server:** The single user-level process that owns workflow state, claims, commands, and runner supervision.
17
+ - **Client:** A Pi extension instance or command-line process connected to the server.
18
+ - **Runner:** A child process that loads one workflow and executes one active run generation.
19
19
  - **Origin session:** The Pi session that started an interactive run.
20
20
  - **Claim:** A time-limited right to change one run.
21
21
  - **Generation:** A number increased each time a new owner claims a run. It fences older owners.
22
22
  - **Durable boundary:** A committed node or lifecycle transition from which execution can resume.
23
23
  - **Interactive request:** A durable agent or assistant-message step that must run in the origin Pi session.
24
- - **Workflow message:** Host-owned content that Pi must add to an origin conversation, such as a step, reminder, decision, notification, terminal result, or follow-up.
24
+ - **Workflow message:** Server-owned content that Pi must add to an origin conversation, such as a step, reminder, decision, notification, terminal result, or follow-up.
25
25
  - **Managed effect:** A side effect reserved and settled through an idempotent durable record.
26
- - **Live run view:** The host's versioned, bounded projection of one run, including its durable state, current origin-session activity, allowed controls, and page cursors.
26
+ - **Live run view:** The server's versioned, bounded projection of one run, including its durable state, current origin-session activity, allowed controls, and page cursors.
27
27
  - **Renderer:** A Pi widget, status line, command-line view, Herdr adapter, or `piw` screen that displays or acts on a live run view without deriving workflow state.
28
28
 
29
29
  ## Boundaries
30
30
 
31
- The host belongs to the `@osolmaz/pi-workflows` package. It uses the existing SQLite database at `~/.pi/agent/workflows/state.sqlite` and documented Pi extension APIs.
31
+ The server belongs to the `@osolmaz/pi-workflows` package. It uses the existing SQLite database at `~/.pi/agent/workflows/state.sqlite` and documented Pi extension APIs.
32
32
 
33
33
  The design does not change Pi source, Pi session files, Pi message schemas, or private Pi APIs. It does not add a remote service or a second database. The package does not install an operating-system service.
34
34
 
@@ -36,46 +36,46 @@ SQLite remains local to one machine. The protocol does not provide distributed c
36
36
 
37
37
  ## Process model
38
38
 
39
- One host owns the global workflow database for one user installation.
39
+ One server owns the global workflow database for one user installation.
40
40
 
41
41
  ```text
42
42
  Pi extension ─┐
43
- CLI client ───┼── WorkflowClient v1 ── local socket ── workflow host ── SQLite
43
+ CLI client ───┼── WorkflowClient v1 ── local socket ── workflow server ── SQLite
44
44
  piw ──────────┘ │
45
- ├── run worker A
45
+ ├── workflow runner A
46
46
  Remote piw ── SSH tunnel ── loopback WebSocket relay ────────┤
47
- ├── run worker B ── headless pi --mode rpc
48
- ├── controller worker
47
+ ├── workflow runner B ── headless pi --mode rpc
48
+ ├── resource runner
49
49
  ├── channel adapter child
50
50
  └── source resolver
51
51
  ```
52
52
 
53
- The local socket and loopback WebSocket relay carry the same logical client protocol and live run view. The relay reads no state and translates no domain contract. The host is the only production process that opens the live SQLite database. Worker, channel-adapter, and source-resolver channels are private supervision protocols, not alternate client interfaces.
53
+ The local socket and loopback WebSocket relay carry the same logical client protocol and live run view. The relay reads no state and translates no domain contract. The server is the only production process that opens the live SQLite database. Runner, channel-adapter, and source-resolver channels are private supervision protocols, not alternate client interfaces.
54
54
 
55
- The host may manage runs from more than one project. Each run keeps its canonical project path and source identity.
55
+ The server may manage runs from more than one project. Each run keeps its canonical project path and source identity.
56
56
 
57
- The host process performs only bounded protocol handling, live-view projection, short SQLite transactions, timers, queue scheduling, and process supervision. It does not import or execute workflow definitions.
57
+ The server process performs only bounded protocol handling, live-view projection, short SQLite transactions, timers, queue scheduling, and process supervision. It does not import or execute workflow definitions.
58
58
 
59
- A worker loads one workflow source and executes one run generation. It cannot receive a writable `WorkflowRunStore`. It proposes changes to the host over a private child channel. This is an architectural guard against accidental writes. It is not a security sandbox against code running as the same operating-system user.
59
+ A runner loads one workflow source and executes one run generation. It cannot receive a writable `WorkflowRunStore`. It proposes changes to the server over a private child channel. This is an architectural guard against accidental writes. It is not a security sandbox against code running as the same operating-system user.
60
60
 
61
- A channel adapter child handles one approved external presentation channel. It receives only the rendered presentation and the private channel configuration needed for its work. It does not open SQLite or receive the decision subject. The host owns claims, answer verification, settlement, and process supervision.
61
+ A channel adapter child handles one approved external presentation channel. It receives only the rendered presentation and the private channel configuration needed for its work. It does not open SQLite or receive the decision subject. The server owns claims, answer verification, settlement, and process supervision.
62
62
 
63
- ## Host lifecycle
63
+ ## Server lifecycle
64
64
 
65
- The package CLI owns host lifecycle commands:
65
+ The package CLI owns server lifecycle commands:
66
66
 
67
67
  ```text
68
- pi-workflows host start
69
- pi-workflows host status
70
- pi-workflows host stop
71
- pi-workflows host run
68
+ pi-workflows server start
69
+ pi-workflows server status
70
+ pi-workflows server stop
71
+ pi-workflows server run
72
72
  ```
73
73
 
74
74
  `run` stays attached for direct operation and tests. `start` starts the package process on demand and waits for a ready handshake. It does not install systemd, launchd, or another persistent service.
75
75
 
76
- The host uses one global lock and one host epoch. Socket creation and the SQLite host claim must agree before the host accepts commands. A second live host refuses to start. After the old host lease expires, a new host increases the epoch before it handles work. Messages from an older epoch are rejected.
76
+ The server uses one global lock and one server epoch. Socket creation and the SQLite server claim must agree before the server accepts commands. A second live server refuses to start. After the old server lease expires, a new server increases the epoch before it handles work. Messages from an older epoch are rejected.
77
77
 
78
- The host stays alive while it has a connected client, an active worker, a scheduled wake, a pending controller, a pending external-channel decision, or other unsettled work. An idle host may exit after a documented idle period. A later client can start it again.
78
+ The server stays alive while it has a connected client, an active runner, a scheduled wake, a pending managed resource, a pending external-channel decision, or other unsettled work. An idle server may exit after a documented idle period. A later client can start it again.
79
79
 
80
80
  ## Claim rules
81
81
 
@@ -103,7 +103,7 @@ The transaction fails without changes when any check fails.
103
103
 
104
104
  An expired claim cannot renew itself, even when the owner ID and token hash still match. Recovery first takes a new claim and increases the generation.
105
105
 
106
- The host also renews active claims from a timer. The timer is a backup for a run with no state writes. Normal write correctness does not depend on the timer.
106
+ The server also renews active claims from a timer. The timer is a backup for a run with no state writes. Normal write correctness does not depend on the timer.
107
107
 
108
108
  Claim rejection uses `ClaimLostError` with one internal reason:
109
109
 
@@ -119,11 +119,11 @@ Logs may show the run ID, generation, and reason. They must not show a raw token
119
119
 
120
120
  The run and queue projections follow these states:
121
121
 
122
- | Run state | Queue state | Claim | Worker | Meaning |
122
+ | Run state | Queue state | Claim | Runner | Meaning |
123
123
  | ----------- | ----------- | ----- | -------- | ------------------------------------------------------- |
124
- | `queued` | `queued` | none | none | Ready for host scheduling. |
125
- | `running` | `starting` | host | starting | A worker launch is being recorded. |
126
- | `running` | `running` | host | live | A worker is executing one node. |
124
+ | `queued` | `queued` | none | none | Ready for server scheduling. |
125
+ | `running` | `starting` | host | starting | A runner launch is being recorded. |
126
+ | `running` | `running` | host | live | A runner is executing one node. |
127
127
  | `running` | `parked` | none | none | Execution stopped at a durable boundary and can resume. |
128
128
  | `waiting` | `parked` | none | none | A checkpoint or interactive request needs input. |
129
129
  | `completed` | `done` | none | none | The run finished successfully. |
@@ -131,22 +131,24 @@ The run and queue projections follow these states:
131
131
  | `timed_out` | `failed` | none | none | The run exceeded a declared timeout. |
132
132
  | `cancelled` | `cancelled` | none | none | Cancellation completed. |
133
133
 
134
+ The `host` claim-owner value and `pi-workflows.worker-launch.v1` launch schema are retained version-1 internal identifiers. They do not name public components.
135
+
134
136
  A lifecycle transaction updates the run, queue, attempt, decision, lease, event, and viewer facts that belong to one transition. The database must not commit a failed event while the run remains running, or a terminal queue row while the run remains nonterminal.
135
137
 
136
- A terminal state commits before the host builds its terminal workflow message. Missing or invalid presentation data can prevent that message, but it cannot roll back completion, failure, or cancellation. The host schedules another attempt and also finds missing terminal messages when it starts, so repaired presentation data can produce the same terminal message later.
138
+ A terminal state commits before the server builds its terminal workflow message. Missing or invalid presentation data can prevent that message, but it cannot roll back completion, failure, or cancellation. The server schedules another attempt and also finds missing terminal messages when it starts, so repaired presentation data can produce the same terminal message later.
137
139
 
138
- Waiting and paused work does not keep a worker or a live claim. Resume takes a new claim generation and starts a new worker from the last durable boundary.
140
+ Waiting and paused work does not keep a runner or a live claim. Resume takes a new claim generation and starts a new runner from the last durable boundary.
139
141
 
140
- ## Worker lifecycle
142
+ ## Runner lifecycle
141
143
 
142
- A worker launch envelope contains:
144
+ A runner launch envelope contains:
143
145
 
144
146
  ```json
145
147
  {
146
148
  "schema": "pi-workflows.worker-launch.v1",
147
149
  "runId": "run-id",
148
150
  "generation": 2,
149
- "workerEpoch": "opaque-id",
151
+ "runnerEpoch": "opaque-id",
150
152
  "projectPath": "/canonical/project/path",
151
153
  "workflowSource": {
152
154
  "root": {
@@ -162,13 +164,13 @@ A worker launch envelope contains:
162
164
  }
163
165
  ```
164
166
 
165
- Before it loads workflow modules, the worker verifies the root identity and every saved mounted file hash or built-in revision. After loading, it also checks the complete mounted-source map against the saved map. A mismatch parks the run with `workflowSourceChanged`. The normal scheduler does not claim that run again. The operator can restore the recorded source and explicitly resume the run, or cancel it. Changed included code does not execute.
167
+ Before it loads workflow modules, the runner verifies the root identity and every saved mounted file hash or built-in revision. After loading, it also checks the complete mounted-source map against the saved map. A mismatch parks the run with `workflowSourceChanged`. The normal scheduler does not claim that run again. The operator can restore the recorded source and explicitly resume the run, or cancel it. Changed included code does not execute.
166
168
 
167
- After the ready message, the host sends one explicit command: `start`, `resume`, `continue`, or `restart`. A continuation names its waiting checkpoint parent. A restart begins a new run from the workflow start. The worker never infers the command from a nullable parent ID.
169
+ After the ready message, the server sends one explicit command: `start`, `resume`, `continue`, or `restart`. A continuation names its waiting checkpoint parent. A restart begins a new run from the workflow start. The runner never infers the command from a nullable parent ID.
168
170
 
169
- The host records a worker epoch before spawn. The child must return a ready message before the startup deadline. Every later child message includes the run ID, generation, and worker epoch.
171
+ The server records a runner epoch before spawn. The child must return a ready message before the startup deadline. Every later child message includes the run ID, generation, and runner epoch.
170
172
 
171
- The host records one terminal worker outcome:
173
+ The server records one terminal runner outcome:
172
174
 
173
175
  - `exited`
174
176
  - `cancelled`
@@ -177,13 +179,13 @@ The host records one terminal worker outcome:
177
179
  - `claimLost`
178
180
  - `orphaned`
179
181
 
180
- A worker exit is not automatically a run failure. The host decides from the last committed attempt and effect state whether it can resume, must park, or must fail. If the saved run revision did not advance after the worker became ready, the host parks the run with `workerNoProgress` and does not claim it again automatically. An explicit resume can make one new attempt after the operator corrects the cause.
182
+ A runner exit is not automatically a run failure. The server decides from the last committed attempt and effect state whether it can resume, must park, or must fail. If the saved run revision did not advance after the runner became ready, the server parks the run with `runnerNoProgress` and does not claim it again automatically. An explicit resume can make one new attempt after the operator corrects the cause.
181
183
 
182
184
  ## Process supervision
183
185
 
184
- Each worker starts in its own process group. A headless Pi child starts in another process group so normal worker completion can stop all Pi tool descendants without signaling the worker itself. The worker registers that direct child with the host before it sends a prompt and unregisters it only after group shutdown. The host owns the one process registry and reaps a registered child if its worker exits first.
186
+ Each runner starts in its own process group. A headless Pi child starts in another process group so normal runner completion can stop all Pi tool descendants without signaling the runner itself. The runner registers that direct child with the server before it sends a prompt and unregisters it only after group shutdown. The server owns the one process registry and reaps a registered child if its runner exits first.
185
187
 
186
- The host enforces:
188
+ The server enforces:
187
189
 
188
190
  - a startup handshake deadline;
189
191
  - node deadlines already declared by the workflow engine;
@@ -191,18 +193,22 @@ The host enforces:
191
193
  - bounded captured stdout and stderr;
192
194
  - cancellation with `SIGTERM` and bounded `SIGKILL` escalation;
193
195
  - process-group cleanup;
194
- - orphan checks after host restart;
196
+ - orphan checks after server restart;
195
197
  - portable memory or process limits where Node and the operating system support them.
196
198
 
197
- The child protocol must apply backpressure. A child that exceeds message or output limits fails its worker epoch with a clear infrastructure reason. The complete durable workflow result stays in SQLite within the existing value limits.
199
+ The child protocol applies backpressure and has an independent 1 MiB frame limit. Before the server sends a reply, it measures the encoded response. An oversized required result is stored in the existing content-addressed blob store. The server returns a small digest-bound reference, and the runner reads and verifies the value in bounded 512 KiB parts. Missing content, bad ranges, wrong lengths, wrong digests, invalid media types, malformed JSON, and oversized errors return bounded failures. They do not crash the runner.
200
+
201
+ Execution reads are narrow. `prepareRunResume()` and continuation reads return only `WorkflowRunState`. Pi session entries, tool results, activity events, viewer history, workflow snapshots, settings, and follow-ups stay in server-owned SQLite unless one exact execution operation needs them. The runner cannot request a complete `LoadedWorkflowRun`. The server measures every runner reply, so another operation cannot silently cross the frame limit.
202
+
203
+ The full logical result and request receipt remain durable for repeat handling. Matching repeated requests return the same value or content reference. Normal blob pruning removes unreferenced transfer content. Viewer history continues through its separate bounded page and content-reference interface.
198
204
 
199
- The process registry includes a process start identity, not only a PID. The host accepts a worker registration only when the PID is a direct child of that active worker. A reused PID cannot let a new host kill an unrelated process.
205
+ The process registry includes a process start identity, not only a PID. The server accepts a runner registration only when the PID is a direct child of that active runner. A reused PID cannot let a new server kill an unrelated process.
200
206
 
201
207
  ## Live client protocol
202
208
 
203
209
  Every production client uses one versioned `WorkflowClient` protocol. No extension, CLI command, Herdr adapter, or `piw` mode opens the live SQLite database. Clients connect through a user-only local socket. Unix socket mode is `0600`. Other platforms use their equivalent local transport and access control. Remote viewing uses a loopback-only WebSocket relay through an SSH tunnel. The relay carries the same messages and does not read SQLite.
204
210
 
205
- The alpha hard cut replaces the existing host request and replay protocols in place with `pi-workflows.client.v1`. It adds no `v2`, compatibility path, fallback reader, or second live protocol. One neutral JSON schema is the wire-contract source for TypeScript and Rust. Shared conformance fixtures must pass in both languages.
211
+ The alpha hard cut replaces the existing server request and replay protocols in place with `pi-workflows.client.v1`. It adds no `v2`, compatibility path, fallback reader, or second live protocol. One neutral JSON schema is the wire-contract source for TypeScript and Rust. Shared conformance fixtures must pass in both languages.
206
212
 
207
213
  Messages use newline-delimited canonical JSON on the local socket and one canonical JSON object per WebSocket message. TypeScript and Rust use the same ECMAScript number formatting and UTF-16 object-key order for canonical JSON. Both parsers reject unknown envelope fields and non-canonical framing. One message is at most 1 MiB, matching the existing durable event limit. The receiver closes only the offending connection when framing or validation fails.
208
214
 
@@ -224,70 +230,70 @@ Each message uses one envelope:
224
230
 
225
231
  The `type` is `hello`, `request`, `response`, or `event`. A response repeats the request ID and includes its outcome, revision, receipt, or bounded safe error. An event names its subscription and carries one revisioned run-list snapshot, run-view snapshot, patch, page, origin-session workflow-message change, or availability change. Valid command outcomes remain `accepted`, `adopted`, `rejected`, `conflict`, `notFound`, `claimLost`, and `unavailable`.
226
232
 
227
- The host commits a command receipt before it acknowledges success. The request ID identifies one transport attempt and is excluded from the durable fingerprint. The Pi extension sends state-changing commands through the durable client path. If a connection closes after commit but before response, a retry uses a new request ID with the same client ID, idempotency key, operation, and payload, then adopts the stored receipt. Reusing a request ID or idempotency key with another durable payload returns a conflict. An `interaction.submit` response stays pending while the supervised child validates the value and settles only after the durable outcome is `accepted`, `adopted`, or `rejected`. A reconnect with the same durable identity and payload waits for and returns that same outcome. Clients do not poll SQLite for submission results.
233
+ The server commits a command receipt before it acknowledges success. The request ID identifies one transport attempt and is excluded from the durable fingerprint. The Pi extension sends state-changing commands through the durable client path. If a connection closes after commit but before response, a retry uses a new request ID with the same client ID, idempotency key, operation, and payload, then adopts the stored receipt. Reusing a request ID or idempotency key with another durable payload returns a conflict. An `interaction.submit` response stays pending while the supervised child validates the value and settles only after the durable outcome is `accepted`, `adopted`, or `rejected`. A reconnect with the same durable identity and payload waits for and returns that same outcome. Clients do not poll SQLite for submission results.
228
234
 
229
- View and subscription reads do not create receipts. Reconnection restores desired subscriptions from the last accepted presentation revision. A retained revision receives patches. A stale revision receives a bounded snapshot. A slow subscriber gets at most one socket-buffered snapshot at a time because the host waits for drain and coalesces later polls. A backpressured client write stops waiting when its connection closes, its socket fails, or its request is cancelled. Every explicit client unsubscribe removes the matching host subscription, including run-list and origin-session subscriptions.
235
+ View and subscription reads do not create receipts. Reconnection restores desired subscriptions from the last accepted presentation revision. A retained revision receives patches. A stale revision receives a bounded snapshot. A slow subscriber gets at most one socket-buffered snapshot at a time because the server waits for drain and coalesces later polls. A backpressured client write stops waiting when its connection closes, its socket fails, or its request is cancelled. Every explicit client unsubscribe removes the matching server subscription, including run-list and origin-session subscriptions.
230
236
 
231
237
  The protocol owns four operation groups:
232
238
 
233
- - run and controller commands, including start, pause, resume, cancel, restart, decisions, updates, submissions, settings, follow-ups, reconciliation, and host control;
239
+ - run and resource manager commands, including start, pause, resume, cancel, restart, decisions, updates, submissions, settings, follow-ups, reconciliation, and server control;
234
240
  - live views and recording, including run lists, snapshots, subscriptions, pages, referenced content, origin-session workflow messages, terminal-view clear, and batched session events;
235
241
  - active-branch and model-turn reports;
236
- - state and channel maintenance, including status, verification, backup, prune, channel status, channel reload, and explicit channel recovery against the active database. Backup and applied prune use one fresh CLI idempotency key per user invocation. An automatic reconnect retry keeps that key and uses a new request ID. A later invocation gets a new key. The host finishes an in-flight operation after a disconnect, stores its accepted or rejected receipt before response, waits for it during shutdown, and adopts an exact retry.
242
+ - state and channel maintenance, including status, verification, backup, prune, channel status, channel reload, and explicit channel recovery against the active database. Backup and applied prune use one fresh CLI idempotency key per user invocation. An automatic reconnect retry keeps that key and uses a new request ID. A later invocation gets a new key. The server finishes an in-flight operation after a disconnect, stores its accepted or rejected receipt before response, waits for it during shutdown, and adopts an exact retry.
237
243
 
238
- `workflowMessage.reportBranch` reports workflow message IDs and Pi entry IDs from the complete origin-session view window together with `isIdle` and `hasPendingMessages`. The host adopts matching entries, changes a matching pending or cancelled message to `sent`, closes proved-lost turns, and creates one missing message of the source's own kind after a branch change. `workflowTurn.report` records exact model-turn starts and ends. The host keeps one active coordinator connection and process-local epoch for each origin session. A replacement connection fences the old one. Only the active epoch receives the next eligible pending message or can report branch and turn state. Polling alone creates no durable command.
244
+ `workflowMessage.reportBranch` reports workflow message IDs and Pi entry IDs from the complete origin-session view window together with `isIdle` and `hasPendingMessages`. The server adopts matching entries, changes a matching pending or cancelled message to `sent`, closes proved-lost turns, and creates one missing message of the source's own kind after a branch change. `workflowTurn.report` records exact model-turn starts and ends. The server keeps one active coordinator connection and process-local epoch for each origin session. A replacement connection fences the old one. Only the active epoch receives the next eligible pending message or can report branch and turn state. Polling alone creates no durable command.
239
245
 
240
246
  ### Live run view
241
247
 
242
- The host returns one canonical `pi-workflows.run-view.v1` document. It contains the existing bounded workflow projection and page cursors plus a `display` object. The queue field contains display metadata only. It does not repeat the input, launch options, worker affinity, or claim capability; the complete input remains reachable through the state projection. The `display` object contains the effective status, current activity kind, allowed controls, and the stored reason when action is required. A reason above the shared 16 KiB inline-content threshold uses a small `reason` notice and a digest-bound `reasonContent` reference, so one diagnostic cannot exceed the 1 MiB protocol frame while the complete reason remains available. Renderers use this object directly. They must not combine separate queries or infer status from durable rows.
248
+ The server returns one canonical `pi-workflows.run-view.v1` document. It contains the existing bounded workflow projection and page cursors plus a `display` object. The queue field contains display metadata only. It does not repeat the input, launch options, runner affinity, or claim capability; the complete input remains reachable through the state projection. The `display` object contains the effective status, current activity kind, allowed controls, and the stored reason when action is required. A reason above the shared 16 KiB inline-content threshold uses a small `reason` notice and a digest-bound `reasonContent` reference, so one diagnostic cannot exceed the 1 MiB protocol frame while the complete reason remains available. Renderers use this object directly. They must not combine separate queries or infer status from durable rows.
243
249
 
244
- The unfinished node-attempt row is the one durable source for the current node. A running run exposes it as `currentNode`. A parked interactive run exposes the same node as `waitingOn`. A checkpoint has no unfinished attempt, so its completed checkpoint node supplies `waitingOn`. During an exact origin-session model turn, the host `display` changes that waiting node to running for presentation only. It does not infer another node or change the durable run state.
250
+ The unfinished node-attempt row is the one durable source for the current node. A running run exposes it as `currentNode`. A parked interactive run exposes the same node as `waitingOn`. A checkpoint has no unfinished attempt, so its completed checkpoint node supplies `waitingOn`. During an exact origin-session model turn, the server `display` changes that waiting node to running for presentation only. It does not infer another node or change the durable run state.
245
251
 
246
252
  Generated referenced content is stored directly in `run_view_content` under its exact run ID, content digest, and media type. It does not share general state-blob media metadata. A content read must match all three values, so a reference from another run or another media representation is unavailable.
247
253
 
248
254
  The origin-session response contains the active run view. When no run is active, it keeps the most recent terminal run visible while its terminal workflow message is pending or its first model turn is open, and then for 60 seconds after that turn ends. A newer run or `sessionView.clearTerminal` removes the retained terminal view. `/workflow clear` and the matching `piw` action call that control without changing workflow state.
249
255
 
250
- The response also contains an ordered byte-bounded window of all nonterminal workflow messages and open sent messages needed for recovery, their complete count, and the next eligible pending message ID only for the active coordinator epoch. Message records include the source, content reference, order, state, and Pi entry needed by the shared coordinator. A branch report can name only IDs from this complete window. The host returns all these facts from one consistent read. The extension materializes the complete run revision and message content before it updates the widget or coordinator. After every host connection, it reports the active branch before it sends a workflow message or reports a model turn. Polling an idle session creates no durable command.
256
+ The response also contains an ordered byte-bounded window of all nonterminal workflow messages and open sent messages needed for recovery, their complete count, and the next eligible pending message ID only for the active coordinator epoch. Message records include the source, content reference, order, state, and Pi entry needed by the shared coordinator. A branch report can name only IDs from this complete window. The server returns all these facts from one consistent read. The extension materializes the complete run revision and message content before it updates the widget or coordinator. After every server connection, it reports the active branch before it sends a workflow message or reports a model turn. Polling an idle session creates no durable command.
251
257
 
252
- Each history page has both an item limit and an encoded byte budget. Oversized values become digest-bound content references. Large workflow topology uses bounded node, edge, graph-step, and transition projections plus references for the complete original definition and complete graph history. Before the host advertises a generated reference, it stores the bytes under the exact run ID, content digest, and media type in `run_view_content`. It does not share media metadata with general state blobs. Memory-cache eviction cannot make a reference unavailable. `view.content` returns bounded chunks until the client has the complete value. The client verifies the assembled bytes against both the response digest and the digest in the advertised reference. TypeScript clients assemble every run-history page for one revision and hydrate the complete definition, complete graph history, and all referenced content before they emit a complete non-interactive view or update the Pi widget. Rust automatically requests and verifies the complete referenced definition and graph history, decodes the complete values, and then builds its graph layout. Session-event pages include the replay checkpoint immediately before the first event in the page. A large checkpoint is also a referenced value. TypeScript hydrates it with the run view, and Rust requests and resolves it before replay. A step-centered trace page selects the exact stored attempt first and uses the node ID only if that attempt has no trace event. The run list reads only status facts and never loads complete run histories.
258
+ Each history page has both an item limit and an encoded byte budget. Oversized values become digest-bound content references. Large workflow topology uses bounded node, edge, graph-step, and transition projections plus references for the complete original definition and complete graph history. Before the server advertises a generated reference, it stores the bytes under the exact run ID, content digest, and media type in `run_view_content`. It does not share media metadata with general state blobs. Memory-cache eviction cannot make a reference unavailable. `view.content` returns bounded chunks until the client has the complete value. The client verifies the assembled bytes against both the response digest and the digest in the advertised reference. TypeScript clients assemble every run-history page for one revision and hydrate the complete definition, complete graph history, and all referenced content before they emit a complete non-interactive view or update the Pi widget. Rust automatically requests and verifies the complete referenced definition and graph history, decodes the complete values, and then builds its graph layout. Session-event pages include the replay checkpoint immediately before the first event in the page. A large checkpoint is also a referenced value. TypeScript hydrates it with the run view, and Rust requests and resolves it before replay. A step-centered trace page selects the exact stored attempt first and uses the node ID only if that attempt has no trace event. The run list reads only status facts and never loads complete run histories.
253
259
 
254
260
  The closed `display.status` set is `queued`, `running`, `waiting`, `paused`, `completed`, `failed`, `timed_out`, `cancelled`, and `ambiguous`.
255
261
 
256
- The host computes effective status in this order:
262
+ The server computes effective status in this order:
257
263
 
258
- 1. A durable ambiguous external effect that requires explicit review is `ambiguous`. An effect that is still applying under a live worker is not ambiguous.
259
- 2. A live supervised worker or an exact active origin-session workflow turn is `running`.
264
+ 1. A durable ambiguous external effect that requires explicit review is `ambiguous`. An effect that is still applying under a live runner is not ambiguous.
265
+ 2. A live supervised runner or an exact active origin-session workflow turn is `running`.
260
266
  3. A durable terminal result keeps its terminal label after its presentation turn ends.
261
267
  4. A durable pause is `paused` after its active Pi turn ends.
262
268
  5. A pending interaction, decision, or presentation with no exact active turn is `waiting`.
263
269
  6. Parked resumable work with no pending interaction is `queued`.
264
270
  7. Admitted work that has not started is `queued`.
265
271
 
266
- Host connection failure is the client condition `unavailable`, not a `display.status` value. `paused` is never inferred from a parked queue, pending interaction, stale cursor, or missing activity report.
272
+ Server connection failure is the client condition `unavailable`, not a `display.status` value. `paused` is never inferred from a parked queue, pending interaction, stale cursor, or missing activity report.
267
273
 
268
274
  ### Origin-session activity
269
275
 
270
- `agent_start` has no message payload. The extension binds it through the current origin-session view. The latest sent step is open while its interaction remains pending and its run is not paused. Any turn that starts in that state is workflow work. A terminal or follow-up message is open only until its first turn ends. Decisions and notifications never open a turn. The host rejects a start against a closed message.
276
+ `agent_start` has no message payload. The extension binds it through the current origin-session view. The latest sent step is open while its interaction remains pending and its run is not paused. Any turn that starts in that state is workflow work. A terminal or follow-up message is open only until its first turn ends. Decisions and notifications never open a turn. The server rejects a start against a closed message.
271
277
 
272
- Each report names the sent workflow message, workflow turn ID, run, and origin session. The extension creates the turn ID at start and keeps it through the matching end and host reconnect. If the session view or message receipt is still loading, it buffers start and end and reports them in order when the message becomes available.
278
+ Each report names the sent workflow message, workflow turn ID, run, and origin session. The extension creates the turn ID at start and keeps it through the matching end and server reconnect. If the session view or message receipt is still loading, it buffers start and end and reports them in order when the message becomes available.
273
279
 
274
- At `agent_end`, the extension derives `completed`, `aborted`, or `error` from the documented assistant messages. It reads response-entry evidence from `ctx.sessionManager.getBranch()`; the entry ID can be null. The host applies the end, activity update, pause, unproductive-turn counter, and pending step-message cancellation in one transaction. A repeated report adopts that result. A stale turn ID cannot clear newer activity.
280
+ At `agent_end`, the extension derives `completed`, `aborted`, or `error` from the documented assistant messages. It reads response-entry evidence from `ctx.sessionManager.getBranch()`; the entry ID can be null. The server applies the end, activity update, pause, unproductive-turn counter, and pending step-message cancellation in one transaction. A repeated report adopts that result. A stale turn ID cannot clear newer activity.
275
281
 
276
282
  An aborted turn sets the run pause, cancels pending step messages, and does not increment `unproductiveTurnEnds`. The interaction derives its paused state from the run. Resuming that submitted-output step atomically clears the pause, increments the interaction revision, and creates one step message with reason `resumed`. Pi starts a fresh model turn from that message. A protected decision does not start a model turn, so pause and resume do not change its interaction revision or create another decision message. A completed, recoverably failed, or proved-lost turn increments the counter only when the submitted-output step remains pending, not paused, and has no accepted or validating submission. Values one and two create one step message with reason `reminder`; a value above two fails the attempt. At most one pending reminder-reason step exists. Acceptance, pause, cancellation, timeout, and branch re-presentation cancel pending step messages.
277
283
 
278
- The process-local coordinator epoch ends on client disconnect, but an open reported workflow turn does not end. Host startup does not close Pi turns. On `session_start`, `workflowMessage.reportBranch` closes an unended open message as `lost` only when Pi is idle. A busy Pi session re-reports the same started turn. A lost step follows the unproductive-turn rule. A lost terminal or follow-up closes after its first turn. Follow-up activity controls ordering but does not show the completed workflow as `running`. Activity cannot grant workflow authority or settle a workflow request.
284
+ The process-local coordinator epoch ends on client disconnect, but an open reported workflow turn does not end. Server startup does not close Pi turns. On `session_start`, `workflowMessage.reportBranch` closes an unended open message as `lost` only when Pi is idle. A busy Pi session re-reports the same started turn. A lost step follows the unproductive-turn rule. A lost terminal or follow-up closes after its first turn. Follow-up activity controls ordering but does not show the completed workflow as `running`. Activity cannot grant workflow authority or settle a workflow request.
279
285
 
280
286
  ### Renderers and controls
281
287
 
282
288
  The Pi widget, Pi status line, `/piw`, `Ctrl+Shift+R`, Herdr placement adapter, CLI status output, and every local or remote `piw` screen consume the same live run view. The Pi extension subscribes by origin session and materializes the complete step history before it renders the widget. The Herdr adapter receives the exact run target from that view and owns only pane placement and focus. The TypeScript CLI and Rust TUI subscribe by run ID and use protocol pages and referenced content. Explicit `piw <runId>` mode keeps the requested run selected and does not replace it with the newest run-list item. They do not open live SQLite or compile or validate its DDL digest.
283
289
 
284
- Local `piw` may start the host only by executing the installed `pi-workflows host start` command. It does not reimplement host lifecycle. A foreground TypeScript client keeps its cold-start retry timer referenced until the host is ready or the start deadline expires. It uses the package socket on Unix and the same package-derived named pipe as TypeScript on Windows. `piw serve` becomes a loopback WebSocket relay for the same client protocol. It opens one host socket connection for each WebSocket connection and couples their lifecycles one to one. It never multiplexes clients, translates state, or opens the database. A client that cannot start or reach the matching host fails with one clear unavailable or package-version error. It must not fall back to direct SQLite access.
290
+ Local `piw` may start the server only by executing the installed `pi-workflows server start` command. It does not reimplement server lifecycle. A foreground TypeScript client keeps its cold-start retry timer referenced until the server is ready or the start deadline expires. It uses the package socket on Unix and the same package-derived named pipe as TypeScript on Windows. `piw serve` becomes a loopback WebSocket relay for the same client protocol. It opens one server socket connection for each WebSocket connection and couples their lifecycles one to one. It never multiplexes clients, translates state, or opens the database. A client that cannot start or reach the matching server fails with one clear unavailable or package-version error. It must not fall back to direct SQLite access.
285
291
 
286
- ## Worker protocol
292
+ ## Runner protocol
287
293
 
288
- The private worker channel accepts these message kinds:
294
+ The private runner channel accepts these message kinds:
289
295
 
290
- - `worker.ready`
296
+ - `runner.ready`
291
297
  - `node.started`
292
298
  - `node.update`
293
299
  - `node.finished`
@@ -301,16 +307,16 @@ The private worker channel accepts these message kinds:
301
307
  - `presentation.requested`
302
308
  - `effect.reserve`
303
309
  - `effect.settle`
304
- - `worker.progress`
305
- - `worker.exiting`
310
+ - `runner.progress`
311
+ - `runner.exiting`
306
312
 
307
- Every worker message includes the worker launch schema, run ID, generation, worker epoch, attempt ID when applicable, expected revision, and a stable message ID. Headless workers use `process.register` and `process.unregister` operations under `worker.progress` to attach their Pi child group to host supervision. Registration requires the live run claim. Unregistration remains valid after a terminal state releases that claim so cleanup can finish.
313
+ Every runner message includes the runner launch schema, run ID, generation, runner epoch, attempt ID when applicable, expected revision, and a stable message ID. Headless runners use `process.register` and `process.unregister` operations under `runner.progress` to attach their Pi child group to server supervision. Registration requires the live run claim. Unregistration remains valid after a terminal state releases that claim so cleanup can finish.
308
314
 
309
- The host checks the generation and epoch before it reads the payload. A stale worker gets one claim-loss response and must exit. The host stores receipts for accepted state-changing messages so a retry receives the same answer.
315
+ The server checks the generation and epoch before it reads the payload. A stale runner gets one claim-loss response and must exit. The server stores receipts for accepted state-changing messages so a retry receives the same answer.
310
316
 
311
317
  ## Supervised channel adapters
312
318
 
313
- The host launches one transport-only child for each configured Telegram profile. The child receives only the complete operator presentation, allowed Telegram identities, and the one profile credential that it needs. It does not receive the canonical decision subject, open SQLite, load workflow code, or change run state.
319
+ The server launches one transport-only child for each configured Telegram profile. The child receives only the complete operator presentation, allowed Telegram identities, and the one profile credential that it needs. It does not receive the canonical decision subject, open SQLite, load workflow code, or change run state.
314
320
 
315
321
  The private version-1 channel protocol has these message kinds:
316
322
 
@@ -320,9 +326,9 @@ The private version-1 channel protocol has these message kinds:
320
326
  - `channel.settle`; and
321
327
  - `channel.exiting`.
322
328
 
323
- Each message includes the adapter epoch, profile, sequence, expected channel revision, and stable attempt ID. The host validates these values before it accepts a result or answer. A stale adapter or stale attempt cannot settle newer work.
329
+ Each message includes the adapter epoch, profile, sequence, expected channel revision, and stable attempt ID. The server validates these values before it accepts a result or answer. A stale adapter or stale attempt cannot settle newer work.
324
330
 
325
- Before the child sends or edits an external message, the host records a managed effect in `effects` and `effect_attempts`. A confirmed result stores its Telegram message references in the effect result. A known rejection can start a bounded new attempt. If the host or adapter stops while an exact attempt is applying, only that in-flight attempt becomes `ambiguous`; the host does not send it again automatically.
331
+ Before the child sends or edits an external message, the server records a managed effect in `effects` and `effect_attempts`. A confirmed result stores its Telegram message references in the effect result. A known rejection can start a bounded new attempt. If the server or adapter stops while an exact attempt is applying, only that in-flight attempt becomes `ambiguous`; the server does not send it again automatically.
326
332
 
327
333
  The operator checks Telegram before resolving an ambiguous attempt. `/workflow-channel recover <message-id> confirm` records that the external work happened. `/workflow-channel recover <message-id> retry` starts a new numbered attempt and warns that a duplicate is possible. `channel_messages` remains the decision feature record for delivery and settlement; it does not duplicate the external-effect state or Telegram references.
328
334
 
@@ -337,11 +343,11 @@ Reuse current rows when they already own a fact:
337
343
  - `workflow_messages` owns all content that Pi must add to an origin conversation.
338
344
  - `run_bindings` owns origin session and execution mode.
339
345
 
340
- `workflow_messages` contains the target session, message kind, source record, content digest, session order, state, confirmed Pi entry ID, and timestamps. Its states are `pending`, `sent`, and `cancelled`; it has no separate sent timestamp. Active-branch evidence changes a matching pending or cancelled message to `sent`. Message kind determines its renderer, turn behavior, and host eligibility rule. A partial unique index allows at most one pending step message for one interactive request. The table stores no sender, send lease, duplicate flag, or message-to-message pointer.
346
+ `workflow_messages` contains the target session, message kind, source record, content digest, session order, state, confirmed Pi entry ID, and timestamps. Its states are `pending`, `sent`, and `cancelled`; it has no separate sent timestamp. Active-branch evidence changes a matching pending or cancelled message to `sent`. Message kind determines its renderer, turn behavior, and server eligibility rule. A partial unique index allows at most one pending step message for one interactive request. The table stores no sender, send lease, duplicate flag, or message-to-message pointer.
341
347
 
342
348
  Add only these records if implementation proves the current rows cannot hold the contract:
343
349
 
344
- ### Host commands
350
+ ### Server commands
345
351
 
346
352
  `host_commands` stores request ID, client ID, operation, idempotency key, durable request fingerprint, run ID, accepted revision, outcome, receipt or error hash, and timestamps. The request ID is transport identity and is not part of the fingerprint. The request primary key prevents one request ID from naming two payloads. The client and idempotency-key uniqueness adopts the same durable payload across transport attempts.
347
353
 
@@ -351,9 +357,9 @@ Add only these records if implementation proves the current rows cannot hold the
351
357
 
352
358
  `interactive_submissions` stores request ID, submission ID, idempotency key, payload hash, validating, accepted, or rejected outcome, receipt hash, and submission time. Repeated keys return the same receipt.
353
359
 
354
- ### Worker epochs
360
+ ### Runner epochs
355
361
 
356
- `run_workers` stores run ID, generation, worker epoch, launch envelope hash, process identity, status, start time, ready time, finish time, exit code, signal, and bounded diagnostic hash. One run and generation can have several sequential worker epochs, but only one may be active.
362
+ `run_workers` stores run ID, generation, runner epoch, launch envelope hash, process identity, status, start time, ready time, finish time, exit code, signal, and bounded diagnostic hash. One run and generation can have several sequential runner epochs, but only one may be active.
357
363
 
358
364
  These tables remain part of `pi-workflows-state` schema version 1. The DDL digest changes in place under the alpha policy.
359
365
 
@@ -361,27 +367,27 @@ These tables remain part of `pi-workflows-state` schema version 1. The DDL diges
361
367
 
362
368
  Agent and assistant-message steps for an interactive run execute in the origin Pi session.
363
369
 
364
- The worker commits the node's resolved wall-clock deadline before it proposes `interaction.requested`. The host commits the request, changes the node attempt to waiting, parks the queue row, releases the claim, and acknowledges the worker. The worker then exits. The host continues to enforce the durable deadline while no worker exists. If the deadline passes, one control claim atomically closes the stale request and schedules a supervised timeout-resume child. The child preserves the same attempt and deadline, records `timed_out`, and follows any `$result.outcome` edge. A run with no timeout recovery edge becomes terminal and releases its session reservation. Restart recovery starts this timeout path before it schedules other work.
370
+ The runner commits the node's resolved wall-clock deadline before it proposes `interaction.requested`. The server commits the request, changes the node attempt to waiting, parks the queue row, releases the claim, and acknowledges the runner. The runner then exits. The server continues to enforce the durable deadline while no runner exists. If the deadline passes, one control claim atomically closes the stale request and schedules a supervised timeout-resume child. The child preserves the same attempt and deadline, records `timed_out`, and follows any `$result.outcome` edge. A run with no timeout recovery edge becomes terminal and releases its session reservation. Restart recovery starts this timeout path before it schedules other work.
365
371
 
366
- The extension finds eligible workflow messages during `session_start`, after model turns settle, and once per second while the session is open. The same poll also establishes the one session subscription when initial host startup or connection fails. It keeps at most one connection attempt and one active subscription, so the open Pi session recovers without a restart and without duplicate coordinators. One `WorkflowMessageCoordinator` handles every message kind. After every host connection, it waits for the complete origin-session view and reports the active branch before it sends a workflow message or reports a model turn. The host view names the next eligible pending message only to the active coordinator epoch.
372
+ The extension finds eligible workflow messages during `session_start`, after model turns settle, and once per second while the session is open. The same poll also establishes the one session subscription when initial server startup or connection fails. It keeps at most one connection attempt and one active subscription, so the open Pi session recovers without a restart and without duplicate coordinators. One `WorkflowMessageCoordinator` handles every message kind. After every server connection, it waits for the complete origin-session view and reports the active branch before it sends a workflow message or reports a model turn. The server view names the next eligible pending message only to the active coordinator epoch.
367
373
 
368
374
  The coordinator waits until Pi is idle and has no queued user input, keeps the message ID in its in-memory queued map, and searches the active branch for that hidden ID. It reports a matching entry before any send. Otherwise, it rechecks synchronously that Pi is idle, has no pending input, the message is absent, and its connection still owns the active epoch. It calls documented `pi.sendMessage()` with no `await` between the final check and call. A poll can discover work, but it cannot send an ID already in the queued map.
369
375
 
370
- After a send, the coordinator waits for the matching Pi entry and reports the active branch so the host records its entry ID and marks the message `sent`. Branch evidence marks a matching message `sent` even if its source cancelled it after the send. If Pi emits `agent_start` before that report or before the session view loads, the coordinator buffers the start and matching end, records the message first, and then reports the turn events in order.
376
+ After a send, the coordinator waits for the matching Pi entry and reports the active branch so the server records its entry ID and marks the message `sent`. Branch evidence marks a matching message `sent` even if its source cancelled it after the send. If Pi emits `agent_start` before that report or before the session view loads, the coordinator buffers the start and matching end, records the message first, and then reports the turn events in order.
371
377
 
372
- The host alone decides whether that Pi model turn belongs to the workflow message. `workflowTurn.report` returns a version-1 receipt with `active`, `settled`, or `absent` ownership and the exact saved turn when one exists. The extension exposes workflow activity and starts session capture only after an `active` receipt. It clears its temporary copy after settlement, rejection, or disconnect. Every new Pi `agent_start` replaces any older local copy and requires fresh host acceptance before the turn can become workflow work.
378
+ The server alone decides whether that Pi model turn belongs to the workflow message. `workflowTurn.report` returns a version-1 receipt with `active`, `settled`, or `absent` ownership and the exact saved turn when one exists. The extension exposes workflow activity and starts session capture only after an `active` receipt. It clears its temporary copy after settlement, rejection, or disconnect. Every new Pi `agent_start` replaces any older local copy and requires fresh server acceptance before the turn can become workflow work.
373
379
 
374
380
  Turn start and end use the exact message, run, session, and turn IDs. A matching repeat adopts the saved result. A conflicting repeat remains an error. When a run becomes terminal, the same transaction ends its open turns as `lost` and cancels pending step and decision messages. Failure and cancellation also cancel pending follow-ups. A committed notification stays eligible for delivery. A late matching end report adopts that terminal cleanup. A terminal run cannot start another step turn, and a later ordinary Pi turn cannot inherit its old workflow ownership.
375
381
 
376
- Active-branch absence is usable only when the branch has no matching ID, Pi is idle, and Pi has no pending messages. If Pi or the extension disappears after the send call but before inspection, the message stays `pending`. A replacement extension reports the branch before another send. The idle branch report settles an unproved open host turn as `lost`. Documented Pi APIs do not prove cross-branch absence or exactly-once model execution.
382
+ Active-branch absence is usable only when the branch has no matching ID, Pi is idle, and Pi has no pending messages. If Pi or the extension disappears after the send call but before inspection, the message stays `pending`. A replacement extension reports the branch before another send. The idle branch report settles an unproved open server turn as `lost`. Documented Pi APIs do not prove cross-branch absence or exactly-once model execution.
377
383
 
378
384
  The extension subscribes to the active origin-session live run view and projects it into Pi's documented widget and status APIs. It never opens SQLite, runs workflow code, or derives a display status. `Shift+Up` and `Shift+Down` scroll the widget. When Herdr is available, the widget also shows `Ctrl+Shift+R piw`, and `/piw` remains the command fallback. Both actions open or focus the exact run from the same view.
379
385
 
380
- A tool update or submission goes to the host. It includes the exact request, node, attempt, expected revision, and tool-call idempotency key. The host first checks this transport contract and records a provisional `validating` submission. It then schedules a supervised workflow child. Only that child loads workflow code and runs the node's `validate` function. The child reports `interaction.accepted` or `interaction.rejected` to the host. The host settles the request only after acceptance. A rejected payload leaves the same request pending and returns the stored actionable error to the model. If the child stops before it reports a result, the host rejects the provisional submission and leaves the request ready for a corrected retry.
386
+ A tool update or submission goes to the server. It includes the exact request, node, attempt, expected revision, and tool-call idempotency key. The server first checks this transport contract and records a provisional `validating` submission. It then schedules a supervised workflow child. Only that child loads workflow code and runs the node's `validate` function. The child reports `interaction.accepted` or `interaction.rejected` to the server. The server settles the request only after acceptance. A rejected payload leaves the same request pending and returns the stored actionable error to the model. If the child stops before it reports a result, the server rejects the provisional submission and leaves the request ready for a corrected retry.
381
387
 
382
- An ordinary checkpoint accepts the model-facing `answer` action and starts a continuation run. A protected human decision never accepts that tool action. The extension displays the decision without starting a model turn, and a person answers it with `/workflow answer` through `decision.answer`. When a protected decision reaches its saved `onTimeout` deadline, the host takes a control claim on the waiting parent, atomically records the validated default, closes the pending interaction, releases the parent claim, and reserves the continuation. A human answer cannot win after that deadline.
388
+ An ordinary checkpoint accepts the model-facing `answer` action and starts a continuation run. A protected human decision never accepts that tool action. The extension displays the decision without starting a model turn, and a person answers it with `/workflow answer` through `decision.answer`. When a protected decision reaches its saved `onTimeout` deadline, the server takes a control claim on the waiting parent, atomically records the validated default, closes the pending interaction, releases the parent claim, and reserves the continuation. A human answer cannot win after that deadline.
383
389
 
384
- The session keeps normal Pi entries for prompts, tools, and replies. Pi Workflows stores the public session entry ID used for presentation adoption. It does not edit the Pi session file or schema. A normal worker continuation leaves an active session capture open until the matching Pi turn ends. Only proved interruption can fail that capture; worker handoff alone cannot report that the host stopped.
390
+ The session keeps normal Pi entries for prompts, tools, and replies. Pi Workflows stores the public session entry ID used for presentation adoption. It does not edit the Pi session file or schema. A normal runner continuation leaves an active session capture open until the matching Pi turn ends. Only proved interruption can fail that capture; runner handoff alone cannot report that the server stopped.
385
391
 
386
392
  One session sends one workflow message at a time. Messages keep acceptance order, but an earlier ineligible or cancelled message does not block unrelated eligible work. Source state and message kind decide eligibility. A reload clears only process-local queued state. `workflowMessage.reportBranch` adopts existing entries and closes lost turns. When a pending source has no entry on the active branch, it creates one message of that source's own kind: a step with reason `resumed` for an interaction, or a decision for a protected decision. Repeating a report or returning to a branch that already contains that source creates no new message.
387
393
 
@@ -389,7 +395,7 @@ A notify node creates a passive `notification` message in the same transaction a
389
395
 
390
396
  ## Detached execution
391
397
 
392
- A run with headless execution mode uses the existing `pi --mode rpc` integration for agent steps. The Pi child uses a separate process group registered with the host. The worker stops that group during normal completion. Cancellation gives the worker a bounded cleanup interval, and the host reaps the registered group if the worker exits first.
398
+ A run with headless execution mode uses the existing `pi --mode rpc` integration for agent steps. The Pi child uses a separate process group registered with the server. The runner stops that group during normal completion. Cancellation gives the runner a bounded cleanup interval, and the server reaps the registered group if the runner exits first.
393
399
 
394
400
  The headless child receives only the workflow step prompt, configured model arguments, and the bridge extension. Its submission uses the same step and attempt contract as origin-session work. A headless run cannot use a visible assistant-message step because it has no origin Pi session.
395
401
 
@@ -397,9 +403,9 @@ The run binding records `interactive` or `headless` execution mode. Viewers show
397
403
 
398
404
  ## Pause and cancellation
399
405
 
400
- An explicit pause command atomically commits `paused = 1` on the run, parks the queue, releases the exact claim, cancels pending step messages, and stores the command receipt. The fenced worker process group then stops. When Escape aborts an origin-session turn, the extension sends one `workflowTurn.report` end message with `stopReason: "aborted"`. The host atomically ends that exact activity, sets the run pause, derives the pending interaction as paused, and cancels its pending step messages. The extension does not send a second pause command. A parked interaction has no worker or live run claim. While its run is paused, updates, submissions, and decision answers are rejected. Resume clears the run pause; work for the same pending interaction continues in place, while other paused work takes a new generation and starts another worker from the last durable boundary. An uncommitted pure node can run again after resume.
406
+ An explicit pause command atomically commits `paused = 1` on the run, parks the queue, releases the exact claim, cancels pending step messages, and stores the command receipt. The fenced runner process group then stops. When Escape aborts an origin-session turn, the extension sends one `workflowTurn.report` end message with `stopReason: "aborted"`. The server atomically ends that exact activity, sets the run pause, derives the pending interaction as paused, and cancels its pending step messages. The extension does not send a second pause command. A parked interaction has no runner or live run claim. While its run is paused, updates, submissions, and decision answers are rejected. Resume clears the run pause; work for the same pending interaction continues in place, while other paused work takes a new generation and starts another runner from the last durable boundary. An uncommitted pure node can run again after resume.
401
407
 
402
- Cancellation against a live worker atomically commits terminal cancellation, cancels pending attempt and interaction state, settles effect recovery state, releases the exact claim, and stores the command receipt. A pending effect becomes cancelled. An applying effect becomes ambiguous because the host cannot prove its external outcome. The host then stops the fenced worker process group. A host crash after the receipt cannot resume the cancelled run or retry the ambiguous effect. If the child does not stop by the deadline, the host kills its process group.
408
+ Cancellation against a live runner atomically commits terminal cancellation, cancels pending attempt and interaction state, settles effect recovery state, releases the exact claim, and stores the command receipt. A pending effect becomes cancelled. An applying effect becomes ambiguous because the server cannot prove its external outcome. The server then stops the fenced runner process group. A server crash after the receipt cannot resume the cancelled run or retry the ambiguous effect. If the child does not stop by the deadline, the server kills its process group.
403
409
 
404
410
  Cancellation against an expired running row first takes a new control claim. The claim operation must prove that the old lease is absent or expired. The new owner then cancels the active attempt, effect recovery state, and pending interaction or human decision in one lifecycle transaction.
405
411
 
@@ -407,18 +413,18 @@ A client cannot force-cancel a live claim through the stale recovery path.
407
413
 
408
414
  ## Recovery
409
415
 
410
- At startup the host:
416
+ At startup the server:
411
417
 
412
- 1. Takes the global host epoch.
413
- 2. Reaps worker records that match an exact stale process identity.
418
+ 1. Takes the global server epoch.
419
+ 2. Reaps runner records that match an exact stale process identity.
414
420
  3. Finds expired running runs and active attempts.
415
421
  4. Reads managed effect state before deciding whether work can repeat.
416
422
  5. Parks uncertain effects for manual review.
417
423
  6. Makes pure and fully settled work claimable.
418
- 7. Restores pending interactive requests, workflow messages, external-channel decisions, and scheduled controller work without changing Pi message or turn state.
419
- 8. Starts supervised timeout recovery for pending interactive requests only when their durable deadline expired during a reported model turn from an active connected session. A disconnect suspends the timer, and a new branch report resumes it without losing the prior active time. Message delivery, waiting, paused time, host downtime, and a closed Pi session do not consume the node timeout.
424
+ 7. Restores pending interactive requests, workflow messages, external-channel decisions, and scheduled resource manager work without changing Pi message or turn state.
425
+ 8. Starts supervised timeout recovery for pending interactive requests only when their durable deadline expired during a reported model turn from an active connected session. A disconnect suspends the timer, and a new branch report resumes it without losing the prior active time. Message delivery, waiting, paused time, server downtime, and a closed Pi session do not consume the node timeout.
420
426
  9. Resumes any remaining provisional `validating` submission in a new supervised child.
421
- 10. Waits for the extension's active-branch report before it confirms pending entries as sent, closes a turn as `lost`, or creates a branch-specific replacement. The extension sends this report after every host connection.
427
+ 10. Waits for the extension's active-branch report before it confirms pending entries as sent, closes a turn as `lost`, or creates a branch-specific replacement. The extension sends this report after every server connection.
422
428
  11. Starts no model turn until a matching Pi session connects or headless mode is declared.
423
429
 
424
430
  Recovery resumes from the last committed boundary. An uncommitted compute node may run again because compute is pure. An action with a stored effect receipt adopts that receipt. An effect in `ambiguous` state requires explicit recovery.
@@ -427,7 +433,7 @@ Claim loss is a handoff, not a run failure. The old owner writes no terminal eve
427
433
 
428
434
  ## Effects and retry safety
429
435
 
430
- Compute nodes must not perform external side effects. They can repeat after a worker crash.
436
+ Compute nodes must not perform external side effects. They can repeat after a runner crash.
431
437
 
432
438
  Side-effecting action and shell behavior must have one of these contracts:
433
439
 
@@ -435,17 +441,17 @@ Side-effecting action and shell behavior must have one of these contracts:
435
441
  - a managed effect with a read-back check that proves whether it applied;
436
442
  - an explicit non-resumable result that becomes `ambiguous` after an uncertain crash.
437
443
 
438
- The host reserves an effect before execution. The engine creates the idempotency key from the run ID, effect type, full compiled node path, and node visit number. Workflow code provides the effect type and request, but it does not provide this internal key. Included workflows can use the same local node name without sharing a key. The request fingerprint prevents key reuse with another payload.
444
+ The server reserves an effect before execution. The engine creates the idempotency key from the run ID, effect type, full compiled node path, and node visit number. Workflow code provides the effect type and request, but it does not provide this internal key. Included workflows can use the same local node name without sharing a key. The request fingerprint prevents key reuse with another payload.
439
445
 
440
446
  An applied, rejected, or cancelled effect is terminal. An ambiguous effect is also terminal for automatic retry. An operator may use a separate reviewed recovery action after inspecting the external system.
441
447
 
442
- ## Controllers
448
+ ## Resource managers
443
449
 
444
- The global host also reconciles controllers. Controllers keep their existing resource claims, queue, effects, and child workflow request keys.
450
+ The global server also reconciles managed resources. Resource managers keep their existing resource claims, queue, effects, and child workflow request keys.
445
451
 
446
- A controller child run enters the same global run queue and worker process model. It does not need an origin Pi session unless its workflow declares an interactive step. A headless child uses the declared provider path. A child that needs an origin session parks with a clear unsupported-input result unless the controller supplied an approved session binding.
452
+ A resource manager child run enters the same global run queue and runner process model. It does not need an origin Pi session unless its workflow declares an interactive step. A headless child uses the declared provider path. A child that needs an origin session parks with a clear unsupported-input result unless the resource manager supplied an approved session binding.
447
453
 
448
- Controller reconcile code runs in a supervised controller worker, not in the host event loop. Controller initialization also runs in a source resolver child. Before `controller.apply` commits, the host checks that the resolved source still matches controller discovery rules and the exact source digest.
454
+ Resource manager reconcile code runs in a supervised resource runner, not in the server event loop. Resource manager initialization also runs in a source resolver child. Before `resourceManager.apply` commits, the server checks that the resolved source still matches resource manager discovery rules and the exact source digest.
449
455
 
450
456
  ## Failure classification
451
457
 
@@ -453,9 +459,9 @@ Use separate states and messages for these failures:
453
459
 
454
460
  - `claimLost`: another generation owns the run, or the claim expired.
455
461
  - `workerCrashed`: the child exited without a terminal protocol message after it saved progress.
456
- - `workerNoProgress`: the child exited before the saved run revision advanced and needs explicit resume or cancellation.
462
+ - `runnerNoProgress`: the child exited before the saved run revision advanced and needs explicit resume or cancellation.
457
463
  - `workerTimedOut`: the child exceeded a declared deadline.
458
- - `hostUnavailable`: the client cannot reach or start the host.
464
+ - `hostUnavailable`: the client cannot reach or start the server.
459
465
  - `sourceChanged`: the workflow source does not match the saved identity.
460
466
  - `effectAmbiguous`: an external action may have applied without a receipt.
461
467
  - `nodeFailed`: workflow code returned a normal failure.
@@ -465,11 +471,11 @@ A failure in one class must not be reported as another. In particular, claim los
465
471
 
466
472
  ## Status and privacy
467
473
 
468
- `pi-workflows host status` reports:
474
+ `pi-workflows server status` reports:
469
475
 
470
- - host state and epoch;
476
+ - server state and epoch;
471
477
  - socket availability;
472
- - active worker count;
478
+ - active runner count;
473
479
  - queued, running, parked, and waiting counts;
474
480
  - expired claim count;
475
481
  - pending interaction count;
@@ -501,10 +507,10 @@ The implementation conforms when:
501
507
 
502
508
  - every protected write checks and renews one live claim atomically;
503
509
  - an expired or replaced owner cannot write;
504
- - a blocked worker cannot stop host renewal;
510
+ - a blocked runner cannot stop server renewal;
505
511
  - Pi can restart while work computes or waits;
506
- - an open Pi session reconnects after initial host startup or connection fails;
507
- - the host can restart and recover from committed state;
512
+ - an open Pi session reconnects after initial server startup or connection fails;
513
+ - the server can restart and recover from committed state;
508
514
  - run, queue, attempt, decision, lease, event, and viewer projections remain consistent after injected crashes;
509
515
  - an expired running row can be resumed or cancelled safely;
510
516
  - duplicate commands and submissions return stored receipts;
@@ -514,10 +520,10 @@ The implementation conforms when:
514
520
  - a busy Pi session with a pending message does not queue duplicate messages or model turns;
515
521
  - two Pi processes cannot send for one origin session because only one coordinator epoch is active;
516
522
  - active-branch absence requires no hidden message ID, an idle Pi session, and no pending Pi messages;
517
- - every host connection reports the active branch before any workflow-message send or turn report;
523
+ - every server connection reports the active branch before any workflow-message send or turn report;
518
524
  - a crash after send leaves the message pending until branch evidence adopts it;
519
525
  - active-branch evidence changes a matching pending or cancelled message to sent;
520
- - host restart alone never closes an active Pi turn as `lost`;
526
+ - server restart alone never closes an active Pi turn as `lost`;
521
527
  - a branch change creates at most one source-kind message when that source has no entry on the active branch;
522
528
  - a partial unique index allows at most one pending step message for each interactive request;
523
529
  - pause is stored once on the run and derived for its interaction;
@@ -531,16 +537,16 @@ The implementation conforms when:
531
537
  - a stale adapter epoch or attempt cannot settle newer channel work;
532
538
  - an interrupted exact in-flight channel attempt becomes ambiguous and is never retried without explicit recovery;
533
539
  - explicit confirmation records observed success, while explicit retry creates a new attempt and warns about possible duplication;
534
- - the extension and host run no workflow or controller code in their own event loops;
540
+ - the extension and server run no workflow or resource manager code in their own event loops;
535
541
  - the production package contains no embedded execution fallback;
536
- - the host is the only production process that opens live SQLite state;
537
- - the widget, status line, Herdr actions, CLI, and `piw` render the same host-produced status and controls;
542
+ - the server is the only production process that opens live SQLite state;
543
+ - the widget, status line, Herdr actions, CLI, and `piw` render the same server-produced status and controls;
538
544
  - running and waiting projections identify the current workflow node from the same unfinished attempt, while checkpoint waits use the completed checkpoint node;
539
545
  - an exact origin-session model turn presents that same waiting node as running without changing its durable identity;
540
546
  - a busy origin session displays `running` for the full exact workflow turn, including a terminal or pausing turn, and a stale turn-end report cannot clear newer activity;
541
- - normal worker continuation does not fail an active Pi session capture or report a false host interruption;
547
+ - normal runner continuation does not fail an active Pi session capture or report a false server interruption;
542
548
  - `paused` appears only after a durable pause and matching turn end;
543
549
  - a terminal run remains in the origin-session view while its terminal message is pending or its first turn is open, and then for 60 seconds after that turn ends, without retaining execution authority;
544
550
  - a TypeScript-created live database is viewable by the matching Rust `piw` through the client protocol without a duplicated SQLite digest;
545
- - no removed host, replay, or direct SQLite client path remains selectable;
551
+ - no removed server, replay, or direct SQLite client path remains selectable;
546
552
  - real Pi end-to-end tests, repository checks, reviewer checks, and CI pass.