@osolmaz/pi-workflows 0.13.4 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/README.md +146 -160
  2. package/dist/builtins/autoimplement.workflow.js +3 -1
  3. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  4. package/dist/builtins/change-verification.workflow.js +7 -2
  5. package/dist/builtins/change-verification.workflow.js.map +1 -1
  6. package/dist/builtins/metadata.d.ts +22 -0
  7. package/dist/builtins/metadata.js +10 -0
  8. package/dist/builtins/metadata.js.map +1 -0
  9. package/dist/builtins/monitor.workflow.js +4 -1
  10. package/dist/builtins/monitor.workflow.js.map +1 -1
  11. package/dist/builtins/sanity-check.workflow.js +4 -1
  12. package/dist/builtins/sanity-check.workflow.js.map +1 -1
  13. package/dist/builtins/workspace-preparation.workflow.js +3 -1
  14. package/dist/builtins/workspace-preparation.workflow.js.map +1 -1
  15. package/dist/controllers/index.d.ts +1 -2
  16. package/dist/controllers/index.js +0 -1
  17. package/dist/controllers/index.js.map +1 -1
  18. package/dist/controllers/sqlite.d.ts +85 -31
  19. package/dist/controllers/sqlite.js +541 -126
  20. package/dist/controllers/sqlite.js.map +1 -1
  21. package/dist/controllers/store.d.ts +1 -0
  22. package/dist/extension/controller-command.d.ts +22 -0
  23. package/dist/extension/controller-command.js +32 -0
  24. package/dist/extension/controller-command.js.map +1 -0
  25. package/dist/extension/index.d.ts +2 -9
  26. package/dist/extension/index.js +876 -2928
  27. package/dist/extension/index.js.map +1 -1
  28. package/dist/extension/message-card.d.ts +13 -0
  29. package/dist/extension/message-card.js +46 -0
  30. package/dist/extension/message-card.js.map +1 -0
  31. package/dist/extension/step-message.d.ts +5 -6
  32. package/dist/extension/step-message.js +41 -52
  33. package/dist/extension/step-message.js.map +1 -1
  34. package/dist/host/child-worker-supervisor.d.ts +50 -0
  35. package/dist/host/child-worker-supervisor.js +159 -0
  36. package/dist/host/child-worker-supervisor.js.map +1 -0
  37. package/dist/host/client.d.ts +48 -0
  38. package/dist/host/client.js +216 -0
  39. package/dist/host/client.js.map +1 -0
  40. package/dist/host/controller-worker-entry.d.ts +2 -0
  41. package/dist/host/controller-worker-entry.js +244 -0
  42. package/dist/host/controller-worker-entry.js.map +1 -0
  43. package/dist/host/controller-worker-protocol.d.ts +36 -0
  44. package/dist/host/controller-worker-protocol.js +49 -0
  45. package/dist/host/controller-worker-protocol.js.map +1 -0
  46. package/dist/host/controller-worker-supervisor.d.ts +21 -0
  47. package/dist/host/controller-worker-supervisor.js +54 -0
  48. package/dist/host/controller-worker-supervisor.js.map +1 -0
  49. package/dist/host/host-entry.d.ts +2 -0
  50. package/dist/host/host-entry.js +23 -0
  51. package/dist/host/host-entry.js.map +1 -0
  52. package/dist/host/processes.d.ts +17 -12
  53. package/dist/host/processes.js +154 -50
  54. package/dist/host/processes.js.map +1 -1
  55. package/dist/host/protocol.d.ts +38 -0
  56. package/dist/host/protocol.js +156 -0
  57. package/dist/host/protocol.js.map +1 -0
  58. package/dist/host/resolver-entry.d.ts +49 -0
  59. package/dist/host/resolver-entry.js +149 -0
  60. package/dist/host/resolver-entry.js.map +1 -0
  61. package/dist/host/rpc-executor.d.ts +14 -3
  62. package/dist/host/rpc-executor.js +63 -30
  63. package/dist/host/rpc-executor.js.map +1 -1
  64. package/dist/host/runner.d.ts +95 -29
  65. package/dist/host/runner.js +2311 -348
  66. package/dist/host/runner.js.map +1 -1
  67. package/dist/host/state.d.ts +174 -0
  68. package/dist/host/state.js +689 -0
  69. package/dist/host/state.js.map +1 -0
  70. package/dist/host/worker-entry.d.ts +10 -0
  71. package/dist/host/worker-entry.js +446 -0
  72. package/dist/host/worker-entry.js.map +1 -0
  73. package/dist/host/worker-protocol.d.ts +31 -0
  74. package/dist/host/worker-protocol.js +122 -0
  75. package/dist/host/worker-protocol.js.map +1 -0
  76. package/dist/host/worker-store.d.ts +80 -0
  77. package/dist/host/worker-store.js +91 -0
  78. package/dist/host/worker-store.js.map +1 -0
  79. package/dist/host/worker-supervisor.d.ts +22 -0
  80. package/dist/host/worker-supervisor.js +54 -0
  81. package/dist/host/worker-supervisor.js.map +1 -0
  82. package/dist/render/canvas.d.ts +2 -1
  83. package/dist/render/canvas.js +40 -15
  84. package/dist/render/canvas.js.map +1 -1
  85. package/dist/render/graph-render.d.ts +7 -3
  86. package/dist/render/graph-render.js +125 -74
  87. package/dist/render/graph-render.js.map +1 -1
  88. package/dist/state/database.js +3 -1
  89. package/dist/state/database.js.map +1 -1
  90. package/dist/state/index.d.ts +1 -0
  91. package/dist/state/index.js +1 -0
  92. package/dist/state/index.js.map +1 -1
  93. package/dist/state/prune.js +36 -10
  94. package/dist/state/prune.js.map +1 -1
  95. package/dist/state/schema.d.ts +1 -1
  96. package/dist/state/schema.js +171 -3
  97. package/dist/state/schema.js.map +1 -1
  98. package/dist/state/viewer.d.ts +46 -0
  99. package/dist/state/viewer.js +249 -0
  100. package/dist/state/viewer.js.map +1 -0
  101. package/dist/viewer/cli.d.ts +1 -1
  102. package/dist/viewer/cli.js +47 -18
  103. package/dist/viewer/cli.js.map +1 -1
  104. package/dist/workflows/composition.js +25 -2
  105. package/dist/workflows/composition.js.map +1 -1
  106. package/dist/workflows/definition.d.ts +3 -1
  107. package/dist/workflows/definition.js +25 -0
  108. package/dist/workflows/definition.js.map +1 -1
  109. package/dist/workflows/engine.d.ts +1 -0
  110. package/dist/workflows/engine.js +157 -42
  111. package/dist/workflows/engine.js.map +1 -1
  112. package/dist/workflows/errors.d.ts +3 -1
  113. package/dist/workflows/errors.js +4 -7
  114. package/dist/workflows/errors.js.map +1 -1
  115. package/dist/workflows/human-decision.d.ts +3 -0
  116. package/dist/workflows/human-decision.js +31 -0
  117. package/dist/workflows/human-decision.js.map +1 -1
  118. package/dist/workflows/index.d.ts +1 -1
  119. package/dist/workflows/index.js +1 -1
  120. package/dist/workflows/index.js.map +1 -1
  121. package/dist/workflows/schema.js +17 -6
  122. package/dist/workflows/schema.js.map +1 -1
  123. package/dist/{viewer → workflows}/session-reducer.d.ts +3 -1
  124. package/dist/{viewer → workflows}/session-reducer.js +4 -0
  125. package/dist/workflows/session-reducer.js.map +1 -0
  126. package/dist/workflows/store.d.ts +87 -1
  127. package/dist/workflows/store.js +892 -93
  128. package/dist/workflows/store.js.map +1 -1
  129. package/dist/workflows/tool-input.d.ts +0 -22
  130. package/dist/workflows/tool-input.js +1 -44
  131. package/dist/workflows/tool-input.js.map +1 -1
  132. package/dist/workflows/types.d.ts +36 -4
  133. package/docs/2026-08-25-workflow-follow-ups.md +8 -6
  134. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +353 -0
  135. package/docs/CONTROLLERS.md +11 -11
  136. package/docs/DEFERRED_TURNS.md +61 -27
  137. package/docs/HUMAN_DECISIONS.md +12 -4
  138. package/docs/SQLITE_STATE.md +42 -8
  139. package/docs/WORKFLOW_HOST.md +452 -0
  140. package/docs/development.md +46 -30
  141. package/docs/live-replay-protocol.md +129 -100
  142. package/docs/plans/2026-08-19-human-decision-gates-plan.md +34 -8
  143. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +399 -0
  144. package/docs/plans/2026-08-28-piw-incremental-viewer-plan.md +293 -0
  145. package/docs/plans/piw-viewer-experience-implementation-plan.md +11 -1
  146. package/docs/plans/tui-viewer-implementation-plan.md +5 -0
  147. package/docs/tui-viewer.md +18 -3
  148. package/docs/workflows.md +164 -156
  149. package/examples/workflows/command-batch.workflow.ts +2 -0
  150. package/examples/workflows/shell.workflow.ts +2 -1
  151. package/herdr-plugin.toml +1 -1
  152. package/package.json +1 -1
  153. package/skills/autodoc/SKILL.md +1 -1
  154. package/skills/autoimplement/SKILL.md +1 -1
  155. package/skills/autoplan/SKILL.md +1 -1
  156. package/skills/pi-workflows/SKILL.md +2 -0
  157. package/src/builtins/autoimplement.workflow.ts +3 -0
  158. package/src/builtins/change-verification.workflow.ts +7 -2
  159. package/src/builtins/metadata.ts +9 -0
  160. package/src/builtins/monitor.workflow.ts +4 -0
  161. package/src/builtins/sanity-check.workflow.ts +4 -0
  162. package/src/builtins/workspace-preparation.workflow.ts +3 -1
  163. package/src/controllers/index.ts +3 -5
  164. package/src/controllers/sqlite.ts +929 -225
  165. package/src/controllers/store.ts +1 -0
  166. package/src/extension/controller-command.ts +45 -0
  167. package/src/extension/index.ts +948 -3506
  168. package/src/extension/message-card.ts +61 -0
  169. package/src/extension/step-message.ts +58 -63
  170. package/src/host/child-worker-supervisor.ts +183 -0
  171. package/src/host/client.ts +293 -0
  172. package/src/host/controller-worker-entry.ts +311 -0
  173. package/src/host/controller-worker-protocol.ts +104 -0
  174. package/src/host/controller-worker-supervisor.ts +79 -0
  175. package/src/host/host-entry.ts +23 -0
  176. package/src/host/processes.ts +171 -54
  177. package/src/host/protocol.ts +196 -0
  178. package/src/host/resolver-entry.ts +241 -0
  179. package/src/host/rpc-executor.ts +76 -34
  180. package/src/host/runner.ts +2813 -422
  181. package/src/host/state.ts +1160 -0
  182. package/src/host/worker-entry.ts +533 -0
  183. package/src/host/worker-protocol.ts +165 -0
  184. package/src/host/worker-store.ts +229 -0
  185. package/src/host/worker-supervisor.ts +74 -0
  186. package/src/render/canvas.ts +44 -10
  187. package/src/render/graph-render.ts +145 -90
  188. package/src/state/database.ts +2 -1
  189. package/src/state/index.ts +14 -0
  190. package/src/state/prune.ts +35 -9
  191. package/src/state/schema.ts +171 -3
  192. package/src/state/viewer.ts +356 -0
  193. package/src/viewer/cli.ts +49 -17
  194. package/src/workflows/composition.ts +36 -2
  195. package/src/workflows/definition.ts +32 -0
  196. package/src/workflows/engine.ts +157 -54
  197. package/src/workflows/errors.ts +11 -2
  198. package/src/workflows/human-decision.ts +49 -0
  199. package/src/workflows/index.ts +2 -0
  200. package/src/workflows/schema.ts +19 -6
  201. package/src/{viewer → workflows}/session-reducer.ts +11 -1
  202. package/src/workflows/store.ts +1316 -108
  203. package/src/workflows/tool-input.ts +2 -60
  204. package/src/workflows/types.ts +32 -4
  205. package/dist/controllers/workflow-engine-scheduler.d.ts +0 -29
  206. package/dist/controllers/workflow-engine-scheduler.js +0 -175
  207. package/dist/controllers/workflow-engine-scheduler.js.map +0 -1
  208. package/dist/extension/controller-host.d.ts +0 -48
  209. package/dist/extension/controller-host.js +0 -110
  210. package/dist/extension/controller-host.js.map +0 -1
  211. package/dist/extension/deferred-turn-coordinator.d.ts +0 -32
  212. package/dist/extension/deferred-turn-coordinator.js +0 -143
  213. package/dist/extension/deferred-turn-coordinator.js.map +0 -1
  214. package/dist/extension/deferred-turn.d.ts +0 -44
  215. package/dist/extension/deferred-turn.js +0 -110
  216. package/dist/extension/deferred-turn.js.map +0 -1
  217. package/dist/extension/executor.d.ts +0 -86
  218. package/dist/extension/executor.js +0 -311
  219. package/dist/extension/executor.js.map +0 -1
  220. package/dist/extension/follow-up-coordinator.d.ts +0 -27
  221. package/dist/extension/follow-up-coordinator.js +0 -131
  222. package/dist/extension/follow-up-coordinator.js.map +0 -1
  223. package/dist/extension/recorder.d.ts +0 -84
  224. package/dist/extension/recorder.js +0 -528
  225. package/dist/extension/recorder.js.map +0 -1
  226. package/dist/extension/session-events.d.ts +0 -133
  227. package/dist/extension/session-events.js +0 -61
  228. package/dist/extension/session-events.js.map +0 -1
  229. package/dist/viewer/session-reducer.js.map +0 -1
  230. package/src/controllers/workflow-engine-scheduler.ts +0 -246
  231. package/src/extension/controller-host.ts +0 -167
  232. package/src/extension/deferred-turn-coordinator.ts +0 -171
  233. package/src/extension/deferred-turn.ts +0 -166
  234. package/src/extension/executor.ts +0 -411
  235. package/src/extension/follow-up-coordinator.ts +0 -151
  236. package/src/extension/recorder.ts +0 -655
  237. package/src/extension/session-events.ts +0 -121
@@ -0,0 +1,399 @@
1
+ ---
2
+ title: Workflow terminal decision and restart plan
3
+ author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
4
+ date: 2026-08-27
5
+ ---
6
+
7
+ # Full plan
8
+
9
+ ## Goal
10
+
11
+ After every top-level workflow run ends, give the model one normal successor turn.
12
+
13
+ That turn contains the workflow result and terminal reason. The model uses the conversation it already has to decide whether to:
14
+
15
+ - stop because the user’s task is complete
16
+ - restart the same workflow as a new run
17
+ - start Monitor for an authorized external wait
18
+ - ask the user for a required decision or authority
19
+ - take another safe authorized action
20
+
21
+ The system does not save or identify the original user message. It does not restart automatically. It gives the model one clear decision opportunity and makes safe retry the default for unfinished work after technical failures.
22
+
23
+ ## Shared terminal behavior
24
+
25
+ The shared terminal message must include:
26
+
27
+ - workflow name and revision
28
+ - terminal run ID
29
+ - exact workflow input
30
+ - workflow result
31
+ - terminal state
32
+ - terminal reason
33
+ - restart count
34
+ - earlier terminal outcomes in the same restart chain
35
+
36
+ The message must tell the model:
37
+
38
+ > A workflow run ended, but that does not prove the user’s task is complete. Use the current conversation and this result to decide what to do next. If the task is unfinished because of an unexpected technical or temporary failure, prefer a safe restart. Stop if the work is complete, the user cancelled it, new authority is required, the user must make a decision, or the same failure has repeated. Use Monitor only for an authorized external wait.
39
+
40
+ Use the term **result**, not “durable result.”
41
+
42
+ ## Implementation steps
43
+
44
+ ### 1. Build one shared terminal-decision message
45
+
46
+ **Where**
47
+
48
+ - `src/extension/deferred-turn.ts`
49
+ - Add `src/extension/terminal-decision.ts` if a separate pure module keeps the code smaller.
50
+
51
+ **Change**
52
+
53
+ Add a pure builder that reads the existing run record and produces the shared terminal facts and prompt.
54
+
55
+ It must not read, copy, hash, or store an original user message.
56
+
57
+ Use the existing stored workflow input and result. Apply the existing output-size rules to large results, but always include the run ID, state, reason, and restart history.
58
+
59
+ **Verification**
60
+
61
+ Unit tests must cover completed, failed, timed-out, maxSteps, cancelled, and blocked results.
62
+
63
+ ### 2. Create one terminal turn for every top-level run
64
+
65
+ **Where**
66
+
67
+ - `finishRun` in `src/extension/index.ts`
68
+ - `src/extension/deferred-turn-coordinator.ts`
69
+ - Existing turn-intent state in `src/controllers/sqlite.ts`
70
+
71
+ **Change**
72
+
73
+ Create one terminal turn intent when a top-level interactive run reaches a terminal state.
74
+
75
+ Normal presentation and fallback delivery must compete for the same intent. The first successful delivery settles it. Every later delivery attempt becomes a no-op.
76
+
77
+ Do not create this turn for:
78
+
79
+ - waiting checkpoints
80
+ - controller child runs
81
+ - internal helper runs that already report to an owner
82
+
83
+ **Verification**
84
+
85
+ Race tests must prove that presentation, fallback, reload recovery, and crash recovery produce one model turn, not two.
86
+
87
+ ### 3. Replace the current terminal presentation instruction
88
+
89
+ **Where**
90
+
91
+ - `buildPresentationMessage`
92
+ - `buildDeferredTurnContent`
93
+ - Related presentation helpers in `src/extension/index.ts`
94
+
95
+ **Change**
96
+
97
+ Remove the current instruction that says the model must not call the workflow tool.
98
+
99
+ Replace it with the shared decision instructions. The terminal turn must permit one workflow launch selected by the model.
100
+
101
+ Completed runs still get a result turn. A workflow state of `completed` does not always mean the larger user task is complete. For example, the result can say that work is blocked.
102
+
103
+ Explicit human cancellation must default to stopping.
104
+
105
+ **Verification**
106
+
107
+ Tests must prove that the model can select restart or Monitor during the terminal turn and that ordinary completed work does not cause an automatic restart.
108
+
109
+ ### 4. Add a generic restart action
110
+
111
+ **Where**
112
+
113
+ - `src/workflows/tool-input.ts`
114
+ - Workflow tool registration, schema, help text, and control switch under `src/workflows/`
115
+ - Restart handling in `src/extension/index.ts`
116
+
117
+ **Contract**
118
+
119
+ ```json
120
+ {
121
+ "action": "restart",
122
+ "runId": "terminal-run-id"
123
+ }
124
+ ```
125
+
126
+ **Change**
127
+
128
+ The action must:
129
+
130
+ 1. Read the terminal run.
131
+ 2. Confirm that it belongs to the current session.
132
+ 3. Confirm that it is terminal.
133
+ 4. Reuse the exact workflow reference, input, and safe launch settings.
134
+ 5. Create a new immutable run.
135
+ 6. Record the restart relationship.
136
+ 7. Leave the old run unchanged.
137
+
138
+ Reject restart when:
139
+
140
+ - the run is active or waiting
141
+ - the run is unknown
142
+ - the run belongs to another session
143
+ - the run was explicitly cancelled
144
+ - the workflow source or revision is no longer available
145
+ - the restart limit was reached
146
+ - the same terminal failure already repeated
147
+
148
+ A later explicit user request can still use normal `start`.
149
+
150
+ **Verification**
151
+
152
+ Tool-schema and extension tests must prove exact input reuse, immutable old runs, session checks, source checks, and correct rejection behavior.
153
+
154
+ ### 5. Permit one selected launch during the terminal turn
155
+
156
+ **Where**
157
+
158
+ - `queueToolLaunch`
159
+ - presentation tracking in `src/extension/index.ts`
160
+ - `agent_settled`
161
+ - existing queued-launch recovery
162
+
163
+ **Change**
164
+
165
+ The current presentation guard rejects workflow launches. Add one narrow exception for the active terminal-decision turn.
166
+
167
+ The model can reserve one of these:
168
+
169
+ - restart
170
+ - Monitor
171
+ - another workflow start
172
+
173
+ The reservation must not activate until the model turn settles. A second workflow launch from the same terminal turn must fail.
174
+
175
+ Other tool calls remain subject to their normal rules.
176
+
177
+ **Verification**
178
+
179
+ Tests must prove that:
180
+
181
+ - one launch can be reserved during presentation
182
+ - it starts only after `agent_settled`
183
+ - a second launch is rejected
184
+ - reload after reservation does not lose it
185
+ - crash recovery does not start it twice
186
+
187
+ ### 6. Add bounded restart lineage
188
+
189
+ **Where**
190
+
191
+ - Add `src/extension/restart-policy.ts`
192
+ - Existing run launch-options JSON and accessors
193
+ - No new database table
194
+
195
+ **Change**
196
+
197
+ Store this information for restarted runs:
198
+
199
+ - root run ID
200
+ - parent run ID
201
+ - restart number
202
+ - parent terminal fingerprint
203
+
204
+ A terminal fingerprint is a stable hash of:
205
+
206
+ - workflow identity and revision
207
+ - exact input
208
+ - terminal state
209
+ - canonical result or error
210
+ - canonical terminal reason
211
+
212
+ Do not include timestamps or new run IDs in the fingerprint.
213
+
214
+ Allow at most three restart actions after the original run. This permits at most four runs in one chain.
215
+
216
+ If a terminal fingerprint occurs again in the same chain, reject another restart immediately. If the result changes because the workflow made progress, another restart can remain eligible until the total limit is reached.
217
+
218
+ Starting Monitor does not consume a restart.
219
+
220
+ **Verification**
221
+
222
+ Tests must cover:
223
+
224
+ - first technical retry
225
+ - progress followed by a different failure
226
+ - repeated identical maxSteps failure
227
+ - three-restart limit
228
+ - Monitor selection
229
+ - restart history after database reopen
230
+
231
+ ### 7. Make restart reservation idempotent
232
+
233
+ **Where**
234
+
235
+ - Existing effect records
236
+ - Existing run queue and reservation code
237
+ - Terminal turn-intent settlement code
238
+
239
+ **Change**
240
+
241
+ Key the selected launch to the source terminal turn intent and tool call.
242
+
243
+ If the host repeats the same tool call after a crash or reload, return the existing reservation or new run instead of creating another one.
244
+
245
+ The terminal turn intent, launch reservation, and resulting run must have one inspectable chain.
246
+
247
+ **Verification**
248
+
249
+ Inject failures after:
250
+
251
+ - turn-intent claim
252
+ - launch reservation
253
+ - run creation
254
+ - terminal response settlement
255
+
256
+ After recovery, there must still be one terminal message and one successor run.
257
+
258
+ ### 8. Document the contract
259
+
260
+ **Where**
261
+
262
+ - `docs/workflows.md`
263
+ - `docs/SQLITE_STATE.md`
264
+ - Workflow tool reference and examples
265
+ - Relevant README text
266
+
267
+ **Change**
268
+
269
+ Document:
270
+
271
+ - the shared terminal decision turn
272
+ - the `restart` action
273
+ - the difference between a workflow ending and the user’s task finishing
274
+ - retry defaults and limits
275
+ - Monitor selection
276
+ - explicit cancellation behavior
277
+ - top-level versus child-run behavior
278
+ - recovery and duplicate prevention
279
+ - that conversation context remains owned by Pi
280
+ - that Pi Workflows does not capture or persist an original user message
281
+
282
+ No workflow definition needs an opt-in or terminal restart step.
283
+
284
+ ### 9. Render deferred terminal turns as compact cards
285
+
286
+ **Where**
287
+
288
+ - `src/extension/deferred-turn.ts`
289
+ - `src/extension/index.ts`
290
+ - Deferred-turn renderer unit tests
291
+ - Real-Pi end-to-end tests
292
+
293
+ **Change**
294
+
295
+ Register a custom TUI message renderer for the existing `pi-workflows-deferred-turn` message type through Pi's documented `pi.registerMessageRenderer()` API.
296
+
297
+ Keep the complete existing message content unchanged. The model and session history must still receive the terminal facts, exact input, bounded result, restart history, and instructions. Do not replace that content with a summary, split it into another entry, or hide the deferred fallback with `display: false`.
298
+
299
+ Add small, bounded presentation fields to the existing message details. The fields cover the workflow name, terminal state or cause, run identity, terminal reason kind, and restart count and limit when available. The renderer must read those fields directly and must not parse the model prompt.
300
+
301
+ The collapsed card must show a concise workflow summary. It must not show the terminal facts JSON, exact input, result, fingerprint, or full model instructions. The expanded card must show the complete existing content through Pi's standard `expanded` state, consistent with agent-step message cards.
302
+
303
+ Use standard Pi TUI components and theme colors. Sanitize all workflow-derived display text. Missing or malformed details must produce a safe generic card instead of an exception.
304
+
305
+ Keep the behavior workflow-agnostic. Ordinary deferred fallbacks, terminal decisions, and restored messages use the same renderer. Presentation messages that already use `display: false` stay unchanged. Headless and RPC behavior stays unchanged. Rendering must not create a duplicate session entry or model turn.
306
+
307
+ This change uses only `pi.sendMessage()` and `pi.registerMessageRenderer()`. It adds no Pi core or private API use, database table, migration, store, service, controller, daemon, or external resource.
308
+
309
+ **Verification**
310
+
311
+ Focused tests must prove that:
312
+
313
+ - collapsed output shows bounded workflow, state or cause, run, and restart fields
314
+ - collapsed output omits the full prompt, terminal JSON, input, result, and fingerprint
315
+ - expanded output contains the complete model-facing content
316
+ - completed, failed, timed-out, cancelled, launch-failure, and maxSteps states render correctly
317
+ - long or terminal-unsafe fields are safe
318
+ - missing and malformed details do not throw
319
+ - the renderer registers once for `pi-workflows-deferred-turn`
320
+ - restored messages render without creating another entry or turn
321
+ - real Pi still gives the provider the complete prompt while the session record keeps the custom message type and renderer details
322
+
323
+ ## Contract changes
324
+
325
+ - The workflow tool gains `restart`.
326
+ - Every top-level terminal run owns one terminal turn intent.
327
+ - Restart always creates a new run.
328
+ - Restart reuses the exact prior workflow input.
329
+ - The model makes the continuation decision from the current conversation.
330
+ - Restart is preferred, not forced, for unfinished work after technical or temporary failures.
331
+ - Explicit cancellation, missing authority, required user decisions, repeated failures, and completed work stop.
332
+ - Restart lineage uses existing run launch data.
333
+ - No new store, service, controller, or Pi API is added.
334
+ - No original-message provenance contract is added.
335
+ - The existing deferred-turn message details gain small, bounded presentation fields.
336
+ - The existing deferred-turn message content remains complete and unchanged for the model and session history.
337
+ - Interactive Pi renders deferred turns through the public message-renderer API. Headless and RPC delivery do not change.
338
+
339
+ ## Test plan
340
+
341
+ Add regression coverage for:
342
+
343
+ 1. Successful completion produces one result turn and no automatic restart.
344
+ 2. A blocked result from a completed workflow lets the model select restart.
345
+ 3. Failed, timed-out, and maxSteps runs offer restart.
346
+ 4. Explicit cancellation is not restartable through the shortcut.
347
+ 5. Waiting checkpoints do not produce a terminal turn.
348
+ 6. Controller child runs do not produce competing turns.
349
+ 7. Presentation and fallback races produce one turn.
350
+ 8. Restart uses the exact workflow reference and input.
351
+ 9. Restart leaves the prior run unchanged.
352
+ 10. Monitor starts through the normal start path.
353
+ 11. A selected launch waits for `agent_settled`.
354
+ 12. Reload and crash recovery do not duplicate turns or runs.
355
+ 13. The same terminal failure cannot repeat indefinitely.
356
+ 14. A chain cannot exceed three restarts.
357
+ 15. No new code captures, hashes, or stores an original user message.
358
+ 16. The maxSteps failure that caused this incident produces a terminal decision turn instead of silently ending the task.
359
+
360
+ Run the full repository checks:
361
+
362
+ ```bash
363
+ npm run check
364
+ npm run test:e2e
365
+ npx slophammer-ts@latest dry .
366
+ npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
367
+ ```
368
+
369
+ ## Main risks
370
+
371
+ - **The model restarts completed work.**
372
+ Make stopping the default for successful results and enforce restart limits.
373
+
374
+ - **A retry repeats external effects.**
375
+ Include the prior result and restart history so the model can inspect the current state before it retries.
376
+
377
+ - **Presentation and fallback both fire.**
378
+ Make both settle the same turn intent.
379
+
380
+ - **A launch starts while the terminal response is still active.**
381
+ Reserve it first and activate it after `agent_settled`.
382
+
383
+ - **A temporary outage causes a loop.**
384
+ Use Monitor for external waits, stop repeated fingerprints, and allow only three restarts.
385
+
386
+ ## Boundaries
387
+
388
+ Do not:
389
+
390
+ - modify Pi core or private APIs
391
+ - store or identify an original user message
392
+ - add restart nodes to individual workflows
393
+ - modify Autoimplement, Monitor, or other workflow definitions
394
+ - create a new controller, database, service, or daemon
395
+ - bypass cancellation, checkpoints, reviews, CI, authority, or safety rules
396
+ - add compatibility shims or parallel state contracts
397
+ - release or deploy anything as part of this plan
398
+
399
+ This is the selected plan.