@osolmaz/pi-workflows 0.10.0 → 0.11.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 (135) hide show
  1. package/README.md +32 -14
  2. package/dist/builtins/autodoc.workflow.d.ts +58 -0
  3. package/dist/builtins/autodoc.workflow.js +266 -0
  4. package/dist/builtins/autodoc.workflow.js.map +1 -0
  5. package/dist/builtins/autoimplement.workflow.d.ts +212 -11
  6. package/dist/builtins/autoimplement.workflow.js +431 -22
  7. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  8. package/dist/builtins/{autodevise.workflow.d.ts → autoplan.workflow.d.ts} +9 -9
  9. package/dist/builtins/{autodevise.workflow.js → autoplan.workflow.js} +20 -20
  10. package/dist/builtins/autoplan.workflow.js.map +1 -0
  11. package/dist/builtins/catalog.js +8 -4
  12. package/dist/builtins/catalog.js.map +1 -1
  13. package/dist/builtins/index.d.ts +6 -3
  14. package/dist/builtins/index.js +5 -2
  15. package/dist/builtins/index.js.map +1 -1
  16. package/dist/builtins/monitor.workflow.d.ts +4 -0
  17. package/dist/builtins/monitor.workflow.js +134 -9
  18. package/dist/builtins/monitor.workflow.js.map +1 -1
  19. package/dist/builtins/plan-approval.workflow.d.ts +83 -0
  20. package/dist/builtins/plan-approval.workflow.js +148 -0
  21. package/dist/builtins/plan-approval.workflow.js.map +1 -0
  22. package/dist/builtins/plan-presentation.d.ts +7 -0
  23. package/dist/builtins/plan-presentation.js +44 -0
  24. package/dist/builtins/plan-presentation.js.map +1 -0
  25. package/dist/extension/decision-channels.d.ts +132 -0
  26. package/dist/extension/decision-channels.js +1082 -0
  27. package/dist/extension/decision-channels.js.map +1 -0
  28. package/dist/extension/index.d.ts +1 -0
  29. package/dist/extension/index.js +426 -11
  30. package/dist/extension/index.js.map +1 -1
  31. package/dist/extension/widget.js +26 -2
  32. package/dist/extension/widget.js.map +1 -1
  33. package/dist/extension/workflow-tool.d.ts +1 -37
  34. package/dist/extension/workflow-tool.js +1 -42
  35. package/dist/extension/workflow-tool.js.map +1 -1
  36. package/dist/herdr/setup.d.ts +13 -1
  37. package/dist/herdr/setup.js +349 -36
  38. package/dist/herdr/setup.js.map +1 -1
  39. package/dist/host/rpc-bridge.js +4 -21
  40. package/dist/host/rpc-bridge.js.map +1 -1
  41. package/dist/render/graph-render.js +33 -8
  42. package/dist/render/graph-render.js.map +1 -1
  43. package/dist/viewer/cli.d.ts +1 -0
  44. package/dist/viewer/cli.js +21 -10
  45. package/dist/viewer/cli.js.map +1 -1
  46. package/dist/viewer/render.js +36 -2
  47. package/dist/viewer/render.js.map +1 -1
  48. package/dist/workflows/composition.js +15 -1
  49. package/dist/workflows/composition.js.map +1 -1
  50. package/dist/workflows/decision-presentation.d.ts +18 -0
  51. package/dist/workflows/decision-presentation.js +417 -0
  52. package/dist/workflows/decision-presentation.js.map +1 -0
  53. package/dist/workflows/engine.d.ts +2 -1
  54. package/dist/workflows/engine.js +86 -4
  55. package/dist/workflows/engine.js.map +1 -1
  56. package/dist/workflows/human-decision.d.ts +87 -0
  57. package/dist/workflows/human-decision.js +583 -0
  58. package/dist/workflows/human-decision.js.map +1 -0
  59. package/dist/workflows/index.d.ts +3 -1
  60. package/dist/workflows/index.js +2 -0
  61. package/dist/workflows/index.js.map +1 -1
  62. package/dist/workflows/schema.js +15 -0
  63. package/dist/workflows/schema.js.map +1 -1
  64. package/dist/workflows/store.js +7 -0
  65. package/dist/workflows/store.js.map +1 -1
  66. package/dist/workflows/tool-input.d.ts +72 -0
  67. package/dist/workflows/tool-input.js +141 -0
  68. package/dist/workflows/tool-input.js.map +1 -0
  69. package/dist/workflows/types.d.ts +223 -0
  70. package/docs/HUMAN_DECISIONS.md +371 -0
  71. package/docs/HUMAN_DECISION_PRESENTATIONS.md +323 -0
  72. package/docs/MONITOR.md +17 -6
  73. package/docs/WORKFLOW_COMPOSITION.md +13 -6
  74. package/docs/plans/2026-08-19-human-decision-gates-plan.md +296 -0
  75. package/docs/plans/2026-08-19-human-decision-presentations-plan.md +172 -0
  76. package/docs/plans/2026-08-19-provider-compatible-workflow-tool-schema-plan.md +45 -0
  77. package/docs/plans/2026-08-19-workflow-composition-plan.md +25 -17
  78. package/docs/plans/2026-08-20-autoimplement-blocker-challenge-plan.md +138 -0
  79. package/docs/plans/2026-08-20-herdr-plugin-sync-plan.md +104 -0
  80. package/docs/run-bundles.md +23 -2
  81. package/docs/workflows.md +47 -5
  82. package/examples/workflows/approved-plan.workflow.ts +58 -0
  83. package/examples/workflows/autoplan.workflow.ts +1 -0
  84. package/examples/workflows/human-decision.workflow.ts +62 -0
  85. package/herdr-plugin.toml +1 -1
  86. package/package.json +2 -1
  87. package/schemas/decision-presentation-v1.schema.json +83 -0
  88. package/schemas/human-decision-accepted-v1.schema.json +44 -0
  89. package/schemas/human-decision-accepted-v2.schema.json +50 -0
  90. package/schemas/human-decision-answer-attempt-v1.schema.json +37 -0
  91. package/schemas/human-decision-cancellation-v1.schema.json +15 -0
  92. package/schemas/human-decision-continuation-v1.schema.json +16 -0
  93. package/schemas/human-decision-delivery-v1.schema.json +28 -0
  94. package/schemas/human-decision-delivery-v2.schema.json +36 -0
  95. package/schemas/human-decision-receipt-v1.schema.json +33 -0
  96. package/schemas/human-decision-receipt-v2.schema.json +39 -0
  97. package/schemas/human-decision-request-v1.schema.json +59 -0
  98. package/schemas/human-decision-request-v2.schema.json +69 -0
  99. package/schemas/human-decision-resolution-v1.schema.json +27 -0
  100. package/schemas/human-decision-resolution-v2.schema.json +27 -0
  101. package/schemas/human-decision-settlement-v1.schema.json +28 -0
  102. package/skills/autodoc/SKILL.md +43 -0
  103. package/skills/autoimplement/SKILL.md +58 -0
  104. package/skills/autoimplement/agents/openai.yaml +4 -0
  105. package/skills/autoplan/SKILL.md +25 -0
  106. package/skills/monitor/SKILL.md +3 -1
  107. package/skills/pi-workflows/SKILL.md +3 -3
  108. package/src/builtins/autodoc.workflow.ts +325 -0
  109. package/src/builtins/autoimplement.workflow.ts +493 -23
  110. package/src/builtins/{autodevise.workflow.ts → autoplan.workflow.ts} +32 -32
  111. package/src/builtins/catalog.ts +8 -4
  112. package/src/builtins/index.ts +25 -6
  113. package/src/builtins/monitor.workflow.ts +162 -8
  114. package/src/builtins/plan-approval.workflow.ts +190 -0
  115. package/src/builtins/plan-presentation.ts +57 -0
  116. package/src/extension/decision-channels.ts +1533 -0
  117. package/src/extension/index.ts +499 -9
  118. package/src/extension/widget.ts +39 -2
  119. package/src/extension/workflow-tool.ts +5 -81
  120. package/src/herdr/setup.ts +429 -39
  121. package/src/host/rpc-bridge.ts +7 -30
  122. package/src/render/graph-render.ts +40 -3
  123. package/src/viewer/cli.ts +22 -10
  124. package/src/viewer/render.ts +56 -3
  125. package/src/workflows/composition.ts +16 -1
  126. package/src/workflows/decision-presentation.ts +501 -0
  127. package/src/workflows/engine.ts +108 -4
  128. package/src/workflows/human-decision.ts +819 -0
  129. package/src/workflows/index.ts +69 -0
  130. package/src/workflows/schema.ts +17 -0
  131. package/src/workflows/store.ts +8 -0
  132. package/src/workflows/tool-input.ts +202 -0
  133. package/src/workflows/types.ts +265 -0
  134. package/dist/builtins/autodevise.workflow.js.map +0 -1
  135. package/examples/workflows/autodevise.workflow.ts +0 -1
@@ -0,0 +1,138 @@
1
+ ---
2
+ title: Confirm blockers before autoimplement stops
3
+ author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
4
+ date: 2026-08-20
5
+ ---
6
+
7
+ # Confirm blockers before autoimplement stops
8
+
9
+ Autoimplement must not stop only because one model says that work is blocked. A separate agent must challenge the claim and confirm that the blocker is real before the workflow uses its terminal blocked result.
10
+
11
+ The canonical workflow behavior is in [Workflow authoring reference](../workflows.md#built-in-planning-and-implementation).
12
+
13
+ ## Outcome
14
+
15
+ Add one independent `challengeBlocker` agent node to the built-in autoimplement workflow. Use only existing public Pi Workflows primitives. Keep the graph explicit and reuse the existing redesign include and terminal blocked result.
16
+
17
+ The challenge asks these questions in plain terms:
18
+
19
+ - Are you really blocked?
20
+ - Is this really a blocker right now?
21
+ - Can you find a safe way to move forward and finish this?
22
+ - Are you getting stuck on something trivial, procedural, reversible, or already authorized?
23
+
24
+ The challenge inspects the task, approved plan, current result, evidence, scope, authority, previous attempts, and viable alternatives. It distinguishes a true external blocker from normal rollout work, local implementation work, a design adjustment, a missing verification step, or a reversible operational task.
25
+
26
+ ## Output and validation
27
+
28
+ The challenge returns this bounded structured output:
29
+
30
+ ```json
31
+ {
32
+ "route": "continue | blocked",
33
+ "blockingNow": true,
34
+ "outsideAuthority": true,
35
+ "canProceed": false,
36
+ "reason": "concise reason",
37
+ "nextAction": "",
38
+ "alternativesChecked": ["checked alternative"],
39
+ "evidence": ["concrete evidence"]
40
+ }
41
+ ```
42
+
43
+ A terminal blocked result is valid only when all these conditions hold:
44
+
45
+ - `route` is `blocked`.
46
+ - `blockingNow` is `true`.
47
+ - `outsideAuthority` is `true`.
48
+ - `canProceed` is `false`.
49
+ - `nextAction` is empty.
50
+ - `alternativesChecked` contains checked practical alternatives.
51
+ - `evidence` contains concrete evidence.
52
+
53
+ A `continue` result must name the next practical action. Contradictory output, such as `route: blocked` with `canProceed: true`, cannot route to the terminal blocked result.
54
+
55
+ Keep the output concise and bounded.
56
+
57
+ ## Routing
58
+
59
+ Route `classifyImplementation.blocked` to `challengeBlocker`. A `continue` challenge result routes to the existing redesign include. Redesign can revise and document the plan, then return through implementation, verification, review, comment handling, CI, and delivery. A valid `blocked` result routes to the existing terminal blocked result.
60
+
61
+ Inspect each later model-produced blocked exit in verification, review, comment handling, CI, delivery, and equivalent current nodes. Route operational or model-judged blockers through the same challenge when it is safe. Use one reusable challenge node and existing edges or includes. Do not copy the prompt into several nodes and do not add an engine-level blocker feature.
62
+
63
+ Preserve direct terminal stops for these hard boundaries:
64
+
65
+ - an explicit human stop;
66
+ - cancellation;
67
+ - an exhausted workflow safety or replan limit;
68
+ - a protected authorization gap;
69
+ - an independent blocked result from redesign when another challenge could make an unsafe or unbounded loop.
70
+
71
+ Limit blocker challenges to three attempts in one run. Include all earlier challenge outputs in each later challenge prompt. If a fourth challenge would be needed, stop with the normal safety-limit reason. Do not repeat an unsupported blocker assertion.
72
+
73
+ Include the latest challenge output in the workflow's latest-issue or context helper. A later redesign must receive the rejected blocker, its evidence, and its required next action.
74
+
75
+ ## Required behavior
76
+
77
+ A supported cutover does not become blocked only because an artifact has an ownership or packaging mismatch. In the Bob artifact incident, authorized deployment and rollback make the safe rollout work part of the task. The challenge must return `continue`, name the next rollout action, and route to redesign.
78
+
79
+ A missing external authorization for a prohibited remote mutation can remain blocked when no non-mutating path completes the task.
80
+
81
+ A local test failure, stale package, packaging mismatch, rollback preparation, or deployment procedure is not, by itself, outside the granted authority.
82
+
83
+ ## Tests
84
+
85
+ Add focused tests in `test/builtin-autoimplement.test.ts` or the best current autoimplement test file. Prove all these cases:
86
+
87
+ 1. A false blocker routes to redesign and continued work.
88
+ 2. A confirmed blocker reaches the terminal blocked result.
89
+ 3. Contradictory blocked output is rejected or cannot route to the terminal blocked result.
90
+ 4. The Bob artifact-ownership mismatch returns `continue` when rollout is authorized.
91
+ 5. An explicit human stop bypasses the challenge.
92
+ 6. A protected authorization gap remains a hard stop.
93
+ 7. An independent `redesign.blocked` path does not create a loop.
94
+ 8. Earlier challenge context is present and the three-attempt bound works.
95
+ 9. All relevant late-stage model-generated blocker routes use the challenge.
96
+ 10. Normal success paths remain unchanged.
97
+
98
+ Keep compute nodes pure. Put the independent reasoning in the challenge agent node.
99
+
100
+ ## Documentation
101
+
102
+ Update `docs/workflows.md` with the blocker-confirmation rule, hard-stop exceptions, and bounded routing. Keep the public behavior concise. Do not add internal details that users do not need.
103
+
104
+ ## Verification
105
+
106
+ Run focused tests during development. Before completion, run these exact checks:
107
+
108
+ ```bash
109
+ npm run check
110
+ npm run test:e2e
111
+ npx slophammer-ts@latest dry .
112
+ npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
113
+ git diff --check
114
+ ```
115
+
116
+ Verify discovery and behavior through the installed package path or the repository's supported real-Pi end-to-end path. A fresh Pi process is required because built-in discovery is process-local.
117
+
118
+ Review the final diff for missing blocker routes, accidental unbounded loops, and false terminal blockers. Fix each valid finding.
119
+
120
+ ## Boundaries
121
+
122
+ - Preserve current run-bundle schemas unless a schema change is required. Do not add a persistence layer.
123
+ - Use existing public Pi Workflows primitives only. Do not change Pi core.
124
+ - Keep explicit human and protected authorization boundaries intact.
125
+ - Use a hard cutover. Do not retain a legacy blocker route.
126
+ - Preserve unrelated work and do not modify other repositories.
127
+ - Make only the smallest source-based adjustment needed to preserve the approved behavior.
128
+ - Do not stop for a trivial, reversible, or already authorized issue.
129
+ - Commit coherent changes with a Conventional Commit message and push after all checks pass.
130
+ - Do not publish a package, create a release, or merge anything.
131
+
132
+ ## Contract impact
133
+
134
+ - **Session state:** normal workflow messages and tool results only.
135
+ - **Other persistent data:** none beyond the existing run bundle records for normal node outputs.
136
+ - **Pi internals:** none.
137
+ - **Public Pi API:** existing documented extension APIs only.
138
+ - **Public Pi Workflows API:** existing agent, compute, edge, and included-workflow primitives only.
@@ -0,0 +1,104 @@
1
+ ---
2
+ title: Keep the Herdr plugin linked after package updates
3
+ author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
4
+ date: 2026-08-20
5
+ ---
6
+
7
+ # Keep the Herdr plugin linked after package updates
8
+
9
+ Pi Workflows ships its Herdr plugin inside the npm package. Herdr records the package's absolute path. npm can move an installed package between nested and hoisted `node_modules` directories during an update, which leaves Herdr linked to a path that no longer exists.
10
+
11
+ Pi Workflows will own one explicit command that finds its own package and repairs this link. OnurPi will call that command after it installs an exact reviewed Pi Workflows release. OnurPi will not contain Herdr paths, manifests, or link-repair rules.
12
+
13
+ ## Outcome
14
+
15
+ The canonical command is:
16
+
17
+ ```bash
18
+ pi-workflows herdr sync --json
19
+ ```
20
+
21
+ `pi-workflows herdr setup` remains an alias for compatibility.
22
+
23
+ The command validates the bundled package before it changes Herdr. It then creates a missing link, enables a disabled link, leaves a correct link unchanged, or replaces a link to another package path or version. A successful result requires a new Herdr query that shows the expected plugin ID, package version, package root, manifest path, enabled state, and no warning.
24
+
25
+ ## Scope
26
+
27
+ ### Pi Workflows
28
+
29
+ - Resolve the installed package root from the running CLI.
30
+ - Validate `package.json`, `herdr-plugin.toml`, and the bundled viewer before changing Herdr.
31
+ - Reconcile the current registration through Herdr's public CLI.
32
+ - Return a versioned JSON result with one of `linked`, `relinked`, `enabled`, `unchanged`, or `unavailable`.
33
+ - Return `unavailable` only when the Herdr executable is absent.
34
+ - Treat malformed package data, malformed Herdr output, command failures, identity conflicts, and failed verification as errors.
35
+ - Keep output bounded and use argument arrays instead of shell commands.
36
+ - Test source and packed-package layouts, including paths that contain spaces.
37
+
38
+ ### OnurPi
39
+
40
+ - Keep the Pi Workflows dependency pinned to an exact reviewed release.
41
+ - Invoke the local `pi-workflows herdr sync --json` command from an explicit TypeScript sync script after dependency installation.
42
+ - Accept the versioned result and keep Herdr-specific behavior in Pi Workflows.
43
+ - Keep package installation free of `postinstall` side effects.
44
+
45
+ ## Non-goals
46
+
47
+ - Do not create another Herdr plugin package or release.
48
+ - Do not duplicate the manifest or viewer in OnurPi.
49
+ - Do not add hard-coded `node_modules` paths.
50
+ - Do not edit Herdr state files directly.
51
+ - Do not change Herdr core or Pi core.
52
+ - Do not hot-reload running Pi processes. A running process still needs `/reload` or restart after a package update.
53
+ - Do not add a service, watcher, or implicit package-install mutation.
54
+
55
+ ## Command contract
56
+
57
+ The JSON result uses schema `pi-workflows.herdr-sync.v1` and contains:
58
+
59
+ - the result status;
60
+ - whether Herdr state changed;
61
+ - the plugin ID;
62
+ - the expected and effective versions when available;
63
+ - the effective enabled state when available;
64
+ - a plain summary; and
65
+ - an advisory that running Pi processes must reload after a package update.
66
+
67
+ A missing Herdr executable returns `unavailable` with exit code zero because Herdr is an optional integration. Every other failure returns a nonzero exit code and does not claim success.
68
+
69
+ The command preflights the new package before unlinking an old registration. Herdr currently exposes separate unlink and link commands, so replacement cannot be atomic. If replacement fails, Pi Workflows makes one restore attempt only when the previous package root still passes the same validation. It then reports the state found by a fresh Herdr query.
70
+
71
+ Concurrent sync commands converge on the same target. After a failed or ambiguous mutation, the command queries Herdr and adopts the result only when another process already reached the exact expected state. It does not repeat the same mutation blindly.
72
+
73
+ ## Compatibility
74
+
75
+ Existing `herdr setup` callers use the same implementation. Other Pi Workflows CLI commands do not change. The npm package remains the only source of the plugin manifest and viewer.
76
+
77
+ OnurPi adds only invocation timing and result handling. It does not parse the Herdr manifest or issue link commands.
78
+
79
+ ## Verification
80
+
81
+ ### Pi Workflows
82
+
83
+ - Test first link, unchanged link, disabled link, moved package path, stale path, and version update.
84
+ - Test missing Herdr, malformed manifests, malformed plugin records, command failures, post-action mismatches, and bounded restore behavior.
85
+ - Test concurrent adoption and paths with spaces.
86
+ - Run the CLI from `npm pack` contents in nested and hoisted layouts.
87
+ - Run `npm run check`, `npm run test:e2e`, Slophammer, SimpleDoc, and diff checks.
88
+
89
+ ### OnurPi
90
+
91
+ - Test every structured result and invalid command output with a fake executable.
92
+ - Verify the wrapper contains no plugin ID, manifest copy, Herdr mutation command, or package path.
93
+ - Verify root and wrapper dependency pins remain equal.
94
+ - Run `npm run check`, `npm run slophammer`, SimpleDoc, and diff checks.
95
+
96
+ ### Adoption
97
+
98
+ After a separately approved Pi Workflows release, update OnurPi to that exact version and run:
99
+
100
+ ```bash
101
+ npm run workflows:sync
102
+ ```
103
+
104
+ Then verify the Herdr plugin list, open `piw`, and start or reload Pi to confirm resource discovery. Repeating the sync must return `unchanged`.
@@ -32,6 +32,27 @@ temporary directories.
32
32
  sha256-<64 hex>.txt
33
33
  ```
34
34
 
35
+ Human decision records use a separate additive directory next to `runs/` so a waiting run bundle remains immutable:
36
+
37
+ ```text
38
+ ~/.pi/agent/workflows/decisions/
39
+ <decision-id>/
40
+ request.json
41
+ deliveries/<channel>/<attempt-id>.json
42
+ answers/<attempt-id>.json
43
+ resolution.json # atomic accepted-or-cancelled fence
44
+ accepted.json
45
+ cancelled.json # present only when a pending request is cancelled or expires
46
+ settlements/<channel>/<attempt-id>.json
47
+ continuation.json
48
+ ```
49
+
50
+ The request links to the waiting run, node, attempt, workflow source, and canonical request digest. A v2 request stores the canonical subject and a separate normalized operator presentation. Its subject, presentation, revision, choices, and input prompts are bound to the request digest. V2 accepted records and redacted continuation receipts preserve the subject and presentation digests. Final records use no-replace creation and adopt only identical retries. `resolution.json` is the first accepted-or-cancelled fence. It materializes either `accepted.json` or the mutually exclusive `cancelled.json`; a crash can rebuild that detail from the resolution. `continuation.json` binds an accepted answer to one deterministic continuation run. Delivery and settlement records cannot change the accepted answer.
51
+
52
+ Telegram multipart delivery uses additive v2 delivery records for the overall intent, each part, and completion. Part records contain only recipient indexes, part indexes, counts, and content digests. Telegram chat and message IDs remain in the private disposable channel projection and never enter run or decision bundles. An ambiguous part remains unknown and is not retried blindly.
53
+
54
+ A human-decision continuation preserves the parent's original workflow input and replaces the carried checkpoint output with the accepted typed response for routing. Its `humanDecision` state is a redacted receipt. A v2 receipt includes the subject digest, presentation digest, and revision, but not the subject itself. Verified actor, channel, event, and idempotency provenance remains in the private sibling decision records and is not copied into the run bundle. Ordinary checkpoint continuations keep using the answer as the continuation input. Existing bundles without human decision data remain valid. V1 requests and their original digests are never rewritten.
55
+
35
56
  Run ids are `<UTC timestamp>-<workflow slug>-<8 hex chars>`, so lexical order
36
57
  is chronological order.
37
58
 
@@ -210,8 +231,8 @@ The full run projection (`WorkflowRunState` in
210
231
  "workflowSources": [
211
232
  {
212
233
  "mountPath": ["redesign"],
213
- "workflowName": "autodevise",
214
- "source": { "kind": "builtin", "id": "autodevise", "revision": "1" }
234
+ "workflowName": "autoplan",
235
+ "source": { "kind": "builtin", "id": "autoplan", "revision": "1" }
215
236
  }
216
237
  ],
217
238
  "definitionDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
package/docs/workflows.md CHANGED
@@ -15,8 +15,11 @@ 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 a built-in `monitor` workflow. A project or global file
19
- named `monitor.workflow.ts` replaces it. The package registers each built-in in
18
+ Pi Workflows includes built-in `autoplan`, `autodoc`, `autoimplement`,
19
+ `plan-approval`, and `monitor` workflows. `autoplan` is the current name for the
20
+ planning workflow that was first released as `autodevise`; the old command and
21
+ export are not retained. A project or global file named `monitor.workflow.ts`
22
+ replaces the built-in monitor. The package registers each built-in in
20
23
  a process-local catalog with a stable reference such as `builtin:monitor` and
21
24
  an explicit revision. Built-ins are imported with the engine when a Pi process
22
25
  starts. They are not read from the package directory when a run starts or
@@ -271,6 +274,39 @@ checkpoint({
271
274
  });
272
275
  ```
273
276
 
277
+ A typed human decision is an authoring layer over checkpoint:
278
+
279
+ ```typescript
280
+ const choices = defineHumanChoices({
281
+ continue: choice({ label: "Continue" }),
282
+ stop: choice({ label: "Stop" }),
283
+ replan: choice({
284
+ label: "Replan",
285
+ input: textInput({ name: "instructions", prompt: "What should change?" }),
286
+ }),
287
+ });
288
+
289
+ humanDecision({
290
+ audience: "operator",
291
+ choices,
292
+ request: ({ outputs }) => ({
293
+ title: "Approve plan",
294
+ subject: outputs.plan,
295
+ presentation: {
296
+ schema: "pi-workflows.decision-presentation.v1",
297
+ summary: "Review the implementation plan.",
298
+ blocks: [{ kind: "paragraph", text: "The plan is ready for approval." }],
299
+ },
300
+ }),
301
+ });
302
+ ```
303
+
304
+ The waiting run stores a versioned request and asks every channel configured for the logical audience. The structured `subject` remains machine data. Channels receive only the normalized `presentation`, title, choices, and input prompts. The first valid verified human answer wins. A continuation preserves the original workflow input and exposes the accepted answer as the checkpoint output. `humanDecisionEdge()` provides exhaustive routing for the choices. Existing `body` requests remain a legacy compatibility form and use deterministic readable formatting.
305
+
306
+ The model-facing workflow tool cannot answer a protected human decision. Pi interactive UI and configured external channels use a host-owned answer path. Ordinary checkpoints keep the existing `/workflow answer` behavior.
307
+
308
+ See [Human decisions](HUMAN_DECISIONS.md) for channels, recovery, persistence, and plan approval.
309
+
274
310
  ### decision
275
311
 
276
312
  `decision` is sugar over `agent` for constrained choices. It builds the prompt
@@ -364,7 +400,7 @@ The model sees one `workflow` tool. Its `action` field supports:
364
400
  - `start` with a workflow name or path and structured input.
365
401
  - `status` for the active run or a supplied run ID.
366
402
  - `pause`, `resume`, and `cancel` for the active run.
367
- - `answer` with checkpoint input and an optional run ID.
403
+ - `answer` with ordinary checkpoint input and an optional run ID. Protected `humanDecision()` gates reject this model-facing action.
368
404
  - `update` for a non-completing update from the current agent attempt.
369
405
  - `submit` for the current workflow step contract.
370
406
 
@@ -377,10 +413,16 @@ runs.
377
413
 
378
414
  ### Built-in planning and implementation
379
415
 
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.
416
+ 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`.
417
+
418
+ The built-in `plan-approval` workflow offers verified human `continue`, `stop`, and exact-text `replan` exits. It is optional. A replan exit returns the unchanged text to autoplan, documents the revised plan, and asks again through a new plan digest.
381
419
 
382
420
  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
421
 
422
+ 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.
423
+
424
+ Autoimplement can run the blocker challenge at most three times in one run. Each later challenge receives the earlier challenge results. Reaching the limit stops with the normal workflow safety-limit reason. Explicit human stops, cancellation, exhausted workflow or replan limits, protected authorization gaps, and an independent blocked result from redesign remain direct stops. These hard boundaries do not enter the blocker challenge.
425
+
384
426
  ### Built-in monitor
385
427
 
386
428
  The built-in `monitor` workflow turns a plain request for repeated checks into
@@ -397,7 +439,7 @@ one looping workflow run. Its input is:
397
439
  }
398
440
  ```
399
441
 
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.
442
+ The first check runs immediately. Omit `repair` for observation-only monitoring. An authorized repair routes through outer `autoplan`, `autodoc`, optional `plan-approval`, `autoimplement`, and internal redesign before the monitor checks the target again. A repeated issue with unchanged target evidence stops as blocked. Add `repair.approval` with a named audience and bounded replan limit only when the operator wants a human decision before implementation.
401
443
 
402
444
  `everyMinutes` defaults to 30. Each accepted check must provide one concise report and choose `continue`, `repair` when authorized, or `stop`. The
403
445
  runtime queues that report as a workflow notification with `triggerTurn:
@@ -0,0 +1,58 @@
1
+ import { compute, defineWorkflow, includeWorkflow, includedResult } from "@osolmaz/pi-workflows";
2
+ import autodoc from "../../src/builtins/autodoc.workflow.js";
3
+ import autoplan from "../../src/builtins/autoplan.workflow.js";
4
+ import planApproval from "../../src/builtins/plan-approval.workflow.js";
5
+
6
+ export default defineWorkflow({
7
+ name: "approved-plan-example",
8
+ startAt: "design",
9
+ maxSteps: 80,
10
+ includes: {
11
+ design: includeWorkflow(autoplan, {
12
+ input: ({ input, outputs }) => {
13
+ const prior = outputs.design as { exit?: string; output?: { plan?: unknown } } | undefined;
14
+ const answer = outputs.approval as
15
+ | { exit?: string; output?: { instructions?: string } }
16
+ | undefined;
17
+ return {
18
+ problem: (input as { task: string }).task,
19
+ ...(prior?.exit === "ready" ? { previousPlan: prior.output?.plan } : {}),
20
+ ...(answer?.exit === "replan" ? { newEvidence: answer.output?.instructions } : {}),
21
+ };
22
+ },
23
+ }),
24
+ documentation: includeWorkflow(autodoc, {
25
+ input: ({ input, outputs }) => {
26
+ const result = includedResult(autoplan, outputs.design);
27
+ if (result.exit !== "ready") throw new Error("design is not ready");
28
+ return { task: (input as { task: string }).task, plan: result.output.plan };
29
+ },
30
+ }),
31
+ approval: includeWorkflow(planApproval, {
32
+ input: ({ input, outputs }) => {
33
+ const result = includedResult(autodoc, outputs.documentation);
34
+ if (result.exit !== "ready") throw new Error("documentation is not ready");
35
+ return {
36
+ task: (input as { task: string }).task,
37
+ plan: result.output.plan,
38
+ planDigest: result.output.planDigest,
39
+ audience: "operator",
40
+ };
41
+ },
42
+ }),
43
+ },
44
+ nodes: {
45
+ done: compute({ run: ({ outputs }) => ({ status: "approved", approval: outputs.approval }) }),
46
+ stopped: compute({ run: ({ outputs }) => ({ status: "stopped", approval: outputs.approval }) }),
47
+ blocked: compute({ run: ({ outputs }) => ({ status: "blocked", outputs }) }),
48
+ },
49
+ edges: [
50
+ { from: "design.ready", to: "documentation" },
51
+ { from: "design.blocked", to: "blocked" },
52
+ { from: "documentation.ready", to: "approval" },
53
+ { from: "documentation.blocked", to: "blocked" },
54
+ { from: "approval.continue", to: "done" },
55
+ { from: "approval.stop", to: "stopped" },
56
+ { from: "approval.replan", to: "design" },
57
+ ],
58
+ });
@@ -0,0 +1 @@
1
+ export { autoplanWorkflow as default } from "@osolmaz/pi-workflows/builtins";
@@ -0,0 +1,62 @@
1
+ import {
2
+ choice,
3
+ compute,
4
+ defineHumanChoices,
5
+ defineWorkflow,
6
+ humanDecision,
7
+ humanDecisionEdge,
8
+ textInput,
9
+ } from "@osolmaz/pi-workflows";
10
+
11
+ const choices = defineHumanChoices({
12
+ continue: choice({ label: "Yes, continue" }),
13
+ stop: choice({ label: "No, stop" }),
14
+ replan: choice({
15
+ label: "Replan",
16
+ input: textInput({ name: "instructions", prompt: "What should change?" }),
17
+ }),
18
+ });
19
+
20
+ export default defineWorkflow({
21
+ name: "human-decision-example",
22
+ startAt: "proposal",
23
+ nodes: {
24
+ proposal: compute({
25
+ run: ({ input }) => ({
26
+ summary: "Apply the proposed workflow change.",
27
+ changes: ["Keep the durable subject.", "Show readable decision text."],
28
+ source: input,
29
+ }),
30
+ }),
31
+ approve: humanDecision({
32
+ audience: "operator",
33
+ choices,
34
+ request: ({ outputs }) => {
35
+ const proposal = outputs.proposal as { summary: string; changes: string[] };
36
+ return {
37
+ title: "Approve the proposal",
38
+ subject: proposal,
39
+ presentation: {
40
+ schema: "pi-workflows.decision-presentation.v1",
41
+ summary: proposal.summary,
42
+ blocks: [
43
+ { kind: "section", title: "Changes" },
44
+ { kind: "bullets", items: proposal.changes },
45
+ ],
46
+ },
47
+ };
48
+ },
49
+ }),
50
+ continued: compute({ run: ({ outputs }) => ({ status: "continue", answer: outputs.approve }) }),
51
+ stopped: compute({ run: ({ outputs }) => ({ status: "stop", answer: outputs.approve }) }),
52
+ replan: compute({ run: ({ outputs }) => ({ status: "replan", answer: outputs.approve }) }),
53
+ },
54
+ edges: [
55
+ { from: "proposal", to: "approve" },
56
+ humanDecisionEdge({
57
+ from: "approve",
58
+ choices,
59
+ cases: { continue: "continued", stop: "stopped", replan: "replan" },
60
+ }),
61
+ ],
62
+ });
package/herdr-plugin.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  id = "osolmaz.pi-workflows"
2
2
  name = "Pi Workflows"
3
- version = "0.10.0"
3
+ version = "0.11.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.10.0",
3
+ "version": "0.11.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"
@@ -23,6 +23,7 @@
23
23
  "skills",
24
24
  "examples",
25
25
  "docs",
26
+ "schemas",
26
27
  "plugins/herdr",
27
28
  "herdr-plugin.toml",
28
29
  "README.md",
@@ -0,0 +1,83 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/osolmaz/pi-workflows/schemas/decision-presentation-v1.schema.json",
4
+ "title": "Pi Workflows decision presentation v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schema", "summary", "blocks"],
8
+ "properties": {
9
+ "schema": { "const": "pi-workflows.decision-presentation.v1" },
10
+ "summary": { "type": "string", "minLength": 1, "maxLength": 16000 },
11
+ "blocks": {
12
+ "type": "array",
13
+ "maxItems": 256,
14
+ "items": {
15
+ "oneOf": [
16
+ {
17
+ "type": "object",
18
+ "additionalProperties": false,
19
+ "required": ["kind", "text"],
20
+ "properties": {
21
+ "kind": { "const": "paragraph" },
22
+ "text": { "type": "string", "minLength": 1, "maxLength": 16000 }
23
+ }
24
+ },
25
+ {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["kind", "title"],
29
+ "properties": {
30
+ "kind": { "const": "section" },
31
+ "title": { "type": "string", "minLength": 1, "maxLength": 16000 }
32
+ }
33
+ },
34
+ {
35
+ "type": "object",
36
+ "additionalProperties": false,
37
+ "required": ["kind", "items"],
38
+ "properties": {
39
+ "kind": { "const": "bullets" },
40
+ "items": {
41
+ "type": "array",
42
+ "minItems": 1,
43
+ "maxItems": 256,
44
+ "items": { "type": "string", "minLength": 1, "maxLength": 16000 }
45
+ }
46
+ }
47
+ },
48
+ {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": ["kind", "items"],
52
+ "properties": {
53
+ "kind": { "const": "fields" },
54
+ "items": {
55
+ "type": "array",
56
+ "minItems": 1,
57
+ "maxItems": 256,
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["label", "value"],
62
+ "properties": {
63
+ "label": { "type": "string", "minLength": 1, "maxLength": 16000 },
64
+ "value": { "type": "string", "minLength": 1, "maxLength": 16000 }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ },
70
+ {
71
+ "type": "object",
72
+ "additionalProperties": false,
73
+ "required": ["kind", "text"],
74
+ "properties": {
75
+ "kind": { "const": "preformatted" },
76
+ "text": { "type": "string", "minLength": 1, "maxLength": 16000 }
77
+ }
78
+ }
79
+ ]
80
+ }
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/osolmaz/pi-workflows/schemas/human-decision-accepted-v1.schema.json",
4
+ "title": "Pi Workflows accepted human decision v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema",
9
+ "decisionId",
10
+ "requestDigest",
11
+ "response",
12
+ "source",
13
+ "idempotencyKey",
14
+ "acceptedAt",
15
+ "answerDigest"
16
+ ],
17
+ "properties": {
18
+ "schema": { "const": "pi-workflows.human-decision-accepted.v1" },
19
+ "decisionId": { "type": "string" },
20
+ "requestDigest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
21
+ "response": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "required": ["choice"],
25
+ "properties": {
26
+ "choice": { "type": "string" },
27
+ "input": { "type": "object", "additionalProperties": { "type": "string" } }
28
+ }
29
+ },
30
+ "source": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["channel", "actorId", "eventId"],
34
+ "properties": {
35
+ "channel": { "type": "string" },
36
+ "actorId": { "type": "string" },
37
+ "eventId": { "type": "string" }
38
+ }
39
+ },
40
+ "idempotencyKey": { "type": "string" },
41
+ "acceptedAt": { "type": "string", "format": "date-time" },
42
+ "answerDigest": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" }
43
+ }
44
+ }