@osolmaz/pi-workflows 0.12.1 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +59 -33
  2. package/dist/builtins/autodoc.workflow.d.ts +194 -7
  3. package/dist/builtins/autodoc.workflow.js +156 -30
  4. package/dist/builtins/autodoc.workflow.js.map +1 -1
  5. package/dist/builtins/autoimplement-command-batches.d.ts +1 -0
  6. package/dist/builtins/autoimplement-command-batches.js +29 -31
  7. package/dist/builtins/autoimplement-command-batches.js.map +1 -1
  8. package/dist/builtins/autoimplement.workflow.d.ts +1619 -97
  9. package/dist/builtins/autoimplement.workflow.js +416 -153
  10. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  11. package/dist/builtins/autoplan.workflow.d.ts +126 -13
  12. package/dist/builtins/autoplan.workflow.js +200 -29
  13. package/dist/builtins/autoplan.workflow.js.map +1 -1
  14. package/dist/builtins/catalog.js +7 -5
  15. package/dist/builtins/catalog.js.map +1 -1
  16. package/dist/builtins/change-verification.workflow.d.ts +110 -0
  17. package/dist/builtins/change-verification.workflow.js +860 -0
  18. package/dist/builtins/change-verification.workflow.js.map +1 -0
  19. package/dist/builtins/index.d.ts +2 -1
  20. package/dist/builtins/index.js +1 -0
  21. package/dist/builtins/index.js.map +1 -1
  22. package/dist/builtins/monitor.workflow.d.ts +56 -21
  23. package/dist/builtins/monitor.workflow.js +499 -217
  24. package/dist/builtins/monitor.workflow.js.map +1 -1
  25. package/dist/builtins/plain-summary.workflow.d.ts +32 -0
  26. package/dist/builtins/plain-summary.workflow.js +134 -0
  27. package/dist/builtins/plain-summary.workflow.js.map +1 -0
  28. package/dist/builtins/plan-change.workflow.d.ts +527 -26
  29. package/dist/builtins/plan-change.workflow.js +26 -0
  30. package/dist/builtins/plan-change.workflow.js.map +1 -1
  31. package/dist/builtins/sanity-check.workflow.d.ts +45 -3
  32. package/dist/builtins/sanity-check.workflow.js +45 -7
  33. package/dist/builtins/sanity-check.workflow.js.map +1 -1
  34. package/dist/builtins/workspace-preparation.workflow.d.ts +75 -0
  35. package/dist/builtins/workspace-preparation.workflow.js +498 -0
  36. package/dist/builtins/workspace-preparation.workflow.js.map +1 -0
  37. package/dist/controllers/effects.d.ts +3 -2
  38. package/dist/controllers/effects.js +8 -1
  39. package/dist/controllers/effects.js.map +1 -1
  40. package/dist/controllers/index.d.ts +1 -1
  41. package/dist/controllers/index.js +1 -1
  42. package/dist/controllers/index.js.map +1 -1
  43. package/dist/controllers/manager.d.ts +1 -0
  44. package/dist/controllers/manager.js +41 -17
  45. package/dist/controllers/manager.js.map +1 -1
  46. package/dist/controllers/sqlite.d.ts +107 -85
  47. package/dist/controllers/sqlite.js +1611 -1486
  48. package/dist/controllers/sqlite.js.map +1 -1
  49. package/dist/controllers/store.d.ts +9 -8
  50. package/dist/controllers/store.js +1 -31
  51. package/dist/controllers/store.js.map +1 -1
  52. package/dist/controllers/types.d.ts +3 -0
  53. package/dist/controllers/workflow-engine-scheduler.d.ts +1 -1
  54. package/dist/controllers/workflow-engine-scheduler.js +3 -5
  55. package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
  56. package/dist/controllers/workflows.d.ts +2 -2
  57. package/dist/controllers/workflows.js +11 -10
  58. package/dist/controllers/workflows.js.map +1 -1
  59. package/dist/extension/controller-host.js +2 -2
  60. package/dist/extension/controller-host.js.map +1 -1
  61. package/dist/extension/decision-channels.d.ts +2 -0
  62. package/dist/extension/decision-channels.js +311 -118
  63. package/dist/extension/decision-channels.js.map +1 -1
  64. package/dist/extension/executor.d.ts +9 -2
  65. package/dist/extension/executor.js +90 -6
  66. package/dist/extension/executor.js.map +1 -1
  67. package/dist/extension/herdr-viewer.d.ts +0 -1
  68. package/dist/extension/herdr-viewer.js +0 -4
  69. package/dist/extension/herdr-viewer.js.map +1 -1
  70. package/dist/extension/index.js +156 -117
  71. package/dist/extension/index.js.map +1 -1
  72. package/dist/extension/recorder.d.ts +3 -10
  73. package/dist/extension/recorder.js +13 -22
  74. package/dist/extension/recorder.js.map +1 -1
  75. package/dist/extension/step-message.d.ts +7 -2
  76. package/dist/extension/step-message.js +94 -2
  77. package/dist/extension/step-message.js.map +1 -1
  78. package/dist/extension/widget.js +6 -0
  79. package/dist/extension/widget.js.map +1 -1
  80. package/dist/host/rpc-executor.d.ts +3 -0
  81. package/dist/host/rpc-executor.js +2 -0
  82. package/dist/host/rpc-executor.js.map +1 -1
  83. package/dist/host/runner.d.ts +3 -6
  84. package/dist/host/runner.js +83 -32
  85. package/dist/host/runner.js.map +1 -1
  86. package/dist/render/graph-render.js +14 -8
  87. package/dist/render/graph-render.js.map +1 -1
  88. package/dist/state/database.d.ts +35 -0
  89. package/dist/state/database.js +287 -0
  90. package/dist/state/database.js.map +1 -0
  91. package/dist/state/index.d.ts +4 -0
  92. package/dist/state/index.js +5 -0
  93. package/dist/state/index.js.map +1 -0
  94. package/dist/state/json.d.ts +6 -0
  95. package/dist/state/json.js +38 -0
  96. package/dist/state/json.js.map +1 -0
  97. package/dist/state/mutation.d.ts +57 -0
  98. package/dist/state/mutation.js +255 -0
  99. package/dist/state/mutation.js.map +1 -0
  100. package/dist/state/schema.d.ts +6 -0
  101. package/dist/state/schema.js +473 -0
  102. package/dist/state/schema.js.map +1 -0
  103. package/dist/viewer/cli.d.ts +2 -2
  104. package/dist/viewer/cli.js +142 -122
  105. package/dist/viewer/cli.js.map +1 -1
  106. package/dist/viewer/render.d.ts +4 -4
  107. package/dist/viewer/render.js +2 -17
  108. package/dist/viewer/render.js.map +1 -1
  109. package/dist/viewer/session-reducer.d.ts +1 -1
  110. package/dist/viewer/session-reducer.js +1 -1
  111. package/dist/viewer/tui.d.ts +3 -3
  112. package/dist/viewer/tui.js +15 -13
  113. package/dist/viewer/tui.js.map +1 -1
  114. package/dist/viewer/watch.d.ts +2 -5
  115. package/dist/viewer/watch.js +13 -13
  116. package/dist/viewer/watch.js.map +1 -1
  117. package/dist/workflows/composition.js +12 -2
  118. package/dist/workflows/composition.js.map +1 -1
  119. package/dist/workflows/definition.d.ts +6 -2
  120. package/dist/workflows/definition.js +17 -0
  121. package/dist/workflows/definition.js.map +1 -1
  122. package/dist/workflows/engine.d.ts +6 -6
  123. package/dist/workflows/engine.js +183 -103
  124. package/dist/workflows/engine.js.map +1 -1
  125. package/dist/workflows/errors.d.ts +3 -3
  126. package/dist/workflows/errors.js +3 -3
  127. package/dist/workflows/human-decision.d.ts +29 -4
  128. package/dist/workflows/human-decision.js +547 -283
  129. package/dist/workflows/human-decision.js.map +1 -1
  130. package/dist/workflows/index.d.ts +4 -5
  131. package/dist/workflows/index.js +3 -4
  132. package/dist/workflows/index.js.map +1 -1
  133. package/dist/workflows/schema.js +17 -1
  134. package/dist/workflows/schema.js.map +1 -1
  135. package/dist/workflows/store.d.ts +83 -103
  136. package/dist/workflows/store.js +902 -951
  137. package/dist/workflows/store.js.map +1 -1
  138. package/dist/workflows/types.d.ts +55 -81
  139. package/docs/CONTROLLERS.md +10 -8
  140. package/docs/DEFERRED_TURNS.md +2 -2
  141. package/docs/DESIGN_PHILOSOPHY.md +4 -2
  142. package/docs/HUMAN_DECISIONS.md +13 -14
  143. package/docs/MONITOR.md +179 -231
  144. package/docs/SQLITE_STATE.md +219 -0
  145. package/docs/WORKFLOW_COMPOSITION.md +27 -19
  146. package/docs/WORKFLOW_STEP_MESSAGES.md +20 -18
  147. package/docs/WORKFLOW_UPDATES.md +10 -9
  148. package/docs/development.md +9 -9
  149. package/docs/live-replay-protocol.md +28 -37
  150. package/docs/plans/2026-08-16-workflow-updates-plan.md +1 -1
  151. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  152. package/docs/plans/2026-08-21-autoimplement-timeout-fallback-plan.md +1 -1
  153. package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +1 -1
  154. package/docs/plans/2026-08-21-sanity-check-plan.md +30 -16
  155. package/docs/plans/2026-08-22-goal-finishing-monitor-plan.md +200 -0
  156. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +701 -0
  157. package/docs/plans/2026-08-23-sqlite-state-plan.md +970 -0
  158. package/docs/plans/2026-08-24-change-scoped-verification-plan.md +419 -0
  159. package/docs/plans/replayable-run-bundles-implementation-plan.md +2 -2
  160. package/docs/plans/session-event-replay-implementation-plan.md +1 -1
  161. package/docs/plans/tui-viewer-implementation-plan.md +1 -1
  162. package/docs/session-event-journal.md +63 -434
  163. package/docs/tui-viewer.md +13 -15
  164. package/docs/workflows.md +111 -62
  165. package/examples/workflows/plain-summary.workflow.ts +1 -0
  166. package/herdr-plugin.toml +1 -1
  167. package/package.json +1 -1
  168. package/plugins/herdr/viewer.mjs +1 -11
  169. package/skills/autodoc/SKILL.md +7 -0
  170. package/skills/autoimplement/SKILL.md +4 -0
  171. package/skills/autoplan/SKILL.md +5 -4
  172. package/skills/monitor/SKILL.md +91 -163
  173. package/skills/pi-workflows/SKILL.md +7 -7
  174. package/skills/sanity-check/SKILL.md +1 -1
  175. package/src/builtins/autodoc.workflow.ts +184 -33
  176. package/src/builtins/autoimplement-command-batches.ts +39 -33
  177. package/src/builtins/autoimplement.workflow.ts +483 -175
  178. package/src/builtins/autoplan.workflow.ts +290 -40
  179. package/src/builtins/catalog.ts +7 -5
  180. package/src/builtins/change-verification.workflow.ts +1143 -0
  181. package/src/builtins/index.ts +7 -1
  182. package/src/builtins/monitor.workflow.ts +667 -250
  183. package/src/builtins/plain-summary.workflow.ts +185 -0
  184. package/src/builtins/plan-change.workflow.ts +35 -0
  185. package/src/builtins/sanity-check.workflow.ts +62 -7
  186. package/src/builtins/workspace-preparation.workflow.ts +668 -0
  187. package/src/controllers/effects.ts +7 -0
  188. package/src/controllers/index.ts +0 -6
  189. package/src/controllers/manager.ts +72 -32
  190. package/src/controllers/sqlite.ts +2420 -1948
  191. package/src/controllers/store.ts +17 -38
  192. package/src/controllers/types.ts +3 -0
  193. package/src/controllers/workflow-engine-scheduler.ts +4 -8
  194. package/src/controllers/workflows.ts +45 -21
  195. package/src/extension/controller-host.ts +1 -2
  196. package/src/extension/decision-channels.ts +427 -144
  197. package/src/extension/executor.ts +106 -6
  198. package/src/extension/herdr-viewer.ts +0 -5
  199. package/src/extension/index.ts +180 -132
  200. package/src/extension/recorder.ts +13 -22
  201. package/src/extension/step-message.ts +106 -4
  202. package/src/extension/widget.ts +8 -0
  203. package/src/host/rpc-executor.ts +4 -0
  204. package/src/host/runner.ts +93 -41
  205. package/src/render/graph-render.ts +11 -4
  206. package/src/state/database.ts +375 -0
  207. package/src/state/index.ts +29 -0
  208. package/src/state/json.ts +42 -0
  209. package/src/state/mutation.ts +435 -0
  210. package/src/state/schema.ts +475 -0
  211. package/src/viewer/cli.ts +151 -144
  212. package/src/viewer/render.ts +12 -24
  213. package/src/viewer/session-reducer.ts +1 -1
  214. package/src/viewer/tui.ts +18 -17
  215. package/src/viewer/watch.ts +13 -17
  216. package/src/workflows/composition.ts +12 -3
  217. package/src/workflows/definition.ts +36 -3
  218. package/src/workflows/engine.ts +212 -116
  219. package/src/workflows/errors.ts +3 -3
  220. package/src/workflows/human-decision.ts +795 -340
  221. package/src/workflows/index.ts +15 -19
  222. package/src/workflows/schema.ts +19 -1
  223. package/src/workflows/store.ts +1295 -1163
  224. package/src/workflows/types.ts +61 -81
  225. package/dist/workflows/artifacts.d.ts +0 -40
  226. package/dist/workflows/artifacts.js +0 -155
  227. package/dist/workflows/artifacts.js.map +0 -1
  228. package/dist/workflows/migrate-sources.d.ts +0 -42
  229. package/dist/workflows/migrate-sources.js +0 -133
  230. package/dist/workflows/migrate-sources.js.map +0 -1
  231. package/docs/run-bundles.md +0 -481
  232. package/src/workflows/artifacts.ts +0 -188
  233. package/src/workflows/migrate-sources.ts +0 -178
package/docs/workflows.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  This document is the authoring reference for pi-workflows definitions. It
4
4
  covers the file format, every node type, edge routing, the step contract the
5
- model sees, and how runs behave at runtime. For the on-disk run format, see
6
- [run-bundles.md](run-bundles.md).
5
+ model sees, and how runs behave at runtime. For durable state, see
6
+ [SQLITE_STATE.md](SQLITE_STATE.md).
7
7
 
8
8
  ## Workflow files
9
9
 
@@ -15,8 +15,8 @@ Files are discovered by suffix (`.workflow.ts`, `.workflow.js`, `.workflow.mts`,
15
15
  2. `~/.pi/agent/workflows/` globally
16
16
  3. Workflows built into Pi Workflows
17
17
 
18
- Pi Workflows includes built-in `autoplan`, `autodoc`, `autoimplement`,
19
- `plan-approval`, `sanity-check`, and `monitor` workflows. `autoplan` is the current name for the
18
+ Pi Workflows includes built-in `plain-summary`, `autoplan`, `autodoc`,
19
+ `autoimplement`, `plan-approval`, `sanity-check`, and `monitor` workflows. `autoplan` is the current name for the
20
20
  planning workflow that was first released as `autodevise`; the old command and
21
21
  export are not retained. A project or global file named `monitor.workflow.ts`
22
22
  replaces the built-in monitor. The package registers each built-in in
@@ -105,11 +105,11 @@ Function actions receive `WorkflowActionContext`, which adds
105
105
 
106
106
  Every interactive `/workflow` run is tracked in the project run queue (see
107
107
  [CONTROLLERS.md](CONTROLLERS.md) for the store). The session that starts a run
108
- claims it and owns it while it executes; every bundle write proves the claim
108
+ claims it and owns it while it executes; every owner-only SQLite write proves the claim
109
109
  first (write fencing).
110
110
 
111
111
  Closing the Pi session mid-run no longer cancels the run. The engine **parks**:
112
- it stops without a terminal event, releases the claim, and leaves the bundle
112
+ it stops without a terminal event, releases the claim, and leaves the run
113
113
  resumable. When a runner is available again (a reopened Pi session or the
114
114
  standalone host), the run **resumes** at the node it stopped on. Completed
115
115
  nodes replay from the recorded state; only the interrupted node and everything
@@ -124,9 +124,11 @@ pi-workflows host --project /path/to/project
124
124
  ```
125
125
 
126
126
  The host claims parked runs, resumes them, and reconciles durable controllers.
127
- Conversation nodes execute in headless `pi --mode rpc` children that load a
128
- small bridge extension; the model sees the same `workflow` tool contract as an
129
- in-session run. The host is a foreground process: start it in a terminal and
127
+ Agent nodes that submit through the workflow tool execute in headless
128
+ `pi --mode rpc` children that load a small bridge extension. An agent node with
129
+ `expectedOutput: assistantMessage()` parks before prompting and waits for the
130
+ origin Pi session because its result must be a visible assistant message. A
131
+ detached run without an origin session fails clearly. The host is a foreground process: start it in a terminal and
130
132
  stop it with Ctrl-C. A second host for the same project refuses to start, and
131
133
  a host that dies has its orphaned children reaped by the next one. While the host works, reports enter a durable outbox addressed to the Pi
132
134
  session that started the run. They remain pending while that session is closed
@@ -136,8 +138,9 @@ and never enter another conversation in the same project.
136
138
 
137
139
  ### agent
138
140
 
139
- Sends a prompt into the current pi conversation and waits for the model to
140
- submit output through the `workflow` tool.
141
+ Sends a prompt to the model. `expectedOutput` selects one of two output forms.
142
+
143
+ The existing string form waits for a `workflow submit` call:
141
144
 
142
145
  ```typescript
143
146
  agent({
@@ -152,14 +155,28 @@ agent({
152
155
  });
153
156
  ```
154
157
 
155
- The engine appends a step contract to the prompt (see below). When the model
156
- calls the tool, the output passes through normalization (a JSON string is
157
- parsed tolerantly) and then `validate`. If `validate` throws, the tool call
158
- returns an error and the model can retry within the same step. If the agent
159
- ends its turn without submitting, the extension nudges it, twice by default,
160
- then fails the step. If an agent node times out or the workflow is cancelled,
161
- the extension also aborts its active Pi turn. The model cannot continue to use
162
- tools after the engine has closed that attempt.
158
+ The assistant-message form waits for one normal visible response and uses its
159
+ exact text as the node output:
160
+
161
+ ```typescript
162
+ agent({
163
+ prompt: ({ outputs }) => `Explain this plainly: ${JSON.stringify(outputs.review)}`,
164
+ expectedOutput: assistantMessage(),
165
+ });
166
+ ```
167
+
168
+ `assistantMessage()` has no default character limit. Authors can opt in with
169
+ `assistantMessage({ maxChars: 2_000 })`. It cannot be combined with `validate`
170
+ because an invalid response is already visible and must not be retried.
171
+
172
+ For submitted output, the engine appends the existing workflow-tool contract.
173
+ The output passes through tolerant JSON normalization and then `validate`.
174
+ Rejected submissions can retry in the same step. If the model settles without
175
+ submitting, the extension nudges it twice by default and then fails the step.
176
+ For assistant-message output, the engine appends a normal-response contract,
177
+ waits for `agent_settled`, rejects empty, failed, aborted, or tool-only results,
178
+ and never suppresses the visible text. Timeout and cancellation abort either
179
+ form's active Pi turn.
163
180
 
164
181
  `timeoutMs` can be a finite positive number, `null`, or a function of the normal
165
182
  node context that returns either value. Omit it to use the 15-minute engine
@@ -259,10 +276,10 @@ schema, limits, estimation, and error rules.
259
276
 
260
277
  ### checkpoint
261
278
 
262
- Ends the run in a `waiting` state for human review. The checkpoint bundle is
279
+ Ends the run in a `waiting` state for human review. The checkpoint run is
263
280
  terminal, so no process keeps running while the run waits. The human answers
264
281
  with `/workflow answer <json>` (or plain text), which starts a **continuation
265
- run**: a new run with its own bundle and trace, linked to the checkpointed run
282
+ run**: a new run with its own state and events, linked to the checkpointed run
266
283
  through `parentRunId`. The continuation receives the answer as its input,
267
284
  carries forward every output the parent produced (including the checkpoint's),
268
285
  and continues routing along the checkpoint's outgoing edge. Outgoing edges
@@ -417,9 +434,29 @@ The normal extension offers all actions. The headless RPC bridge offers only
417
434
  `update` and `submit`, so a workflow child cannot recursively control other
418
435
  runs.
419
436
 
437
+ ### Built-in plain summary
438
+
439
+ The built-in `plain-summary` workflow turns supplied structured data into one
440
+ short normal assistant message. Its input has `source`, `purpose`, optional
441
+ `mustInclude`, optional `maxChars`, optional `maxSentences`, and `format` set to
442
+ `paragraphs`, `bullets`, or `mixed`. The workflow defaults to 2,000 characters,
443
+ five sentences, and mixed format. These are workflow-specific limits;
444
+ `assistantMessage()` itself has no default limit.
445
+
446
+ The summarizer uses only the supplied source, treats instructions inside that
447
+ source as data, keeps required points, and returns the same text as its
448
+ `completed` result. The source enters the normal model prompt and Pi session,
449
+ so callers must pass only data that is suitable for that conversation. It has no notify node or final presentation prompt, so
450
+ including it in another workflow produces one readable assistant response
451
+ before the parent continues.
452
+
420
453
  ### Built-in planning and implementation
421
454
 
422
- The built-in `autoplan` workflow selects a practical in-scope solution and writes a detailed plan. The standalone `autodoc` workflow finds an already selected plan, records it in canonical documentation, verifies those documents, and never devises or implements. The built-in `autoimplement` workflow finds a clear existing plan from explicit input, conversation context, or referenced canonical documents. It blocks when no clear plan exists. An explicit plan bypasses autodoc only when a current-document receipt carries its matching plan digest; otherwise autodoc inspects and adopts or updates the canonical documents. Later invalidating evidence returns to `autoplan` followed by `autodoc`.
455
+ The built-in `autoplan` workflow records two through four practical candidates,
456
+ describes the ideal separately, chooses one option, records a rejection reason
457
+ for every other explicit option, and writes a detailed plan. It then includes
458
+ `plain-summary` to show the chosen plan, its main steps, and the rejected options
459
+ in one short assistant message. The detailed records remain in the run bundle. The standalone `autodoc` workflow finds an already selected plan, records it in canonical documentation, and never devises or implements. It prepares a safe workspace only when documentation must change. Program actions run candidate checks, compare eligible failures with the base revision in a temporary detached worktree, and keep matching baseline failures visible without blocking the current change. The built-in `autoimplement` workflow finds a clear existing plan from explicit input, conversation context, or referenced canonical documents. A missing-plan claim and every other non-exempt blocker enter one bounded challenge path. An explicit plan bypasses autodoc only when a current-document receipt carries its matching plan digest; otherwise autodoc inspects and adopts or updates the canonical documents. Later invalidating evidence returns to `autoplan` followed by `autodoc`.
423
460
 
424
461
  The built-in `plan-approval` workflow offers `continue`, `stop`, and exact-text `replan` exits. Its shared policy uses `auto`, `required`, or `skip` mode. Omitted policy defaults to `auto`: ask audience `operator`, then continue with the exact plan after 10 minutes without an answer. Required mode waits for a human. Skip mode creates no decision. Stop and replan always require a human answer.
425
462
 
@@ -427,22 +464,17 @@ The internal plan-change workflow composes Autoplan, Autodoc, plan approval, and
427
464
 
428
465
  Autoimplement runs independent commands through bounded command batches. A batch is an ordinary function action that calls the public `runCommandBatch` helper. Each command has a stable ID, executable, arguments, absolute working directory, timeout, and output limit. Results stay separate and return in input order. One command uses the same path with concurrency one.
429
466
 
430
- Autoimplement gives `implement` an eight-hour deadline. When a supported
431
- long-running agent node times out, one shared read-only fallback inspects the
432
- current repository, accepted workflow outputs, and relevant pull-request state.
433
- It then retries the timed-out stage or routes to verification, review, CI,
434
- delivery, the existing redesign workflow, or blocked. The fallback can run at
435
- most three times in one Autoimplement run. Its own failure or timeout is
436
- terminal. Cancellation remains immediate and never enters fallback. A repeated
437
- effect step first checks what already exists and performs only missing work.
438
- This graph fallback starts after the timed-out turn ends and is separate from
439
- successor-turn delivery.
467
+ Autoimplement prepares the workspace before its first edit-capable node. `workspaceMode` accepts `auto`, `branch`, `worktree`, or `defaultBranch`. Auto mode adopts a current task branch, creates a model-named branch from a clean default branch, or creates a model-named standard sibling worktree when the default checkout has existing work. Program actions validate and apply names. Direct default-branch work requires explicit authority and does not imply commit, push, merge, or release authority. Every later stage uses the prepared absolute path.
468
+
469
+ Autoimplement gives `implement` an eight-hour deadline. When a supported step fails or times out, one shared bounded recovery step inspects accepted outputs and durable repository or pull-request state. It adopts a completed effect or retries only a missing effect. Cancellation remains immediate and never enters recovery. Unsupported or uncertain effects create a qualified blocker claim before challenge.
440
470
 
441
- Autoimplement uses batches for pi-reviewer, pending CI watches, and local verification commands from independent repositories. It keeps model turns, fixes, pushes, comment changes, merges, and releases in their existing order. Reviewer commands are tied to the repository, base branch, pushed head, and relevant dependency fingerprint. A later review round includes only repositories whose head or dependency fingerprint changed. P0 or P1 work still requires another review. P2-only work can be addressed and verified without another reviewer run only because of that P2 work.
471
+ Local verification uses the shared change-verification composition. Direct program actions run candidate checks and read-only base-eligible checks with the same command, arguments, timeout, and output limit. Results separate related, unrelated, fixed-baseline, unknown, and untested findings. Matching base failures do not block the candidate. Related failures enter a two-attempt mechanical or semantic repair loop. Unknown or incomplete evidence needs bounded judgment, and truncated, timed-out, cancelled, or spawn-failed output cannot pass.
472
+
473
+ Autoimplement uses batches for pi-reviewer and pending CI watches. It keeps model turns, fixes, pushes, comment changes, merges, and releases in their existing order. Reviewer commands are tied to the repository, base branch, pushed head, and relevant dependency fingerprint. A later review round includes only repositories whose head or dependency fingerprint changed. P0 or P1 work still requires another review. P2-only work can be addressed and verified without another reviewer run only because of that P2 work.
442
474
 
443
475
  Autoimplement inspects every pull request before it waits for CI. It accepts only supported pending `gh pr checks --watch` or `gh run watch` descriptors and binds each one to the validated pull request as `gh pr checks <PR URL> --watch`. Repository and pull-request overrides are rejected. One watch lasts at most five minutes. A failed or timed-out watch affects only its pull request. When checks remain pending, the model runs more useful local tests before checking CI again. Autoimplement does not invent an ETA.
444
476
 
445
- The action abort signal stops active command process groups and prevents queued commands from starting. Accepted outputs use the existing trace and artifacts. An interrupted unaccepted batch runs again because batch commands are read-only or isolated local checks. Progress updates contain metadata only and never control routing. Truncated reviewer or CI output cannot count as clean. See [Run independent commands in bounded batches](plans/2026-08-20-bounded-command-batches-plan.md) for the complete contract and implementation plan.
477
+ The action abort signal stops active command process groups and prevents queued commands from starting. Accepted outputs use immutable events and content-addressed blobs. An interrupted unaccepted batch runs again because batch commands are read-only or isolated local checks. Progress updates contain metadata only and never control routing. Truncated reviewer or CI output cannot count as clean. See [Run independent commands in bounded batches](plans/2026-08-20-bounded-command-batches-plan.md) for the complete contract and implementation plan.
446
478
 
447
479
  A model-generated blocker from implementation or a safe later stage does not end autoimplement by itself. A separate blocker-challenge agent checks the task, approved plan, current result, evidence, scope, authority, earlier attempts, and practical alternatives. It confirms a blocker only when the blocker exists now, is outside the granted authority, has no safe path forward, has an empty next action, and includes concrete evidence and checked alternatives. A rejected blocker must name the next practical action and routes through the existing redesign workflow before implementation and verification continue.
448
480
 
@@ -463,7 +495,7 @@ Serial mode is the default. It runs one review session for all four review areas
463
495
 
464
496
  The workflow collects pull request intent and repository diff evidence before model review. It bounds evidence and review results before prompt construction and marks truncated input. Every review must cite evidence and give the strongest case for accepting the current design. The verification session removes unsupported claims, requires exact file and symbol references, resolves supported conflicts, and returns `keep`, `simplify`, `refactor`, `drop`, or `needs_evidence`.
465
497
 
466
- Sanity Check revision 3 creates child sessions directly through the documented Pi SDK. A private built-in runner uses `createAgentSession` with `SessionManager.inMemory`, one independent context per child, and only the verified built-in `read`, `grep`, `find`, and `ls` tools. Child sessions load no skills, prompt templates, themes, or context files. They create no Pi session file.
498
+ Sanity Check revision 4 creates child sessions directly through the documented Pi SDK. A private built-in runner uses `createAgentSession` with `SessionManager.inMemory`, one independent context per child, and only the verified built-in `read`, `grep`, `find`, and `ls` tools. Child sessions load no skills, prompt templates, themes, or context files. They create no Pi session file.
467
499
 
468
500
  The parent Pi process keeps its normal configured extensions enabled. The child runner resolves enabled user extension paths, excludes Pi Workflows and project extensions by default, and preflights the remaining paths without creating a session. It admits only the extension that registers the exact configured provider, plus any behavior extension on an explicit private allowlist. It rejects competing provider owners, workflow tools or commands, and extensions that replace a built-in read-only tool. The admitted paths are frozen for the group, and each child loads only those explicit paths without a second discovery pass.
469
501
 
@@ -477,40 +509,51 @@ Only bounded final assistant text and safe operational facts leave a live child
477
509
 
478
510
  The workflow publishes aggregate and per-agent `pi-workflows.progress.v1` tracks under `agents/review/*` and `agents/verification/*`. Progress contains role, the verified actual model when known, state, elapsed facts, and safe phases such as `thinking` or `tool: read`. The Pi widget shows the aggregate plus failed and active children within its ten-line limit. `piw` shows every durable child track and its samples. Both views use existing progress records, so no child workflow run or new persisted schema is needed.
479
511
 
480
- Serial mode still uses two sessions, and parallel mode still uses five. Prompts, review areas, strict result validation, verdicts, and final notification stay unchanged. The workflow sends the final report through a final notification with `triggerTurn: false`, so the origin model does not produce another response. The CLI, JSON or RPC stream, temporary prompt file, standard-output cap, subprocess fallback, shared child runtime, and blanket child-extension ban are not retained. See [the Sanity Check plan](plans/2026-08-21-sanity-check-plan.md) for the selected implementation and test boundaries.
512
+ Serial mode still uses two child sessions, and parallel mode still uses five. Review prompts, review areas, strict result validation, verdicts, and progress stay unchanged. After verification, an assistant-message agent shows the full bounded report verbatim. A mismatch stops before summary generation. The graph then includes `plain-summary`, which shows a short plain-language explanation with the verdict and the most important next action. The detailed response always settles before the summary starts. A final compute node returns the original strict result, so presentation cannot change the verdict. Sanity Check uses no final notification or root `presentationPrompt`.
513
+
514
+ The CLI, JSON or RPC stream, temporary prompt file, standard-output cap, subprocess fallback, shared child runtime, and blanket child-extension ban are not retained. See [the Sanity Check plan](plans/2026-08-21-sanity-check-plan.md) for the selected implementation and test boundaries.
481
515
 
482
516
  ### Built-in monitor
483
517
 
484
- The built-in `monitor` workflow turns a plain request for repeated checks into
485
- one looping workflow run. Its input is:
518
+ The built-in `monitor` workflow turns a plain request to finish and monitor an
519
+ authorized goal into one looping workflow run. It accepts only `task`,
520
+ `stopWhen`, `everyMinutes`, and `maxChecks`:
486
521
 
487
522
  ```json
488
523
  {
489
- "task": "Check pull request 123",
490
- "stopWhen": "The pull request is merged or closed",
491
- "repair": {
492
- "authorized": true,
493
- "scope": "the current repository"
494
- }
524
+ "task": "Finish pull request 123 within the recorded repository and delivery authority.",
525
+ "stopWhen": "The pull request is merged or safe continuation is blocked.",
526
+ "everyMinutes": 30
495
527
  }
496
528
  ```
497
529
 
498
- The first check runs immediately. Omit `repair` for observation-only monitoring. An authorized repair routes through the shared plan-change workflow, Autoimplement, and a fresh check. A repeated issue with unchanged target evidence stops as blocked. Omit `repair.approval` for the 10-minute autonomous default. Use `approval.mode: "required"` to wait for an explicit answer or `approval.mode: "skip"` to continue without asking.
530
+ The first `observe` step runs immediately and is read-only. It inspects the real
531
+ target with normal tools and chooses `wait`, `act`, or `stop`. `wait` means that
532
+ useful target work is moving or an external event must finish. `act` states one
533
+ safe action that existing authority permits. `stop` means that the goal is
534
+ complete or cannot continue safely.
499
535
 
500
- `everyMinutes` defaults to 30. Each accepted check must provide one concise report and choose `continue`, `repair` when authorized, or `stop`. The
536
+ An `advance` or `recover` action runs directly in a separate normal-tools step.
537
+ A `repair` action composes the shared plan-change workflow and Autoimplement.
538
+ Monitor observes again immediately after every action. It stops instead of
539
+ repeating a completed repair when the same stable failure and target state
540
+ return. The timer is reachable only from `wait`.
541
+
542
+ `everyMinutes` defaults to 30. Every accepted observation provides one concise
543
+ report that separates Monitor state, goal state, and target work state. The
501
544
  runtime queues that report as a workflow notification with `triggerTurn:
502
- false`, so it does not cause an assistant reply. A check can also provide
503
- independent progress tracks. The regular Pi model running the check observes
504
- the target and submits those facts. Pi Workflows validates the counts and
505
- calculates rates, confidence, and ETA deterministically. The target does not
506
- need a Pi Workflows dependency or reporting protocol.
545
+ false`, so it does not cause an assistant reply. An observation can also provide
546
+ independent progress tracks. The regular Pi model observes the target and
547
+ submits those facts. Pi Workflows validates counts and calculates rates,
548
+ confidence, and ETA deterministically. The target does not need a Pi Workflows
549
+ dependency or reporting protocol.
507
550
 
508
551
  Intervals must be whole minutes from 1 through 1,440. When `stopWhen` is
509
552
  omitted, the monitor stops only after an explicit user request. `maxChecks`
510
- defaults to the disclosed safety ceiling of 1,000 and cannot exceed it. Callers
511
- omit `maxChecks` unless the user requests a fixed count. `checkTimeoutMinutes`
512
- is from 5 through 1,440 and defaults to the larger of 60 and `everyMinutes`.
513
- See [MONITOR.md](MONITOR.md) for the check and progress schemas.
553
+ defaults to the disclosed observation safety limit of 1,000 and cannot exceed
554
+ it. Callers omit `maxChecks` unless the user requests a fixed count. Unknown
555
+ fields fail before a run is created. See [MONITOR.md](MONITOR.md) for the
556
+ observation, action, and progress schemas.
514
557
 
515
558
  The interval uses the existing shell action to launch the current Node
516
559
  executable with a timer. This works on every platform supported by Pi. The node
@@ -559,8 +602,8 @@ and [Deferred workflow turns](DEFERRED_TURNS.md) for the successor-turn contract
559
602
 
560
603
  ## Result presentation
561
604
 
562
- Workflow nodes produce structured JSON for routing and persistence. When a
563
- person should see a normal prose response after the run, add
605
+ Workflow nodes normally produce structured values for routing and persistence.
606
+ When a person should see a normal prose response only after the root run, add
564
607
  `presentationPrompt` at the top level:
565
608
 
566
609
  ```typescript
@@ -588,8 +631,14 @@ or normal user turn starts; stale presentations are discarded. Once a presentati
588
631
  been queued, another workflow cannot start until that assistant response
589
632
  settles, so results cannot interleave.
590
633
 
634
+ An agent with `expectedOutput: assistantMessage()` is different. Its visible
635
+ assistant response is the node output, can appear before later nodes, and also
636
+ works inside an included workflow. A root `presentationPrompt` would add a
637
+ second response, so workflows that end with assistant-message output normally
638
+ omit it.
639
+
591
640
  Presentation is outside the workflow graph: it cannot route to another node,
592
- change the run status, or alter the run bundle. If prompt generation or message
641
+ change the run status, or alter the SQLite run state. If prompt generation or message
593
642
  delivery fails, the extension reports a warning and leaves the finished run
594
643
  unchanged. Opting in adds one hidden custom message and one assistant response
595
644
  to the normal Pi session; it adds no other persistent data and uses no Pi
@@ -598,7 +647,7 @@ internals.
598
647
  ## Runtime behavior
599
648
 
600
649
  Runs execute one node at a time. Every transition is persisted to the run
601
- bundle before the engine moves on, which is what makes the live viewer
650
+ database transaction before the engine moves on, which is what makes the live viewer
602
651
  possible. Defaults worth knowing:
603
652
 
604
653
  - Node timeout is 15 minutes unless the node sets `timeoutMs` to a positive
@@ -617,7 +666,7 @@ possible. Defaults worth knowing:
617
666
  `/workflow resume` re-delivers the pending step prompt.
618
667
  - A model-started workflow is persisted as `queued` with its final run ID before the start tool
619
668
  returns. Activation waits for the initiating agent turn to settle, then moves through `starting`
620
- and `running`. `workflow status` and `workflow cancel` accept the run ID before a run bundle
669
+ and `running`. `workflow status` and `workflow cancel` accept the run ID before a SQLite run state
621
670
  exists.
622
671
  - If deferred activation fails, the queue stores a bounded safe error, releases the session
623
672
  reservation, and creates one deferred-turn intent for the initiating session. A workflow that
@@ -630,7 +679,7 @@ possible. Defaults worth knowing:
630
679
  is explicit user control. When no run is live but the widget still shows a parked or finished run,
631
680
  the command clears the widget.
632
681
  - One workflow runs per session at a time.
633
- - After the workflow tool accepts an agent-step submission, the extension removes any assistant tail text from the rest of that agent run. The next workflow message is the visible continuation. A deferred intent makes a workflow prompt, presentation, and factual fallback compete to provide one successor turn, so an abort cannot produce two continuation turns.
682
+ - After the workflow tool accepts an agent-step submission, any assistant text that follows remains visible. The next workflow message continues the graph. A deferred intent makes a workflow prompt, presentation, and factual fallback compete to provide one successor turn, so an abort cannot produce two continuation turns.
634
683
  - Agent nudges: if the model ends its turn without submitting the pending
635
684
  step, it gets a reminder, twice by default, then the step fails.
636
685
 
@@ -657,7 +706,7 @@ if (run.state !== "succeeded") {
657
706
  }
658
707
  ```
659
708
 
660
- Child workflow completion queues the parent resource again. A running child left by a stopped host is recorded as a failed run bundle with a `run_interrupted` event. The controller treats that child attempt as interrupted, and the next parent reconciliation starts another immutable attempt. Consequential external mutations should use the controller effect API so uncertain results are observed before retry.
709
+ Child workflow completion queues the parent resource again. A running child left by a stopped host is recorded as a failed SQLite run state with a `run_interrupted` event. The controller treats that child attempt as interrupted, and the next parent reconciliation starts another immutable attempt. Consequential external mutations should use the controller effect API so uncertain results are observed before retry.
661
710
 
662
711
  See [CONTROLLERS.md](CONTROLLERS.md) for controller definitions and the full recovery contract.
663
712
 
@@ -0,0 +1 @@
1
+ export { plainSummaryWorkflow as default } from "@osolmaz/pi-workflows/builtins";
package/herdr-plugin.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  id = "osolmaz.pi-workflows"
2
2
  name = "pi-workflows"
3
- version = "0.12.1"
3
+ version = "0.13.1"
4
4
  min_herdr_version = "0.7.0"
5
5
  description = "Open the active pi-workflows run in piw from a managed Herdr pane."
6
6
  platforms = ["linux", "macos"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osolmaz/pi-workflows",
3
- "version": "0.12.1",
3
+ "version": "0.13.1",
4
4
  "description": "Workflow and controller runtime with a live terminal viewer for the pi coding agent",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -1,22 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawn, spawnSync } from "node:child_process";
4
- import fs from "node:fs";
5
- import path from "node:path";
6
4
 
7
5
  const runId = process.env.PI_WORKFLOWS_RUN_ID ?? "";
8
- const runDir = process.env.PI_WORKFLOWS_RUN_DIR ?? "";
9
6
 
10
7
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/u.test(runId)) {
11
8
  fail("PI_WORKFLOWS_RUN_ID is missing or invalid.");
12
9
  }
13
- if (!path.isAbsolute(runDir) || path.basename(runDir) !== runId) {
14
- fail("PI_WORKFLOWS_RUN_DIR must be the absolute bundle directory for the selected run.");
15
- }
16
- if (!fs.existsSync(path.join(runDir, "manifest.json"))) {
17
- fail(`Workflow bundle not found: ${runDir}`);
18
- }
19
-
20
10
  const paneId = process.env.HERDR_PANE_ID ?? "";
21
11
  if (!/^[A-Za-z0-9]+:p[A-Za-z0-9]+$/u.test(paneId)) {
22
12
  fail("HERDR_PANE_ID is missing or invalid.");
@@ -33,7 +23,7 @@ if (labeled.status !== 0) {
33
23
  fail(`Could not label the Herdr viewer pane: ${bounded(labeled.stderr) || "unknown error"}`);
34
24
  }
35
25
 
36
- const viewer = spawn("piw", [runDir], { stdio: "inherit" });
26
+ const viewer = spawn("piw", [runId], { stdio: "inherit" });
37
27
  for (const signal of ["SIGINT", "SIGTERM"]) {
38
28
  process.on(signal, () => viewer.kill(signal));
39
29
  }
@@ -15,6 +15,10 @@ Build the input as follows:
15
15
  - `task`: State what selected plan must be recorded and that this run is documentation-only.
16
16
  - `plan`: Pass the complete selected plan. Autodoc does not devise or improve it.
17
17
  - `repository`: Use the absolute path of the repository that owns the canonical documentation.
18
+ - `baseBranch`: Use the requested base or the repository default branch.
19
+ - `scope`: Name the allowed repository and documentation edits. Exclude implementation and unauthorized remote actions.
20
+ - `workspaceMode`: Use `auto` unless the conversation requires `branch`, `worktree`, or explicitly authorized `defaultBranch` work. Autodoc prepares the workspace only when documentation needs an update.
21
+ - `preparedWorkspace`: Include a previously confirmed `pi-workflows.prepared-workspace.v1` result when a parent workflow already prepared the workspace. Omit it otherwise.
18
22
  - `documents`: Include every known canonical specification or plan candidate. Use an empty array when none is known.
19
23
  - `evidence`: Include implementation evidence or current-document evidence when it affects whether documentation is current.
20
24
 
@@ -31,6 +35,9 @@ Replace the example values below with facts from the conversation, then make one
31
35
  "requirements": ["Keep cancellation terminal."]
32
36
  },
33
37
  "repository": "/absolute/path/to/repository",
38
+ "baseBranch": "main",
39
+ "scope": "Only /absolute/path/to/repository. May update canonical documentation and run documentation checks. Must not implement, push, merge, release, or deploy.",
40
+ "workspaceMode": "auto",
34
41
  "documents": ["docs/plans/timeout-fallback-plan.md"],
35
42
  "evidence": {
36
43
  "currentBehavior": "A timeout ends the run."
@@ -18,6 +18,9 @@ Build the input as follows:
18
18
  - `scope`: Always include a concrete authority statement. Name every allowed repository and the allowed edit, test, commit, push, pull-request, merge, and release actions. Carry forward exclusions from the conversation. A repository path alone is not a scope.
19
19
  - `constraints`: Include all applicable user and repository constraints. Use an empty array when none apply.
20
20
  - `baseBranch`: Use the requested base or the repository default branch.
21
+ - `workspaceMode`: Use `auto` unless the user or repository requires `branch`, `worktree`, or `defaultBranch`. `auto` keeps a correct task branch, creates a task branch from a clean default branch, and isolates a dirty default checkout in a standard sibling worktree. Use `defaultBranch` only with explicit direct-work authority.
22
+ - `preparedWorkspace`: Include a previously confirmed `pi-workflows.prepared-workspace.v1` result when the workspace was prepared before the run. Omit it otherwise.
23
+ - `directDefaultBranchAuthorized`: Set `true` only when direct work on the actual default branch is explicit. It does not grant commit, push, merge, or release authority.
21
24
  - `merge`: Set `true` only when the user explicitly requested merge or an applicable standing instruction authorizes it. Otherwise set `false`.
22
25
  - `documents`: Include known canonical plan or specification paths. Use an empty array when none are known.
23
26
  - `approval`: Omit it for the default behavior: ask on each new plan and continue after 10 minutes without an answer. Use `{ "mode": "required" }` when the user says to block on plan changes. Use `{ "mode": "skip" }` when the user says to continue without asking about plan changes.
@@ -46,6 +49,7 @@ Replace the example values below with facts from the conversation, then make one
46
49
  "scope": "Only /absolute/path/to/repository. May edit and test task-related files, create commits, push the task branch, and open or update its pull request. Must not modify other repositories, merge, release, deploy, change credentials, or change repository policy.",
47
50
  "constraints": ["Preserve immediate cancellation.", "Keep deferred-turn work separate."],
48
51
  "baseBranch": "main",
52
+ "workspaceMode": "auto",
49
53
  "merge": false,
50
54
  "documents": ["docs/plans/timeout-fallback-plan.md"]
51
55
  }
@@ -37,13 +37,14 @@ When this skill is loaded inside an active workflow step, do not start another w
37
37
  Outside Pi, or when the workflow is unavailable:
38
38
 
39
39
  1. Frame the problem, observable success criteria, scope, constraints, and interfaces under our control.
40
- 2. Devise the most elegant long-term production-ready solution within that scope.
40
+ 2. Record two through four distinct practical candidates. Give each one a stable id, short title, plain gist, full solution, rationale, parts, and trade-offs.
41
41
  3. Describe the holy grail separately. Name every dependency outside our authority.
42
- 4. Choose the right option without asking the user to decide between them.
42
+ 4. Choose the right option without asking the user to decide between them. Record one rejection reason for every other explicit candidate.
43
43
  - Choose the ideal when it is proportionate, production-ready, in scope, and implementable through interfaces we control.
44
44
  - Otherwise choose the strongest practical in-scope solution with a clear path toward the ideal.
45
45
  - Do not block only because the ideal requires an upstream or external change.
46
46
  5. Write a detailed implementation plan. For each step, state what changes, where it changes, and how to verify it.
47
- 6. Stop as blocked only when no truthful in-scope solution can meet the success criteria.
47
+ 6. Present one short plain assistant message with the chosen plan, its main steps, and a one-line gist and rejection reason for every other candidate. Call it selected for approval when a later human decision still applies.
48
+ 7. Stop as blocked only when no truthful in-scope solution can meet the success criteria.
48
49
 
49
- When revising a plan, preserve the previous plan and new evidence. State whether the plan changed and why. Do not implement unless the user also requested implementation.
50
+ When revising a plan, preserve the previous plan and new evidence. Record whether the previous plan remains a candidate or why new evidence rejects it. State whether the final plan changed and why. “All plans” means the explicit candidate records, never hidden model reasoning. Do not implement unless the user also requested implementation.