pi-subagents 0.73.1 → 0.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +1 -1
  3. package/docs/agents.md +16 -12
  4. package/docs/configuration.md +66 -9
  5. package/docs/extension-api.md +5 -4
  6. package/docs/missions.md +13 -13
  7. package/docs/models.md +2 -2
  8. package/docs/observability.md +2 -2
  9. package/docs/tool-reference.md +63 -86
  10. package/docs/workflows.md +165 -171
  11. package/package.json +2 -2
  12. package/prompts/review-loop.md +1 -1
  13. package/skills/council-mode/SKILL.md +1 -1
  14. package/skills/pi-subagents/SKILL.md +12 -5
  15. package/skills/pi-subagents/references/constraints-and-recipes.md +3 -3
  16. package/skills/pi-subagents/references/execution-controls.md +68 -67
  17. package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  18. package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
  19. package/skills/pi-subagents/references/prompting-and-roles.md +45 -48
  20. package/src/agents/agent-management.js +2 -2
  21. package/src/agents/agent-management.js.map +1 -1
  22. package/src/agents/agents.d.ts +1 -0
  23. package/src/agents/agents.d.ts.map +1 -1
  24. package/src/agents/agents.js +8 -0
  25. package/src/agents/agents.js.map +1 -1
  26. package/src/api/preflight.d.ts +5 -1
  27. package/src/api/preflight.d.ts.map +1 -1
  28. package/src/api/preflight.js +2 -1
  29. package/src/api/preflight.js.map +1 -1
  30. package/src/extension/config.d.ts.map +1 -1
  31. package/src/extension/config.js +12 -4
  32. package/src/extension/config.js.map +1 -1
  33. package/src/extension/control-notices.d.ts +2 -0
  34. package/src/extension/control-notices.d.ts.map +1 -1
  35. package/src/extension/control-notices.js +2 -0
  36. package/src/extension/control-notices.js.map +1 -1
  37. package/src/extension/doctor.d.ts.map +1 -1
  38. package/src/extension/doctor.js +1 -0
  39. package/src/extension/doctor.js.map +1 -1
  40. package/src/extension/fanout-child.d.ts.map +1 -1
  41. package/src/extension/fanout-child.js +13 -3
  42. package/src/extension/fanout-child.js.map +1 -1
  43. package/src/extension/herdr-pi-bridge.d.ts.map +1 -1
  44. package/src/extension/herdr-pi-bridge.js +2 -0
  45. package/src/extension/herdr-pi-bridge.js.map +1 -1
  46. package/src/extension/index.d.ts +1 -1
  47. package/src/extension/index.d.ts.map +1 -1
  48. package/src/extension/index.js +62 -161
  49. package/src/extension/index.js.map +1 -1
  50. package/src/extension/public-execution.d.ts +10 -1
  51. package/src/extension/public-execution.d.ts.map +1 -1
  52. package/src/extension/public-execution.js +69 -35
  53. package/src/extension/public-execution.js.map +1 -1
  54. package/src/extension/reply-workflow-script.d.ts +12 -0
  55. package/src/extension/reply-workflow-script.d.ts.map +1 -0
  56. package/src/extension/reply-workflow-script.js +61 -0
  57. package/src/extension/reply-workflow-script.js.map +1 -0
  58. package/src/extension/rpc.d.ts +2 -0
  59. package/src/extension/rpc.d.ts.map +1 -1
  60. package/src/extension/rpc.js +33 -10
  61. package/src/extension/rpc.js.map +1 -1
  62. package/src/extension/schemas.d.ts +3 -117
  63. package/src/extension/schemas.d.ts.map +1 -1
  64. package/src/extension/schemas.js +38 -125
  65. package/src/extension/schemas.js.map +1 -1
  66. package/src/extension/tool-activation.d.ts +2 -4
  67. package/src/extension/tool-activation.d.ts.map +1 -1
  68. package/src/extension/tool-activation.js +54 -104
  69. package/src/extension/tool-activation.js.map +1 -1
  70. package/src/extension/tool-description.d.ts +8 -5
  71. package/src/extension/tool-description.d.ts.map +1 -1
  72. package/src/extension/tool-description.js +51 -27
  73. package/src/extension/tool-description.js.map +1 -1
  74. package/src/extension/upgrade-notice.d.ts +7 -0
  75. package/src/extension/upgrade-notice.d.ts.map +1 -0
  76. package/src/extension/upgrade-notice.js +37 -0
  77. package/src/extension/upgrade-notice.js.map +1 -0
  78. package/src/integrations/herdr-status.d.ts +3 -0
  79. package/src/integrations/herdr-status.d.ts.map +1 -1
  80. package/src/integrations/herdr-status.js +17 -3
  81. package/src/integrations/herdr-status.js.map +1 -1
  82. package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  83. package/src/intercom/native-supervisor-channel.js +4 -1
  84. package/src/intercom/native-supervisor-channel.js.map +1 -1
  85. package/src/runs/background/async-execution.d.ts +3 -0
  86. package/src/runs/background/async-execution.d.ts.map +1 -1
  87. package/src/runs/background/async-execution.js +6 -2
  88. package/src/runs/background/async-execution.js.map +1 -1
  89. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  90. package/src/runs/background/async-job-tracker.js +65 -22
  91. package/src/runs/background/async-job-tracker.js.map +1 -1
  92. package/src/runs/background/async-retention.d.ts +1 -1
  93. package/src/runs/background/async-retention.d.ts.map +1 -1
  94. package/src/runs/background/async-retention.js +47 -15
  95. package/src/runs/background/async-retention.js.map +1 -1
  96. package/src/runs/background/await-async-run.d.ts +23 -0
  97. package/src/runs/background/await-async-run.d.ts.map +1 -0
  98. package/src/runs/background/await-async-run.js +80 -0
  99. package/src/runs/background/await-async-run.js.map +1 -0
  100. package/src/runs/background/chain-root-attachment.d.ts +1 -0
  101. package/src/runs/background/chain-root-attachment.d.ts.map +1 -1
  102. package/src/runs/background/chain-root-attachment.js +3 -3
  103. package/src/runs/background/chain-root-attachment.js.map +1 -1
  104. package/src/runs/background/notify.d.ts +3 -0
  105. package/src/runs/background/notify.d.ts.map +1 -1
  106. package/src/runs/background/notify.js +3 -0
  107. package/src/runs/background/notify.js.map +1 -1
  108. package/src/runs/background/run-child-session.d.ts.map +1 -1
  109. package/src/runs/background/run-child-session.js +4 -1
  110. package/src/runs/background/run-child-session.js.map +1 -1
  111. package/src/runs/background/run-status.d.ts.map +1 -1
  112. package/src/runs/background/run-status.js +6 -0
  113. package/src/runs/background/run-status.js.map +1 -1
  114. package/src/runs/background/runner-child-launch.d.ts +1 -0
  115. package/src/runs/background/runner-child-launch.d.ts.map +1 -1
  116. package/src/runs/background/runner-child-launch.js +2 -0
  117. package/src/runs/background/runner-child-launch.js.map +1 -1
  118. package/src/runs/background/scheduled-runs.js +5 -5
  119. package/src/runs/background/scheduled-runs.js.map +1 -1
  120. package/src/runs/background/subagent-runner.d.ts +3 -0
  121. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  122. package/src/runs/background/subagent-runner.js +5 -0
  123. package/src/runs/background/subagent-runner.js.map +1 -1
  124. package/src/runs/foreground/async-stop-action.d.ts.map +1 -1
  125. package/src/runs/foreground/async-stop-action.js +15 -1
  126. package/src/runs/foreground/async-stop-action.js.map +1 -1
  127. package/src/runs/foreground/execution.d.ts.map +1 -1
  128. package/src/runs/foreground/execution.js +8 -1
  129. package/src/runs/foreground/execution.js.map +1 -1
  130. package/src/runs/foreground/subagent-executor.d.ts +6 -5
  131. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  132. package/src/runs/foreground/subagent-executor.js +293 -182
  133. package/src/runs/foreground/subagent-executor.js.map +1 -1
  134. package/src/runs/shared/child-launch.d.ts +5 -1
  135. package/src/runs/shared/child-launch.d.ts.map +1 -1
  136. package/src/runs/shared/child-launch.js +15 -1
  137. package/src/runs/shared/child-launch.js.map +1 -1
  138. package/src/runs/shared/child-session.d.ts +9 -0
  139. package/src/runs/shared/child-session.d.ts.map +1 -1
  140. package/src/runs/shared/child-session.js +90 -4
  141. package/src/runs/shared/child-session.js.map +1 -1
  142. package/src/runs/shared/child-tool-plan.d.ts +4 -0
  143. package/src/runs/shared/child-tool-plan.d.ts.map +1 -1
  144. package/src/runs/shared/child-tool-plan.js +11 -4
  145. package/src/runs/shared/child-tool-plan.js.map +1 -1
  146. package/src/runs/shared/dynamic-fanout.js +1 -1
  147. package/src/runs/shared/dynamic-fanout.js.map +1 -1
  148. package/src/runs/shared/mcp-config-sources.d.ts +1 -0
  149. package/src/runs/shared/mcp-config-sources.d.ts.map +1 -1
  150. package/src/runs/shared/mcp-config-sources.js +1 -1
  151. package/src/runs/shared/mcp-config-sources.js.map +1 -1
  152. package/src/runs/shared/mcp-direct-tool-allowlist.d.ts +28 -0
  153. package/src/runs/shared/mcp-direct-tool-allowlist.d.ts.map +1 -1
  154. package/src/runs/shared/mcp-direct-tool-allowlist.js +78 -2
  155. package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
  156. package/src/runs/shared/model-resolution.d.ts +10 -0
  157. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  158. package/src/runs/shared/model-resolution.js +30 -9
  159. package/src/runs/shared/model-resolution.js.map +1 -1
  160. package/src/runs/shared/model-scope.d.ts +2 -1
  161. package/src/runs/shared/model-scope.d.ts.map +1 -1
  162. package/src/runs/shared/model-scope.js +26 -10
  163. package/src/runs/shared/model-scope.js.map +1 -1
  164. package/src/runs/shared/parallel-utils.d.ts +2 -0
  165. package/src/runs/shared/parallel-utils.d.ts.map +1 -1
  166. package/src/runs/shared/parallel-utils.js.map +1 -1
  167. package/src/runs/shared/pi-spawn.d.ts +1 -10
  168. package/src/runs/shared/pi-spawn.d.ts.map +1 -1
  169. package/src/runs/shared/pi-spawn.js +7 -86
  170. package/src/runs/shared/pi-spawn.js.map +1 -1
  171. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  172. package/src/runs/shared/subagent-prompt-runtime.js +2 -0
  173. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  174. package/src/runs/shared/worktree.d.ts +1 -1
  175. package/src/runs/shared/worktree.d.ts.map +1 -1
  176. package/src/runs/shared/worktree.js +1 -1
  177. package/src/runs/shared/worktree.js.map +1 -1
  178. package/src/shared/disabled-features.d.ts +92 -0
  179. package/src/shared/disabled-features.d.ts.map +1 -0
  180. package/src/shared/disabled-features.js +113 -0
  181. package/src/shared/disabled-features.js.map +1 -0
  182. package/src/shared/extension-context.d.ts +9 -0
  183. package/src/shared/extension-context.d.ts.map +1 -1
  184. package/src/shared/extension-context.js +7 -0
  185. package/src/shared/extension-context.js.map +1 -1
  186. package/src/shared/settings.d.ts +1 -1
  187. package/src/shared/types.d.ts +20 -0
  188. package/src/shared/types.d.ts.map +1 -1
  189. package/src/shared/types.js.map +1 -1
  190. package/src/slash/prompt-template-bridge.js +2 -2
  191. package/src/slash/prompt-template-bridge.js.map +1 -1
  192. package/src/slash/slash-commands.d.ts +2 -0
  193. package/src/slash/slash-commands.d.ts.map +1 -1
  194. package/src/slash/slash-commands.js +2 -2
  195. package/src/slash/slash-commands.js.map +1 -1
  196. package/src/tui/render.d.ts.map +1 -1
  197. package/src/tui/render.js +55 -17
  198. package/src/tui/render.js.map +1 -1
  199. package/src/watchdog/diff-tool.d.ts +3 -1
  200. package/src/watchdog/diff-tool.d.ts.map +1 -1
  201. package/src/watchdog/diff-tool.js +20 -11
  202. package/src/watchdog/diff-tool.js.map +1 -1
  203. package/src/watchdog/register-child.js +2 -2
  204. package/src/watchdog/register-child.js.map +1 -1
  205. package/src/watchdog/register-main.js +2 -2
  206. package/src/watchdog/register-main.js.map +1 -1
  207. package/src/watchdog/review.d.ts +1 -1
  208. package/src/watchdog/review.d.ts.map +1 -1
  209. package/src/watchdog/review.js +1 -1
  210. package/src/watchdog/review.js.map +1 -1
  211. package/src/watchdog/turn-delta.js +1 -1
  212. package/src/watchdog/turn-delta.js.map +1 -1
  213. package/src/workflows/chat-progress.js +2 -2
  214. package/src/workflows/chat-progress.js.map +1 -1
  215. package/src/workflows/scripted-workflow.d.ts +8 -0
  216. package/src/workflows/scripted-workflow.d.ts.map +1 -1
  217. package/src/workflows/scripted-workflow.js +10 -2
  218. package/src/workflows/scripted-workflow.js.map +1 -1
  219. package/src/workflows/structured-workflow-scripts.d.ts +10 -0
  220. package/src/workflows/structured-workflow-scripts.d.ts.map +1 -0
  221. package/src/workflows/structured-workflow-scripts.js +166 -0
  222. package/src/workflows/structured-workflow-scripts.js.map +1 -0
  223. package/src/workflows/workflow-receipt.d.ts.map +1 -1
  224. package/src/workflows/workflow-receipt.js +8 -2
  225. package/src/workflows/workflow-receipt.js.map +1 -1
  226. package/src/workflows/workflow-resources.d.ts +9 -0
  227. package/src/workflows/workflow-resources.d.ts.map +1 -1
  228. package/src/workflows/workflow-resources.js +39 -12
  229. package/src/workflows/workflow-resources.js.map +1 -1
  230. package/src/workflows/workflow-reuse.d.ts +51 -0
  231. package/src/workflows/workflow-reuse.d.ts.map +1 -0
  232. package/src/workflows/workflow-reuse.js +103 -0
  233. package/src/workflows/workflow-reuse.js.map +1 -0
  234. package/src/workflows/workflow-revival.d.ts +32 -0
  235. package/src/workflows/workflow-revival.d.ts.map +1 -0
  236. package/src/workflows/workflow-revival.js +111 -0
  237. package/src/workflows/workflow-revival.js.map +1 -0
@@ -8,13 +8,15 @@ Call `{ action: "guide", topic: "tool-reference" }` for this reference or `topic
8
8
 
9
9
  ## Execution examples
10
10
 
11
- Chaining is code-driven through `workflowScript`. Use `await runs.run(...)` for sequential steps and `await runs.all([{ key, agent, task }, ...])` for ordinary parallel fanout. `runs.all` resolves to an ordered array, not a key map, so use indexes, destructuring, or `.map(...)`, not `results.<key>`. Do not read `.output` from an unawaited `runs.run` launch. Stored `runs.run` promises are only for the advanced rolling fanout pattern under [Workflow steering](#workflow-steering), where every promise is later observed with direct `await`, `Promise.race`, or `Promise.all`. Legacy top-level `chain`, `tasks`, and `parallel` inputs are not supported. Helper functions must be plain functions or explicit Promise chains. Nested `async function` helpers, async arrows, and async methods are rejected so child-launch tracking stays portable across Node and Bun. For permission-sensitive host calls, use an extension-owned named resource such as `{ workflow: "run-ci", args: { command: "npm test" } }`; raw public `workflowScript`/`workflowScriptPath` inputs have unknown resource provenance and cannot call `runs.host`. A resolved resource may internally use `runs.host(key, { kind: "command", command, timeoutMs, output?, role?, provider? })` within its authority ceiling; there is no per-step `cwd`, and commands and relative output paths use the workflow `cwd`. Set `cwd` on the outer `subagent({...})` request instead, or put a trusted directory change in the command (for example, `cd /path/to/worktree && npm test`).
11
+ Chaining is code-driven through a workflow script. Write the script as one ```` ```js workflow ```` fenced block in the reply, then call `subagent({ workflow: true, ... })` in the same reply. A `workflow` string containing `/` is a script file, and any other string is a named resource. `workflowScript` and `workflowScriptPath` were removed; use these forms instead.
12
12
 
13
- Use `{ action: "validate", workflowScript }` to check statically decidable syntax and structure without launching children. It returns `{ ok, errors }` and fails the tool call when `ok` is false. Literal child `baseRef` values are checked against the runtime ref policy. Dynamic keys and values remain subject to runtime checks; static validation does not guess them.
13
+ Use `await runs.run(...)` for sequential steps and `await runs.all([{ key, agent, task }, ...])` for ordinary parallel fanout. `runs.all` resolves to an ordered array, not a key map, so use indexes, destructuring, or `.map(...)`, not `results.<key>`. Do not read `.output` from an unawaited `runs.run` launch. Stored `runs.run` promises are only for the advanced rolling fanout pattern under [Workflow steering](#workflow-steering), where every promise is later observed with direct `await`, `Promise.race`, or `Promise.all`. Legacy top-level `chain`, `tasks`, and `parallel` inputs are not supported, except that `disabledFeatures: ["workflow-scripts"]` replaces workflow scripts with top-level `chain` and `tasks` (see [configuration](configuration.md#chain-and-tasks-without-workflow-scripts)). Helper functions must be plain functions or explicit Promise chains. Nested `async function` helpers, async arrows, and async methods are rejected so child-launch tracking stays portable across Node and Bun. For permission-sensitive host calls, use an extension-owned named resource such as `{ workflow: "run-ci", args: { command: "npm test" } }`; raw scripts (`workflow: true` or a script path) have unknown resource provenance and cannot call `runs.host`. A resolved resource may internally use `runs.host(key, { kind: "command", command, timeoutMs, output?, role?, provider? })` within its authority ceiling; there is no per-step `cwd`, and commands and relative output paths use the workflow `cwd`. Set `cwd` on the outer `subagent({...})` request instead, or put a trusted directory change in the command (for example, `cd /path/to/worktree && npm test`).
14
14
 
15
- Use `workflowScriptPath` instead of `workflowScript` to load the same JavaScript statement body from a file. The two fields are mutually exclusive. Relative paths resolve against the request `cwd`, and absolute paths pass through. The host reads the file before validation, scheduling, or sandbox execution. The workflow sandbox still has no filesystem access. Missing, unreadable, and empty files fail as file input errors.
15
+ Use `{ action: "validate", workflow: true }` (or a script path) to check statically decidable syntax and structure without launching children. It returns `{ ok, errors }` and fails the tool call when `ok` is false. Literal child `baseRef` values are checked against the runtime ref policy. Dynamic keys and values remain subject to runtime checks; static validation does not guess them.
16
16
 
17
- Raw inline and file-backed scripts accept bounded plain-JSON `args`, including during `validate` and `schedule.create`. Omitted raw args become `{}`; supplied args are deeply frozen in the sandbox. Normalized args persist in run and schedule evidence for diagnosis and exact replay, so never include secrets. Args are data only and do not grant `runs.host` authority.
17
+ Use `workflow: "./path/to/script.js"` to load the same JavaScript statement body from a file. Relative paths resolve against the request `cwd`, and absolute paths pass through. The host reads the file before validation, scheduling, or sandbox execution. The workflow sandbox still has no filesystem access. Missing, unreadable, and empty files fail as file input errors.
18
+
19
+ Raw reply-block and file-backed scripts accept bounded plain-JSON `args`, including during `validate` and `schedule.create`. Omitted raw args become `{}`; supplied args are deeply frozen in the sandbox. Normalized args persist in run and schedule evidence for diagnosis and exact replay, so never include secrets. Args are data only and do not grant `runs.host` authority.
18
20
 
19
21
  For permission-extension interoperability, use one of the package-owned named resources with bounded `args` instead of caller-supplied workflow text:
20
22
 
@@ -23,66 +25,41 @@ For permission-extension interoperability, use one of the package-owned named re
23
25
  { workflow: "run-ci", args: { command: "npm test" } }
24
26
  ```
25
27
 
26
- The host resolves the script and authority internally and records bounded provenance in workflow details and receipts. Named resources cannot be combined with `agent`, `task`, `workflowScript`, or `workflowScriptPath`; user/project resource registries are not part of this first slice.
28
+ The host resolves the script and authority internally and records bounded provenance in workflow details and receipts. Named resources cannot be combined with `agent` or `task`; user/project resource registries are not part of this first slice.
27
29
 
28
30
  ```js
29
- { workflowScriptPath: "workflows/review.js", args: { target: "src/workflows" }, cwd: "/path/to/project" }
30
- { action: "validate", workflowScriptPath: "workflows/review.js", args: { target: "src/workflows" } }
31
- { action: "schedule.create", every: "6h", workflowScriptPath: "workflows/review.js", args: { target: "src/workflows" } }
31
+ { workflow: "./workflows/review.js", args: { target: "src/workflows" }, cwd: "/path/to/project" }
32
+ { action: "validate", workflow: "./workflows/review.js", args: { target: "src/workflows" } }
33
+ { action: "schedule.create", every: "6h", workflow: "./workflows/review.js", args: { target: "src/workflows" } }
32
34
  ```
33
35
 
34
- ```js
36
+ Each script below is the ```` ```js workflow ```` block of a reply that then calls `subagent({ workflow: true })`:
37
+
38
+ ```js workflow
35
39
  // One child; return the child promise explicitly
36
- { workflowScript: `return runs.run("main", { agent: "scout", task: "Analyze the auth flow" })` }
40
+ return runs.run("main", { agent: "scout", task: "Analyze the auth flow" });
41
+ ```
37
42
 
43
+ ```js workflow
38
44
  // Sequential workflow
39
- { workflowScript: `
40
- const scan = await runs.run("scan", { agent: "scout", task: "Analyze auth" });
41
- return (await runs.run("implement", { agent: "worker", task: "Implement from: " + scan.output })).output;
42
- ` }
45
+ const scan = await runs.run("scan", { agent: "scout", task: "Analyze auth" });
46
+ return (await runs.run("implement", { agent: "worker", task: "Implement from: " + scan.output })).output;
47
+ ```
43
48
 
49
+ ```js workflow
44
50
  // Parallel workflow
45
- { workflowScript: `
46
- const results = await runs.all([
47
- { key: "backend", agent: "reviewer", task: "Review backend" },
48
- { key: "frontend", agent: "reviewer", task: "Review frontend" }
49
- ]);
50
- return results.map(result => result.output);
51
- ` }
51
+ const results = await runs.all([
52
+ { key: "backend", agent: "reviewer", task: "Review backend" },
53
+ { key: "frontend", agent: "reviewer", task: "Review frontend" }
54
+ ]);
55
+ return results.map(result => result.output);
52
56
  ```
53
57
 
54
58
  ### Parallel sequential lanes
55
59
 
56
- Use `runs.lanes(lanes)` inside a `workflowScript` when several independent lanes each have ordered stages. This helper composes the existing workflow child runner; it does not add a top-level `lanes` parameter or a second persistence/cleanup system.
60
+ Use `runs.lanes(lanes)` inside a workflow script when several independent lanes each have ordered stages. This helper composes the existing workflow child runner; it does not add a top-level `lanes` parameter or a second persistence/cleanup system.
57
61
 
58
- ```js
59
- { workflowScript: `
60
- const board = await runs.lanes([
61
- { key: "api", stages: [
62
- { key: "writer", agent: "worker", task: "Implement the API change" },
63
- { key: "challenge", resume: "previous", task: "Challenge the implementation" },
64
- { key: "review", agent: "reviewer", task: "Review the API lane" }
65
- ] },
66
- { key: "ui", stages: [
67
- { key: "writer", agent: "worker", task: "Implement the UI change" },
68
- { key: "review", agent: "reviewer", task: "Review the UI lane" }
69
- ] }
70
- ]);
71
- return board.map((lane) => ({
72
- key: lane.key,
73
- state: lane.state,
74
- failedStage: lane.failedStage,
75
- stages: lane.stages.map((stage) => ({
76
- key: stage.key,
77
- state: stage.state,
78
- ok: stage.ok,
79
- runId: stage.runId,
80
- outputReference: stage.outputReference,
81
- verdict: stage.verdict
82
- }))
83
- }));
84
- ` }
85
- ```
62
+ See the [staged-lane example](workflows.md#parallel-sequential-lanes) (guide topic `workflows`).
86
63
 
87
64
  The first stage of each lane is launched by one existing `runs.all(...)` batch. Later stages run in lane order. Set `resume: "previous"` on a later stage to continue the preceding retained child; the helper requires that child’s returned `runId` and delegates to the existing resume checks. Stage keys are local to the lane, and generated child keys are `<lane>.<stage>`.
88
65
 
@@ -114,19 +91,19 @@ The complete plain-JSON inventory is validated before the first launch (maximum
114
91
  | `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
115
92
  | `capabilities` | boolean | `false` | With `action: "list"`, return compact prompt-free rows and `details.agentCapabilities` machine-readable records for each agent's declared/default routing capabilities. External CLI rows also include their command and passive local availability. |
116
93
  | `async` | boolean | default-on | Background execution. Workflows default to background. `async:false` blocks the parent until completion. A local foreground child runs inside the parent Pi process and never loads the parent's ambient extensions, but it does inherit the providers those extensions registered. A pane-native remote foreground child instead uses the remote machine's provider discovery and configuration. Agents that need MCP tools (`mcpDirectTools`, or MCP tools from an ambient adapter such as pi-mcp-adapter) must run as background children, which load them inside the detached runner process. |
117
- | `chatProgress` | `auto \| off \| live-card` | `auto` | WorkflowScript chat projection. `auto` renders a live in-chat card only for watched foreground workflows in the same Git repository, including managed worktrees; it is off otherwise. Explicit `live-card` requires `async:false` and the same Git repository. Async workflows have no inline live card, so omit `chatProgress` or use `auto`/`off`; use `async:false` only when the parent must block. |
94
+ | `chatProgress` | `auto \| off \| live-card` | `auto` | Workflow chat projection. `auto` renders a live in-chat card only for watched foreground workflows in the same Git repository, including managed worktrees; it is off otherwise. Explicit `live-card` requires `async:false` and the same Git repository. Async workflows have no inline live card, so omit `chatProgress` or use `auto`/`off`; use `async:false` only when the parent must block. |
118
95
  | `isolation` | `none \| worktree` | - | Workflow child isolation. `none` runs in the shared cwd and does not need Git. `worktree` requires a managed Git worktree. Do not combine it with a contradictory `worktree` value. |
119
- | `baseRef` | string | `HEAD` | `HEAD` or a supported named ref such as `refs/heads/release`, `refs/tags/v1`, or `origin/main`. Full 40/64-character commit IDs and revision expressions such as `HEAD~1` are unsupported. The ref must resolve to a commit at worktree allocation; omitted values default to `HEAD` resolved at that time. Source-checkout cleanliness is still checked. For workflowScript, set it on the outer request as a default or on an individual `runs.run`/`runs.all` child to override it. |
96
+ | `baseRef` | string | `HEAD` | `HEAD` or a supported named ref such as `refs/heads/release`, `refs/tags/v1`, or `origin/main`. Full 40/64-character commit IDs and revision expressions such as `HEAD~1` are unsupported. The ref must resolve to a commit at worktree allocation; omitted values default to `HEAD` resolved at that time. Source-checkout cleanliness is still checked. For a workflow script, set it on the outer request as a default or on an individual `runs.run`/`runs.all` child to override it. |
120
97
  | `timeoutMs` / `maxRuntimeMs` | number | config `timeoutMs`, else 30 min foreground / single-agent async | Optional run-level max runtime in milliseconds. Both aliases may be supplied only when their values agree. When omitted, the global [`timeoutMs`](configuration.md#timeoutms) config provides the default; absent that, foreground and plain single-agent async runs fall back to 30 minutes, while composite async runs (chains, parallel tasks, workflows) stay unbounded at the top level. Expiration of this run-level deadline is terminal. |
121
98
  | `toolTimeoutMs` | number | fast-tool default | Optional positive hard per-tool-call deadline in milliseconds. Precedence: call value → agent frontmatter → config → `PI_SUBAGENT_TOOL_TIMEOUT_MS`. The timer starts on `tool_execution_start`, clears on the matching `tool_execution_end`, and terminates the run with `timedOut: true` if the tool remains open. When omitted, known-fast built-in tools get a five-minute default; long-running tools get attention notices but no hard default. It never extends the run deadline; `contact_supervisor`, `intercom`, and `bg_wait` are exempt. |
122
99
  | `checkpointBeforeDeadlineMs` | number | none | Async single-agent runs only. The runner requests that the child "checkpoint and stop" this many milliseconds before the run deadline (finish the current tool call, report changed files, build/test state, remaining work, commit/PR state; start no new work). This best-effort steer uses the normal steering lifecycle at the next tool boundary, so the receipt is visible in status and events; the ordinary deadline kill still applies. Precedence: call value → config `checkpointBeforeDeadlineMs`. Disarmed when the deadline leaves under one second before the checkpoint. |
123
100
  | `toolBudget` | object | none | Optional child tool-call budget `{ soft?, hard, block? }`: `hard` is a positive integer and `soft`, if set, is a positive integer no greater than `hard`. At `soft` the child is nudged to finalize. After `hard`, configured tools are blocked; `block` defaults to `read`, `grep`, `find`, and `ls`, and accepts either a nonempty array of tool names or `"*"` for every tool call. Final assistant text is never blocked. |
124
101
  | `usageBudget` | object | none | Optional root-only reported-usage budget `{ tokens?: { soft?, hard }, costUsd?: { soft?, hard } }`. Include at least one metric; each `hard` must be positive and each optional `soft` positive and no greater than its `hard`. Soft limits are status-only. Hard limits prevent later child launches after reported usage is reconciled; already-running children are not stopped and no reservations are made. |
125
102
  | `extensionBindings` | object | none | Child-only plain JSON keyed by namespaces like `package.name/1` (positive version): at most 16 namespaces, nesting depth 16, 256 total object properties, and 16 KiB of canonical UTF-8 JSON. Native Pi launches only; external runners and retained resumes reject it. |
126
- | `preflight` | object | none | Advisory lane hints for `workflowScript` or `workflowScriptPath` only; not accepted with named workflows or direct children. See [bounded workflows](workflows.md#opt-in-bounded-workflows). |
103
+ | `preflight` | object | none | Advisory lane hints for raw scripts (`workflow: true` or a script path) only; not accepted with named workflows or direct children. See [bounded workflows](workflows.md#opt-in-bounded-workflows). |
127
104
  | `cwd` | string | runtime cwd | Override working directory. With `machine`, the directory on that machine. |
128
105
  | `machine` | string | - | Herdr saved machine (label or profile id) for external-cli agents; see [agents.md](agents.md#running-external-cli-agents-on-a-herdr-saved-machine). |
129
- | `maxOutput` | object | none | Final output truncation limits `{ bytes?, lines? }`. For child runs it is only applied when set; there is no default cap on the inline path, so use `outputMode: "file-only"` for large outputs. For `workflowScript` results, the Return, Emitted, and Console sections are always capped, at 200 KB / 5000 lines unless `maxOutput` sets other limits. |
106
+ | `maxOutput` | object | none | Final output truncation limits `{ bytes?, lines? }`. For child runs it is only applied when set; there is no default cap on the inline path, so use `outputMode: "file-only"` for large outputs. For workflow script results, the Return, Emitted, and Console sections are always capped, at 200 KB / 5000 lines unless `maxOutput` sets other limits. |
130
107
  | `artifacts` | boolean | true | Write debug artifacts. |
131
108
  | `includeProgress` | boolean | false | Include full progress in result. |
132
109
  | `share` | boolean | false | Upload session export to GitHub Gist. |
@@ -156,26 +133,24 @@ The workflow trace records the attempt and receipt. Always await, return, or inc
156
133
 
157
134
  For advanced rolling fanout, keep the launched `runs.run` promises in ordinary JavaScript data only when every promise is later observed with direct `await`, `Promise.race`, or `Promise.all`. `Promise.race` gives the next completed child, `runs.steer` can challenge a still-running keyed sibling, and `Promise.all` collects the rest. No separate `runs.start`, `runs.next`, or `runs.collect` API is exposed.
158
135
 
159
- ```js
160
- { workflowScript: `
161
- let pending = [
162
- { key: "writer", promise: runs.run("writer", { agent: "worker", task: "Draft the fix" }).then((result) => ({ key: "writer", result })) },
163
- { key: "reviewer", promise: runs.run("reviewer", { agent: "reviewer", task: "Review likely risks" }).then((result) => ({ key: "reviewer", result })) }
164
- ];
165
- const first = await Promise.race(pending.map((child) => child.promise));
166
- pending = pending.filter((child) => child.key !== first.key);
167
- const target = pending[0];
168
- const receipt = await runs.steer(target.key, "Use this early review:\n" + first.result.output, { mode: "auto" });
169
- const rest = await Promise.all(pending.map((child) => child.promise));
170
- return { first: first.key, rest: rest.map((child) => child.key), receipt };
171
- ` }
136
+ ```js workflow
137
+ let pending = [
138
+ { key: "writer", promise: runs.run("writer", { agent: "worker", task: "Draft the fix" }).then((result) => ({ key: "writer", result })) },
139
+ { key: "reviewer", promise: runs.run("reviewer", { agent: "reviewer", task: "Review likely risks" }).then((result) => ({ key: "reviewer", result })) }
140
+ ];
141
+ const first = await Promise.race(pending.map((child) => child.promise));
142
+ pending = pending.filter((child) => child.key !== first.key);
143
+ const target = pending[0];
144
+ const receipt = await runs.steer(target.key, "Use this early review:\n" + first.result.output, { mode: "auto" });
145
+ const rest = await Promise.all(pending.map((child) => child.promise));
146
+ return { first: first.key, rest: rest.map((child) => child.key), receipt };
172
147
  ```
173
148
 
174
149
  ### Output mode details
175
150
 
176
151
  Use `outputMode: "file-only"` when a saved output may be large and the parent only needs a pointer. The returned text is a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` Failed runs and save errors still return normal inline output for debugging.
177
152
 
178
- In workflowScript, give each child an explicit output path when later script steps need a durable file reference. A child with only read-only tools does not need direct filesystem access for `output`: it returns the complete artifact in its final response and the runtime persists it. Children with mutation-capable tools retain the direct-write instruction.
153
+ In a workflow script, give each child an explicit output path when later script steps need a durable file reference. A child with only read-only tools does not need direct filesystem access for `output`: it returns the complete artifact in its final response and the runtime persists it. Children with mutation-capable tools retain the direct-write instruction.
179
154
 
180
155
  The `output` field is the API binding; a filename mentioned in task text (for example, `Write your findings to exactly this path: report.md`) is only instruction and does not override runtime routing. When a later workflow step or parent needs a durable file, set `output` on `runs.run`/`runs.all` and return the child’s `outputReference`, `outputPathMapping`, or `artifactPaths`; arbitrary literal strings returned by workflow JavaScript are not rewritten. Omitted child output may use a managed aggregate-derived sibling path.
181
156
 
@@ -185,20 +160,18 @@ Workflows get `await state.get(key)` and `await state.set(key, value)` through t
185
160
 
186
161
  Completed workflow children from the current parent session stay addressable as retained children. `{ action: "children.list" }` lists up to the last 10 with their run ids and explicit `resumable` or `not resumable` state. This workflow-only roster is not an exhaustive list of direct native children. Resume only rows reported `resumable`. When the exact run id of an intended direct child is known, inspect it with `{ action: "status", id: "<run-id>" }`; if status identifies the candidate, attempt `{ action: "resume", id: "<run-id>", message: "..." }`. Resume performs the authoritative eligibility check and may reject the attempt. Start a same-role fallback challenge, labeled as fallback, only when no known candidate exists or resume rejects eligibility. A later workflow continues a resumable child by passing `resume` instead of `agent`:
187
162
 
188
- ```js
189
- { workflowScript: `
190
- let writer = await runs.run("implement", { agent: "worker", task: "Implement the accepted contract" });
191
- for (const pass of [1, 2]) {
192
- if (!writer.runId) throw new Error("writer did not return a retained run id");
193
- writer = await runs.run("followup-" + pass, { resume: writer.runId, task: "Revisit pass " + pass + ": " + writer.output });
194
- }
195
- return writer;
196
- ` }
163
+ ```js workflow
164
+ let writer = await runs.run("implement", { agent: "worker", task: "Implement the accepted contract" });
165
+ for (const pass of [1, 2]) {
166
+ if (!writer.runId) throw new Error("writer did not return a retained run id");
167
+ writer = await runs.run("followup-" + pass, { resume: writer.runId, task: "Revisit pass " + pass + ": " + writer.output });
168
+ }
169
+ return writer;
197
170
  ```
198
171
 
199
172
  Each workflow key identifies one result lane. Use a new stable workflow key for every distinct retained resume pass; same-key calls are reused only when launch parameters are identical, and incompatible parameters are rejected.
200
173
 
201
- Inside `workflowScript`, `await runs.run(key, { resume, task })` waits for the revived child to finish and returns its completed output and new `runId`. Each resume can return a new retained run id, so loops must continue from the latest returned `runId`. Top-level `{ action: "resume" }` remains detached and returns a background-run receipt.
174
+ Inside a workflow script, `await runs.run(key, { resume, task })` waits for the revived child to finish and returns its completed output and new `runId`. Each resume can return a new retained run id, so loops must continue from the latest returned `runId`. Top-level `{ action: "resume" }` remains detached and returns a background-run receipt. When it revives a failed async workflow child (or a failed revival of one), the revived run becomes that key's latest run: workflow `status` adds `Revived → <run>: <state>` under the key, and keyed `resume: { workflowRunId, key, latest: true }` continues from it with lineage `[original, revived, ...]`. If the workflow was still running, the receipt it writes when it ends adds the revived runs to the key's lineage, and its completion notice keeps the child's failed result with the same `Revived →` line. The workflow's return value and state are not changed, notices already delivered are not rewritten, and a key accepts at most 16 chained revivals. Reviving a completed, paused, or stopped child does not change its key.
202
175
 
203
176
  For a simple implementation challenge outside a workflow script, send the challenge through `subagent({ action: "resume", id: "<retained-writer-run>", message: "Reconsider the implementation and make any better current-scope change." })` when `children.list` reports that retained writer as `resumable`, or attempt it after exact-id status inspection identifies a known direct-child candidate. Status is advisory; resume authoritatively checks eligibility and may reject missing recovery requirements. If there is no known candidate or resume rejects eligibility, start a same-role fallback challenge and record why it is a fallback. Use workflow `runs.run({ resume })` only when the script must await the revived writer output before the next step. Do not use `steer` as the sole challenge action for a completed retained child; `steer` with `mode: "follow_up"` only queues text for the next `resume`.
204
177
 
@@ -273,7 +246,7 @@ Rules:
273
246
 
274
247
  ### Schedule controls
275
248
 
276
- Use `schedule.create` with `workflowScript` or `workflowScriptPath`, not a direct child. `at` accepts a delay like `+10m` or an ISO timestamp with timezone; `every` accepts fixed intervals. `sessionOnly:true` binds restoration/execution to the creating session file; omitted/false is project-wide. Recurring `quiet:true` keeps successful automatic fires visible without a parent turn; failed, stopped or paused runs still wake the parent. One-shot `at` and manual `schedule.run` stay noisy unless that launch passes `quiet:true`. See [missions and schedules](missions.md#schedules) for examples and list/show/history/pause/resume/run/run-due/delete. Calendar selectors (`on`, `timezone`) and schedule mission attachment are deferred. `baseRef` resolves only at worktree allocation and still requires a clean source checkout.
249
+ Use `schedule.create` with `workflow: true` or a script path, not a direct child. `at` accepts a delay like `+10m` or an ISO timestamp with timezone; `every` accepts fixed intervals. `sessionOnly:true` binds restoration/execution to the creating session file; omitted/false is project-wide. Recurring `quiet:true` keeps successful automatic fires visible without a parent turn; failed, stopped or paused runs still wake the parent. One-shot `at` and manual `schedule.run` stay noisy unless that launch passes `quiet:true`. See [missions and schedules](missions.md#schedules) for examples and list/show/history/pause/resume/run/run-due/delete. Calendar selectors (`on`, `timezone`) and schedule mission attachment are deferred. `baseRef` resolves only at worktree allocation and still requires a clean source checkout.
277
250
 
278
251
  ## Lane merge evidence and cleanup eligibility
279
252
 
@@ -406,8 +379,8 @@ Prefer an inline JSON object. JSON-encoded object strings are tolerated only dur
406
379
 
407
380
  When one host-run command is the entire verification contract, use the `gate` shorthand instead of a full `acceptance` object:
408
381
 
409
- ```js
410
- { workflowScript: `return runs.run("impl", { agent: "worker", task: "Implement the fix", gate: "npm test" })` }
382
+ ```js workflow
383
+ return runs.run("impl", { agent: "worker", task: "Implement the fix", gate: "npm test" });
411
384
  ```
412
385
 
413
386
  `gate` normalizes to verified acceptance with that single command, so the runtime executes it on the host and records the result as evidence. Verification results are memoized per tracked workspace state and effective environment, so an unchanged tree does not rerun the same command. Use explicit `acceptance.verify` when you need multiple commands, timeouts, or custom criteria. `gate` rejects `acceptance` except `false` (treated as omitted), and rejects retained `resume` items. With `worktree: true`, the gate runs inside the child's managed worktree.
@@ -416,12 +389,12 @@ When one host-run command is the entire verification contract, use the `gate` sh
416
389
 
417
390
  A gate given as `{ command, output: "json" }` runs like a string gate, and then parses the command's stdout:
418
391
 
419
- ```js
420
- { workflowScript: `return runs.run("review", {
392
+ ```js workflow
393
+ return runs.run("review", {
421
394
  agent: "reviewer", task: "Review the change", output: "reports/review.md", outputMode: "file-only",
422
395
  gate: { command: "classify --report reports/review.md", output: "json",
423
396
  schema: { type: "object", properties: { verdict: { enum: ["ok", "blocked"] } }, required: ["verdict"] } }
424
- })` }
397
+ });
425
398
  ```
426
399
 
427
400
  - The command runs after the child's output file is saved, in the child's cwd or managed worktree, so it can read what the child wrote.
@@ -516,8 +489,12 @@ Intentionally unsupported: native Pi child options such as model override, struc
516
489
 
517
490
  Pass `share: true` to export a full session to HTML, upload it to a secret GitHub Gist through your `gh` credentials, and return a `https://shittycodingagent.ai/session/?<gistId>` URL.
518
491
 
519
- ```ts
520
- { workflowScript: `return runs.run("main", { agent: "scout", task: "..." })`, share: true }
492
+ ```js workflow
493
+ return runs.run("main", { agent: "scout", task: "..." });
494
+ ```
495
+
496
+ ```js
497
+ subagent({ workflow: true, share: true });
521
498
  ```
522
499
 
523
500
  This is disabled by default. Session data may contain source code, paths, environment variables, credentials, or other sensitive output. You need `gh` installed and authenticated.