@osolmaz/pi-workflows 0.9.0 → 0.10.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 (78) hide show
  1. package/README.md +50 -16
  2. package/dist/builtins/autodevise.workflow.d.ts +58 -0
  3. package/dist/builtins/autodevise.workflow.js +190 -0
  4. package/dist/builtins/autodevise.workflow.js.map +1 -0
  5. package/dist/builtins/autoimplement.workflow.d.ts +154 -0
  6. package/dist/builtins/autoimplement.workflow.js +729 -0
  7. package/dist/builtins/autoimplement.workflow.js.map +1 -0
  8. package/dist/builtins/catalog.js +5 -1
  9. package/dist/builtins/catalog.js.map +1 -1
  10. package/dist/builtins/index.d.ts +3 -0
  11. package/dist/builtins/index.js +4 -0
  12. package/dist/builtins/index.js.map +1 -0
  13. package/dist/builtins/monitor.workflow.d.ts +25 -3
  14. package/dist/builtins/monitor.workflow.js +200 -13
  15. package/dist/builtins/monitor.workflow.js.map +1 -1
  16. package/dist/extension/herdr-viewer.js +2 -6
  17. package/dist/extension/herdr-viewer.js.map +1 -1
  18. package/dist/render/graph-render.js +13 -2
  19. package/dist/render/graph-render.js.map +1 -1
  20. package/dist/workflows/catalog.d.ts +1 -0
  21. package/dist/workflows/catalog.js +6 -0
  22. package/dist/workflows/catalog.js.map +1 -1
  23. package/dist/workflows/composition.d.ts +45 -0
  24. package/dist/workflows/composition.js +471 -0
  25. package/dist/workflows/composition.js.map +1 -0
  26. package/dist/workflows/decision.d.ts +11 -5
  27. package/dist/workflows/decision.js.map +1 -1
  28. package/dist/workflows/definition.d.ts +22 -3
  29. package/dist/workflows/definition.js +46 -3
  30. package/dist/workflows/definition.js.map +1 -1
  31. package/dist/workflows/engine.js +115 -16
  32. package/dist/workflows/engine.js.map +1 -1
  33. package/dist/workflows/graph.js +8 -6
  34. package/dist/workflows/graph.js.map +1 -1
  35. package/dist/workflows/index.d.ts +3 -2
  36. package/dist/workflows/index.js +2 -1
  37. package/dist/workflows/index.js.map +1 -1
  38. package/dist/workflows/loader.d.ts +5 -4
  39. package/dist/workflows/loader.js +118 -18
  40. package/dist/workflows/loader.js.map +1 -1
  41. package/dist/workflows/schema.d.ts +3 -1
  42. package/dist/workflows/schema.js +49 -2
  43. package/dist/workflows/schema.js.map +1 -1
  44. package/dist/workflows/store.js +32 -2
  45. package/dist/workflows/store.js.map +1 -1
  46. package/dist/workflows/types.d.ts +77 -2
  47. package/docs/CONTROLLERS.md +1 -1
  48. package/docs/DESIGN_PHILOSOPHY.md +1 -1
  49. package/docs/MONITOR.md +35 -18
  50. package/docs/WORKFLOW_COMPOSITION.md +326 -0
  51. package/docs/plans/2026-08-19-workflow-composition-plan.md +300 -0
  52. package/docs/run-bundles.md +24 -10
  53. package/docs/workflows.md +65 -12
  54. package/examples/workflows/autodevise.workflow.ts +1 -0
  55. package/examples/workflows/autoimplement.workflow.ts +1 -92
  56. package/herdr-plugin.toml +1 -1
  57. package/package.json +5 -1
  58. package/skills/monitor/SKILL.md +6 -1
  59. package/skills/pi-workflows/SKILL.md +3 -1
  60. package/src/builtins/autodevise.workflow.ts +231 -0
  61. package/src/builtins/autoimplement.workflow.ts +856 -0
  62. package/src/builtins/catalog.ts +5 -1
  63. package/src/builtins/index.ts +13 -0
  64. package/src/builtins/monitor.workflow.ts +242 -15
  65. package/src/extension/herdr-viewer.ts +1 -6
  66. package/src/render/graph-render.ts +14 -2
  67. package/src/workflows/catalog.ts +7 -0
  68. package/src/workflows/composition.ts +627 -0
  69. package/src/workflows/decision.ts +12 -5
  70. package/src/workflows/definition.ts +118 -8
  71. package/src/workflows/engine.ts +151 -18
  72. package/src/workflows/graph.ts +8 -6
  73. package/src/workflows/index.ts +20 -0
  74. package/src/workflows/loader.ts +186 -18
  75. package/src/workflows/schema.ts +62 -2
  76. package/src/workflows/store.ts +37 -2
  77. package/src/workflows/types.ts +109 -2
  78. package/examples/workflows/elegant-solution.workflow.ts +0 -95
@@ -0,0 +1,300 @@
1
+ ---
2
+ title: Add typed workflow composition and automatic repair
3
+ author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
4
+ date: 2026-08-19
5
+ ---
6
+
7
+ # Add typed workflow composition and automatic repair
8
+
9
+ Pi Workflows needs reusable nested workflows with normal TypeScript imports. Monitor must be able to devise and implement a repair when mutation is authorized. Autoimplement must move back to solution design when new evidence invalidates its plan, correct failed reviewer commands, track P0, P1, and P2 findings, and use long CI waits for additional local testing.
10
+
11
+ The canonical behavior is in [Workflow composition](../WORKFLOW_COMPOSITION.md).
12
+
13
+ ## Outcome
14
+
15
+ A workflow can run alone or as a typed child in one durable parent run. Authors can import a child definition, map its input, and route from named exits. Dynamic project, global, built-in, and path references remain available.
16
+
17
+ The package will ship `autodevise`, `autoimplement`, and `monitor` as compatible built-ins. Monitor will remain observation-only by default. An explicitly authorized monitor can run outer solution design, autoimplementation, internal redesign, and a fresh target check without copying workflow nodes.
18
+
19
+ ## Scope
20
+
21
+ ### Public workflow API
22
+
23
+ - Add generic workflow input and named-exit contracts.
24
+ - Add runtime input and exit validation.
25
+ - Add direct typed `includeWorkflow(child, options)` composition.
26
+ - Keep dynamic `includeWorkflow({ workflow, input })` references.
27
+ - Add `defineWorkflowRegistry()` for shipped typed definitions.
28
+ - Type-check child input mappers and parent exit names where the child is imported directly.
29
+
30
+ ### Resolution and execution
31
+
32
+ - Resolve all direct and dynamic includes before `run_started`.
33
+ - Reject direct and indirect source cycles.
34
+ - Compile one qualified executable graph.
35
+ - Give child callbacks a local invocation view.
36
+ - Support repeated and nested mounts.
37
+ - Apply root and per-invocation step limits.
38
+ - Record named entry and exit transitions.
39
+ - Keep one pause, cancellation, checkpoint, update, notification, and presentation lifecycle.
40
+
41
+ ### Persistence and display
42
+
43
+ - Record all child sources and their mount paths.
44
+ - Record a digest of the resolved definition.
45
+ - Refuse normal resume when any source or digest changes.
46
+ - Add mount data to the definition snapshot.
47
+ - Add include entry and exit trace events.
48
+ - Group qualified child nodes in viewers while preserving flat replay.
49
+
50
+ ### Workflow library
51
+
52
+ - Make `autodevise` accept an existing plan and new evidence.
53
+ - Add `ready` and `blocked` exits to `autodevise`.
54
+ - Rebuild `autoimplement` around explicit issue routes.
55
+ - Include `autodevise` inside `autoimplement` for redesign.
56
+ - Track P0, P1, and P2 review findings by round.
57
+ - Rerun review only after P0 or P1 work.
58
+ - Permit P2 work without another reviewer round.
59
+ - Generate, validate, execute, and correct exact Pi Reviewer commands.
60
+ - Track PR comments, CI, merge, and final PR reporting.
61
+ - Bound one CI watch to five minutes.
62
+ - Route a long CI wait to useful local testing before checking CI again.
63
+ - Add authorized repair to monitor through outer `autodevise` and `autoimplement` mounts.
64
+ - Detect repeated repair with no changed issue, plan, implementation, evidence, or target state.
65
+
66
+ ## Non-goals
67
+
68
+ - Do not change Pi core or use private Pi APIs.
69
+ - Do not create another run store, service, or child Pi session.
70
+ - Do not let a child jump into a parent or sibling node.
71
+ - Do not permit recursive include graphs.
72
+ - Do not add unrestricted model-selected node names.
73
+ - Do not let monitor mutate a target without explicit authorization.
74
+ - Do not replace Pi Reviewer with another reviewer after an invocation failure.
75
+ - Do not merge before required gates pass or an allowed unrelated failure is recorded.
76
+ - Do not rewrite existing terminal run bundles.
77
+
78
+ ## Data contracts
79
+
80
+ ### Child result
81
+
82
+ A completed child mount exposes a discriminated result:
83
+
84
+ ```typescript
85
+ type IncludedResult<TExits> = {
86
+ [K in keyof TExits]: { exit: K; output: TExits[K] };
87
+ }[keyof TExits];
88
+ ```
89
+
90
+ ### Source record
91
+
92
+ ```typescript
93
+ type WorkflowMountedSource = {
94
+ mountPath: string[];
95
+ workflowName: string;
96
+ source: WorkflowSource;
97
+ };
98
+ ```
99
+
100
+ ### Review round
101
+
102
+ ```typescript
103
+ type ReviewRound = {
104
+ command: StructuredCommand;
105
+ p0: ReviewFinding[];
106
+ p1: ReviewFinding[];
107
+ p2: ReviewFinding[];
108
+ lower: ReviewFinding[];
109
+ invocationSucceeded: boolean;
110
+ };
111
+ ```
112
+
113
+ P0 or P1 findings route to redesign or fix, then verification, push, and another review. P2-only work routes through a separate verification path and then continues to PR comments without another review.
114
+
115
+ ### CI decision
116
+
117
+ ```typescript
118
+ type CiDecision = {
119
+ status: "green" | "failed" | "pending" | "unavailable";
120
+ relatedFailures: string[];
121
+ unrelatedFailures: string[];
122
+ trackingCommand?: StructuredCommand;
123
+ };
124
+ ```
125
+
126
+ A pending result must include a validated `gh` tracking command. The shell action stops after five minutes. A timeout routes to opportunistic local testing. The workflow checks CI again after that work.
127
+
128
+ ## Implementation sequence
129
+
130
+ ### 1. Typed contracts
131
+
132
+ - Make workflow definitions generic over input and exits.
133
+ - Add source identity, input parser, exit parser, and include declarations.
134
+ - Add direct and dynamic `includeWorkflow()` overloads.
135
+ - Add registry helpers and compile-time contract tests.
136
+ - Keep old workflow definitions valid.
137
+
138
+ ### 2. Composition resolver
139
+
140
+ - Resolve nested direct and dynamic definitions.
141
+ - Preserve parent-relative paths.
142
+ - Build the complete source list.
143
+ - Reject source cycles with the mount chain.
144
+ - Validate child exit nodes and parent include edges.
145
+ - Compile qualified nodes and internal entry and exit transitions.
146
+ - Attach immutable composition metadata to the resolved definition.
147
+
148
+ ### 3. Local execution context
149
+
150
+ - Project each child callback to its mount-local input, outputs, results, and steps.
151
+ - Hide parent and sibling data.
152
+ - Start each re-entry after the latest mount-entry step.
153
+ - Expose only the latest named child result to the parent.
154
+ - Enforce per-invocation and root step limits.
155
+ - Emit include entry and exit events.
156
+
157
+ ### 4. Persistence and resume
158
+
159
+ - Add mounted sources and the resolved digest to state and manifest projections.
160
+ - Add mount metadata to definition snapshots.
161
+ - Compare the complete identity during resume and continuation.
162
+ - Keep old single-source bundles readable.
163
+ - Add trace reconstruction and torn-tail tests for include transitions.
164
+
165
+ ### 5. Viewer grouping
166
+
167
+ - Derive groups from snapshot mount metadata.
168
+ - Keep qualified names in replay and details.
169
+ - Update TypeScript and Rust fixtures together.
170
+
171
+ ### 6. Autodevise
172
+
173
+ - Move the current workflow into the built-in library.
174
+ - Add typed input, `ready`, and `blocked` exits.
175
+ - Accept a previous plan and new evidence.
176
+ - Calculate a plan digest.
177
+ - Return whether the selected plan changed.
178
+ - Keep the current practical, in-scope selection rule.
179
+
180
+ ### 7. Autoimplement
181
+
182
+ Build this graph:
183
+
184
+ ```text
185
+ prepare plan
186
+ -> implement
187
+ -> verify
188
+ -> classify issue
189
+ -> redesign -> autodevise -> implement
190
+ -> fix -> verify
191
+ -> publish -> write reviewer command -> run reviewer
192
+
193
+ review result
194
+ -> command error -> rewrite command -> run reviewer
195
+ -> P0/P1 -> classify issue
196
+ -> P2 -> address P2 -> verify P2 -> PR comments
197
+ -> clean -> PR comments
198
+
199
+ PR comments
200
+ -> redesign
201
+ -> fix
202
+ -> CI
203
+
204
+ CI
205
+ -> related design failure -> redesign
206
+ -> related local failure -> fix
207
+ -> pending -> track for at most five minutes
208
+ -> tracking timeout -> run additional useful tests -> check CI
209
+ -> green or allowed unrelated failure -> merge
210
+ -> unavailable or forbidden -> blocked
211
+ ```
212
+
213
+ The workflow will collect all review rounds in its final output. It will never rerun Pi Reviewer solely because P2 work changed files.
214
+
215
+ ### 8. Monitor repair
216
+
217
+ - Add explicit repair authorization to monitor input.
218
+ - Add `repair` to the check result only when authorization is present.
219
+ - Mount outer `autodevise` and `autoimplement`.
220
+ - Pass the outer plan into autoimplement.
221
+ - Check the target again after a reported repair.
222
+ - Stop on repeated no-progress evidence.
223
+ - Keep ordinary monitor calls observation-only and backward compatible.
224
+
225
+ ### 9. Skills and docs
226
+
227
+ - Update workflow authoring, persistence, monitor, and controller-boundary docs.
228
+ - Align the public monitor and autoimplement skills with the new workflows.
229
+ - Run the normal agent synchronization command in the source repository after skill edits.
230
+ - Record any implementation departure in this plan and the canonical specification.
231
+
232
+ ## Acceptance criteria
233
+
234
+ - Direct imports infer child input and named exits.
235
+ - Invalid direct input mappings fail type checking.
236
+ - Invalid child exit names fail type checking or definition validation.
237
+ - Dynamic references resolve through existing precedence rules.
238
+ - Two mounts of one child do not share invocation state.
239
+ - Nested redesign uses a fresh autodevise invocation.
240
+ - Source cycles fail before the run bundle is created.
241
+ - Included checkpoints, updates, notifications, pause, cancellation, and resume behave like root nodes.
242
+ - Every mounted source and the resolved digest is durable.
243
+ - P0 and P1 work triggers another review round.
244
+ - P2-only work can be addressed without another review round.
245
+ - A failed reviewer command can be corrected and rerun without changing reviewer tools.
246
+ - A pending CI decision supplies an exact command.
247
+ - A CI wait longer than five minutes routes to useful local testing.
248
+ - Monitor mutates only when repair is explicitly authorized.
249
+ - A repaired monitor target is checked again.
250
+ - Repeated repair without changed evidence stops as blocked.
251
+ - Existing workflows and terminal run bundles remain valid.
252
+
253
+ ## Verification
254
+
255
+ Run focused checks while implementing:
256
+
257
+ ```bash
258
+ npx vitest run test/composition.test.ts test/graph.test.ts test/loader.test.ts
259
+ npx vitest run test/engine.test.ts test/run-resume.test.ts test/store.test.ts
260
+ npx vitest run test/builtin-autodevise.test.ts test/builtin-autoimplement.test.ts test/builtin-monitor.test.ts
261
+ ```
262
+
263
+ Run all repository gates before review:
264
+
265
+ ```bash
266
+ npm run check
267
+ npm run test:e2e
268
+ npx slophammer-ts@latest dry .
269
+ npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
270
+ npx -y @simpledoc/simpledoc check
271
+ git diff --check
272
+ ```
273
+
274
+ Run Pi Reviewer against the pushed branch. Fix every P0 and P1 finding and rerun it. P2-only changes do not require another reviewer run unless they expose a new P0 or P1 concern. Check PR comments and CI after review passes.
275
+
276
+ ## Release
277
+
278
+ This adds compatible public APIs to a pre-1.0 package. The planned version is `0.10.0`. Existing `0.9.x` run bundles remain readable, and no published version is rewritten.
279
+
280
+ ## Implementation record
281
+
282
+ The implementation follows the canonical specification with one visible detail: compiled include entry and exit transitions have durable internal step records so resume can reconstruct the active invocation. They do not consume root or child `maxSteps` limits. Viewers label them as entry and named-exit transitions.
283
+
284
+ Direct imports check mapped input and exit names. `includedResult()` recovers the discriminated child result type from a parent output. Dynamic overrides carry a direct contract definition and must match its stable `contractId`, input presence, and named exits.
285
+
286
+ The shipped workflows are registered built-ins:
287
+
288
+ - `autodevise` returns `ready` or `blocked` with plan lineage.
289
+ - `autoimplement` supports redesign, implementation fixes, exact reviewer and CI commands, P0 through P2 history, bounded CI watches, PR comments, merge, and final reporting.
290
+ - `monitor` remains observation-only by default and enables composed repair only through an explicit repair policy.
291
+
292
+ The package and Rust viewer version is `0.10.0`.
293
+
294
+ ## Contract impact
295
+
296
+ - **Session state:** normal workflow messages and tool results only.
297
+ - **Other persistent data:** additive mount, source, digest, review, and CI evidence in existing run bundles.
298
+ - **Pi internals:** none.
299
+ - **Public Pi API:** existing documented extension APIs only.
300
+ - **Public Pi Workflows API:** generic input and exits, direct and dynamic `includeWorkflow()`, and `defineWorkflowRegistry()`.
@@ -142,11 +142,13 @@ Identity and pointers, kept in sync with the state on every snapshot:
142
142
  }
143
143
  ```
144
144
 
145
- `workflowSource` identifies the definition used by the run. User workflow
145
+ `workflowSource` identifies the root definition used by the run. User workflow
146
146
  files use an absolute path and SHA-256 hash. Package-provided workflows use a
147
- stable identity such as `{ "kind": "builtin", "id": "monitor", "revision": "1" }`.
147
+ stable identity such as `{ "kind": "builtin", "id": "monitor", "revision": "4" }`.
148
148
  A built-in identity does not contain an installation path.
149
149
 
150
+ A composed run also records `workflowSources`, sorted by mount path, and `definitionDigest`. Each mounted source has `mountPath`, `workflowName`, and the same file or built-in source identity. The digest is SHA-256 over the resolved definition snapshot.
151
+
150
152
  `paths.artifacts` is declared from bundle creation so a live session-event
151
153
  patch can safely reference a newly written artifact before the next workflow
152
154
  state projection. The directory itself is created only when needed.
@@ -160,8 +162,7 @@ A serializable snapshot of the graph taken at run start
160
162
  (`pi-workflows.definition-snapshot.v1`). Functions such as prompts and
161
163
  validators are not serialized. Each node keeps only its metadata (`nodeType`,
162
164
  `timeoutMs`, `statusDetail`, `expectedOutput`, `summary`, `actionExecution`),
163
- and edges are copied verbatim. The snapshot is what lets viewers draw all
164
- nodes, including ones that have not run yet. It is immutable after run start.
165
+ and edges are copied verbatim. Included nodes also record `mountPath`, `localNodeId`, and internal entry or exit status. The top-level `composition.mounts` list records every mount, entry, named exit, and child step limit. The snapshot is what lets viewers draw all nodes, including ones that have not run yet. It is immutable after run start.
165
166
 
166
167
  ## Resume and repair
167
168
 
@@ -176,10 +177,12 @@ instead of failing. Resume is a named operation with strict rules:
176
177
  `state.traceSeq` and the trace agree again before any new event.
177
178
  3. Completed nodes replay from the projection. The in-flight node reruns with
178
179
  a fresh attempt; a `run_resumed` trace event marks the boundary.
179
- 4. `state.workflowSource` pins the workflow source from run start. File
180
+ 4. `state.workflowSource` pins the root workflow source from run start. File
180
181
  sources require the same hash. Built-in sources require the same catalog
181
- id and revision. Resume refuses a mismatch unless forced, and a forced
182
- resume records the mismatch in the `run_resumed` payload.
182
+ id and revision.
183
+ 5. Composed runs also require the same sorted `workflowSources` and
184
+ `definitionDigest`. A changed or missing child refuses normal resume.
185
+ 6. A forced resume records the identity mismatch in the `run_resumed` payload.
183
186
 
184
187
  Continuation runs (answering a checkpoint) are new bundles, not resumed ones.
185
188
  They link back through `state.parentRunId`, carry the parent's outputs,
@@ -204,6 +207,14 @@ The full run projection (`WorkflowRunState` in
204
207
  "path": "/repo/.pi/workflows/autoimplement.workflow.ts",
205
208
  "hash": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
206
209
  },
210
+ "workflowSources": [
211
+ {
212
+ "mountPath": ["redesign"],
213
+ "workflowName": "autodevise",
214
+ "source": { "kind": "builtin", "id": "autodevise", "revision": "1" }
215
+ }
216
+ ],
217
+ "definitionDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
207
218
  "startedAt": "…",
208
219
  "updatedAt": "…",
209
220
  "status": "running",
@@ -215,9 +226,10 @@ The full run projection (`WorkflowRunState` in
215
226
  }
216
227
  ```
217
228
 
218
- - `workflowSource` is the canonical source identity. Resuming a file requires
219
- the same hash. Resuming a built-in requires the same catalog revision. A
220
- mismatch refuses the resume instead of loading another definition.
229
+ - `workflowSource` is the canonical root source identity. Resuming a file requires
230
+ the same hash. Resuming a built-in requires the same catalog revision.
231
+ - `workflowSources` and `definitionDigest` attest the complete composed graph.
232
+ A mismatch refuses resume instead of loading another child definition.
221
233
  - `status` is one of `running`, `waiting`, `completed`, `failed`, `timed_out`,
222
234
  or `cancelled`. A controller host records an abandoned bundle as `failed`
223
235
  with a final `run_interrupted` trace event. Before doing that, recovery checks
@@ -315,6 +327,8 @@ Event catalog and payload contracts:
315
327
  | `agent_prompt_sent` | agent | `prompt` |
316
328
  | `node_finished` | node | `outcome: "ok"`, `durationMs`, `output`, `conversation?`, `action?` |
317
329
  | `node_failed` | node | `outcome`, `durationMs`, `error`, `conversation?`, `action?` |
330
+ | `include_entered` | run | `mountPath`, `workflowName`, `invocation` |
331
+ | `include_exited` | run | `mountPath`, `workflowName`, `invocation`, `exit`, `output` |
318
332
  | `run_paused` | run | _(empty)_ |
319
333
  | `run_resumed` | run | _(empty)_ |
320
334
  | `run_completed` | run | `status`, `finalOutput` |
package/docs/workflows.md CHANGED
@@ -53,15 +53,20 @@ export default defineWorkflow({
53
53
 
54
54
  Top-level fields:
55
55
 
56
- | Field | Type | Notes |
57
- | -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
58
- | `name` | `string` | Required. Used in run ids and the step contract. `answer`, `cancel`, `list`, `pause`, `resume`, and `status` are reserved for `/workflow` subcommands. |
59
- | `title` | `string` or function | Optional run title, resolved once at start from `{ input, workflowName }`. Async resolution is bounded (30s) and cancellable. |
60
- | `presentationPrompt` | `string` or function | Optional instructions for a normal assistant response after the run. A function receives `{ state, finalOutput, signal }` and may return a prompt or `undefined`. See [Result presentation](#result-presentation). |
61
- | `startAt` | `string` | Required. Id of the first node. |
62
- | `nodes` | `Record<string, node>` | Required, non-empty. Node ids must match `[A-Za-z_][A-Za-z0-9_-]*`. |
63
- | `edges` | `WorkflowEdge[]` | Required. See routing below. |
64
- | `maxSteps` | `number` | Optional loop bound, default 100. The run fails when exceeded. |
56
+ | Field | Type | Notes |
57
+ | -------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
58
+ | `name` | `string` | Required. Used in run ids and the step contract. `answer`, `cancel`, `list`, `pause`, `resume`, and `status` are reserved for `/workflow` subcommands. |
59
+ | `source` | `string` | Optional `import.meta.url` for exact provenance when another TypeScript workflow imports this definition directly. |
60
+ | `contractId` | `string` | Optional stable input-and-exit contract identity. Dynamic overrides must match it. |
61
+ | `input` | `function` | Optional runtime input normalizer and validator. Its return type is the workflow input type. |
62
+ | `title` | `string` or function | Optional run title, resolved once at start from `{ input, workflowName }`. Async resolution is bounded (30s) and cancellable. |
63
+ | `presentationPrompt` | `string` or function | Optional instructions for a normal assistant response after the run. A function receives `{ state, finalOutput, signal }` and may return a prompt or `undefined`. See [Result presentation](#result-presentation). |
64
+ | `startAt` | `string` | Required. Id of the first node. |
65
+ | `nodes` | `Record<string, node>` | Required, non-empty. Node ids must match `[A-Za-z_][A-Za-z0-9_-]*`. |
66
+ | `includes` | `Record<string, include>` | Optional imported or dynamically resolved child workflows. |
67
+ | `exits` | `Record<string, exit>` | Optional named successful terminal nodes used when another workflow includes this workflow. |
68
+ | `edges` | `WorkflowEdge[]` | Required. See routing below. |
69
+ | `maxSteps` | `number` | Optional loop bound, default 100. The run fails when exceeded. |
65
70
 
66
71
  `defineWorkflow` validates the shape eagerly (node ids, edge shapes, function
67
72
  fields) and validates the graph (unknown targets, duplicate outgoing edges,
@@ -314,6 +319,43 @@ A missing case for the resolved value fails the run with a routing error. A
314
319
  node with no outgoing edge (or no matching failure route) ends the run:
315
320
  `completed` on success, `failed`/`timed_out`/`cancelled` otherwise.
316
321
 
322
+ ## Included workflows
323
+
324
+ Use `includeWorkflow()` to mount a standalone workflow under a parent name:
325
+
326
+ ```typescript
327
+ import repair from "./repair.workflow.js";
328
+
329
+ includes: {
330
+ repair: includeWorkflow(repair, {
331
+ input: ({ outputs }) => ({ issue: outputs.check }),
332
+ }),
333
+ },
334
+ ```
335
+
336
+ The child declares named exits:
337
+
338
+ ```typescript
339
+ exits: {
340
+ completed: { from: "finalize", validate: parseCompleted },
341
+ blocked: { from: "blocked", validate: parseBlocked },
342
+ },
343
+ ```
344
+
345
+ Enter through the mount and leave through `<mount>.<exit>`:
346
+
347
+ ```typescript
348
+ { from: "check", to: "repair" }
349
+ { from: "repair.completed", to: "check" }
350
+ { from: "repair.blocked", to: "finish" }
351
+ ```
352
+
353
+ Direct imports check child input and exit names in TypeScript. Use `includedResult(child, outputs.mount)` to recover the child's discriminated exit output without a cast. Dynamic discovered names, built-in references, and file paths are also supported. Every reference resolves before the run starts.
354
+
355
+ Child callbacks receive local input, outputs, results, and steps from their current invocation. Persisted node identities include the mount path. Re-entry starts with empty child-local state. Root and child step limits both apply. Internal entry and exit transitions do not consume those limits.
356
+
357
+ The run records every mounted source and a digest of the resolved graph. Resume refuses a changed child source. Source cycles are rejected before the run starts. See [Workflow composition](WORKFLOW_COMPOSITION.md) for typing, persistence, nesting, and viewer rules.
358
+
317
359
  ## Model workflow control
318
360
 
319
361
  The model sees one `workflow` tool. Its `action` field supports:
@@ -333,6 +375,12 @@ The normal extension offers all actions. The headless RPC bridge offers only
333
375
  `update` and `submit`, so a workflow child cannot recursively control other
334
376
  runs.
335
377
 
378
+ ### Built-in planning and implementation
379
+
380
+ The built-in `autodevise` workflow selects a practical in-scope solution and writes a detailed plan. The built-in `autoimplement` workflow implements a supplied plan and returns to its internal `autodevise` mount when new evidence invalidates that plan.
381
+
382
+ Autoimplement writes and runs the exact Pi Reviewer command. It records P0 through P2 by review round. P0 or P1 work requires another review. P2-only work can be addressed and verified without another reviewer run. CI tracking commands are also explicit. One CI watch lasts at most five minutes, after which the model runs more useful local tests before checking CI again.
383
+
336
384
  ### Built-in monitor
337
385
 
338
386
  The built-in `monitor` workflow turns a plain request for repeated checks into
@@ -341,12 +389,17 @@ one looping workflow run. Its input is:
341
389
  ```json
342
390
  {
343
391
  "task": "Check pull request 123",
344
- "stopWhen": "The pull request is merged or closed"
392
+ "stopWhen": "The pull request is merged or closed",
393
+ "repair": {
394
+ "authorized": true,
395
+ "scope": "the current repository"
396
+ }
345
397
  }
346
398
  ```
347
399
 
348
- The first check runs immediately. `everyMinutes` defaults to 30. Each accepted
349
- check must provide one concise report and choose `continue` or `stop`. The
400
+ The first check runs immediately. Omit `repair` for observation-only monitoring. An authorized repair can route through outer `autodevise`, `autoimplement`, and internal redesign before the monitor checks the target again. A repeated issue with unchanged target evidence stops as blocked.
401
+
402
+ `everyMinutes` defaults to 30. Each accepted check must provide one concise report and choose `continue`, `repair` when authorized, or `stop`. The
350
403
  runtime queues that report as a workflow notification with `triggerTurn:
351
404
  false`, so it does not cause an assistant reply. A check can also provide
352
405
  independent progress tracks. The regular Pi model running the check observes
@@ -0,0 +1 @@
1
+ export { autodeviseWorkflow as default } from "@osolmaz/pi-workflows/builtins";
@@ -1,92 +1 @@
1
- import { agent, compute, decision, decisionEdge, defineWorkflow } from "@osolmaz/pi-workflows";
2
-
3
- type AutoimplementInput = {
4
- task?: string;
5
- };
6
-
7
- const reviewChoices = ["clean", "issues_found"] as const;
8
-
9
- /**
10
- * Implement, verify, then loop a self-review until it comes back clean. The
11
- * decision edge routes `issues_found` back to the fix step, and the engine's
12
- * maxSteps guard bounds the loop.
13
- */
14
- export default defineWorkflow({
15
- name: "autoimplement",
16
- title: ({ input }) => {
17
- const task = (input as AutoimplementInput).task;
18
- return task ? `autoimplement: ${task.slice(0, 60)}` : undefined;
19
- },
20
- presentationPrompt:
21
- "Summarize what was implemented, what verification passed, and any remaining limitation. Be concise and direct.",
22
- maxSteps: 20,
23
- startAt: "implement",
24
- nodes: {
25
- implement: agent({
26
- timeoutMs: 60 * 60_000,
27
- statusDetail: "implementing",
28
- prompt: ({ input }) => {
29
- const task =
30
- (input as AutoimplementInput).task ?? "the plan discussed so far in this conversation";
31
- return [
32
- `Implement ${task} end-to-end.`,
33
- "Aim for the most elegant, long-term production-ready solution without gold-plating.",
34
- ].join("\n");
35
- },
36
- expectedOutput: `{ "summary": "what was implemented", "files": ["changed file", "changed file"] }`,
37
- }),
38
- verify: agent({
39
- timeoutMs: 30 * 60_000,
40
- statusDetail: "verifying",
41
- prompt: () =>
42
- [
43
- "Verify the implementation.",
44
- "Run the test suite plus any relevant builds, linters, or local smoke tests.",
45
- "Do not run destructive commands.",
46
- ].join("\n"),
47
- expectedOutput: `{ "passed": true | false, "details": "what was run and what happened" }`,
48
- }),
49
- review: decision({
50
- choices: reviewChoices,
51
- question: ({ outputs }) =>
52
- [
53
- "Critically review your implementation as a strict reviewer.",
54
- "Look for correctness bugs, missed requirements, and failing checks.",
55
- "Pick `issues_found` if anything must be fixed, otherwise `clean`.",
56
- "",
57
- `Verification: ${JSON.stringify(outputs.verify)}`,
58
- ].join("\n"),
59
- }),
60
- fix: agent({
61
- timeoutMs: 30 * 60_000,
62
- statusDetail: "fixing",
63
- prompt: ({ outputs }) =>
64
- [
65
- "Fix the issues you found in review, then stop.",
66
- "",
67
- `Review: ${JSON.stringify(outputs.review)}`,
68
- ].join("\n"),
69
- expectedOutput: `{ "fixed": "what was changed" }`,
70
- }),
71
- finalize: compute({
72
- run: ({ outputs }) => ({
73
- implementation: outputs.implement,
74
- verification: outputs.verify,
75
- review: outputs.review,
76
- }),
77
- }),
78
- },
79
- edges: [
80
- { from: "implement", to: "verify" },
81
- { from: "verify", to: "review" },
82
- decisionEdge({
83
- from: "review",
84
- choices: reviewChoices,
85
- cases: {
86
- clean: "finalize",
87
- issues_found: "fix",
88
- },
89
- }),
90
- { from: "fix", to: "verify" },
91
- ],
92
- });
1
+ export { autoimplementWorkflow 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.9.0"
3
+ version = "0.10.0"
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.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Workflow and controller runtime with a live terminal viewer for the pi coding agent",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -41,6 +41,10 @@
41
41
  "./controllers": {
42
42
  "types": "./dist/controllers/index.d.ts",
43
43
  "default": "./dist/controllers/index.js"
44
+ },
45
+ "./builtins": {
46
+ "types": "./dist/builtins/index.d.ts",
47
+ "default": "./dist/builtins/index.js"
44
48
  }
45
49
  },
46
50
  "publishConfig": {
@@ -29,11 +29,14 @@ Derive the workflow input from the full conversation:
29
29
  - `task`: State the complete objective, the exact current target and stable identifiers, authoritative status sources, durable progress and final-output surfaces, routine actions authorized by the monitor request, other recorded approvals, immutable boundaries, cost and credential rules, and required validation or downstream operations.
30
30
  - `everyMinutes`: Use the user's interval when present. Use `30` when the user gives no interval. The built-in workflow accepts intervals from 1 minute through 24 hours.
31
31
  - `stopWhen`: Infer verified completion from the full conversation. Describe completion of the complete objective, not only the end of one physical process. Also name material blockers that require human intervention.
32
+ - `repair`: Include this object only when the request or an existing approval authorizes mutation. Set `authorized: true` and record the repository, scope, base branch, merge policy, and constraints that apply. Omit it for observation-only work.
32
33
 
33
34
  When the conversation gives no clear finish criterion, set `stopWhen` to `Stop only when the user explicitly asks to stop.` Do not use that fallback when a broader implementation, repair, publication, or deployment objective is clear from context.
34
35
 
35
36
  Do not invent a finite check count. Omit `maxChecks` unless the user explicitly requests one. The workflow host can apply its own safety upper bound. Disclose that bound if it appears.
36
37
 
38
+ When repair is authorized, route a concrete code or design defect through the monitor's composed repair path. Supply the problem, observed evidence, and a stable fingerprint of the issue plus target state. The workflow runs outer `autodevise`, `autoimplement`, and internal redesign when needed, then checks the target again. Do not copy their prompts into the monitor task.
39
+
37
40
  ## Keep routine work moving
38
41
 
39
42
  While the workflow is active, do routine, bounded work required by the exact objective without asking for another confirmation. This includes:
@@ -140,7 +143,9 @@ Stop only for a material blocker, such as:
140
143
  - a cost, time, or resource ceiling that cannot safely contain the remaining work;
141
144
  - evidence that the requested result cannot be made truthful or valid under the current contract.
142
145
 
143
- Never keep paid workers retrying a deterministic shared failure. Contain affected work, report the evidence and ETA impact, and stop for a decision.
146
+ Never keep paid workers retrying a deterministic shared failure. When repair is authorized and the defect is inside scope, stop affected work, preserve the evidence, and use the composed repair path. Stop for a decision when repair is outside scope or would change a protected contract.
147
+
148
+ If the same issue and target-state fingerprint return after a completed repair, report the no-progress result and stop. Do not start the same repair again.
144
149
 
145
150
  ### Status unavailable
146
151