pi-subagents 0.40.0 → 0.41.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 (119) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +246 -525
  3. package/agents/oracle.md +1 -0
  4. package/package.json +12 -4
  5. package/prompts/parallel-context-build.md +1 -1
  6. package/prompts/parallel-handoff-plan.md +1 -1
  7. package/prompts/review-loop.md +1 -1
  8. package/skills/pi-subagents/SKILL.md +6 -6
  9. package/skills/pi-subagents/references/constraints-and-recipes.md +19 -26
  10. package/skills/pi-subagents/references/execution-controls.md +98 -97
  11. package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  12. package/skills/pi-subagents/references/prompting-and-roles.md +18 -27
  13. package/src/agents/agent-management.ts +155 -65
  14. package/src/agents/agent-serializer.ts +19 -0
  15. package/src/agents/agents.ts +154 -71
  16. package/src/agents/chain-serializer.ts +10 -7
  17. package/src/agents/frontmatter.ts +5 -3
  18. package/src/agents/identity.ts +1 -1
  19. package/src/agents/proactive-skills.ts +13 -10
  20. package/src/agents/skills.ts +23 -6
  21. package/src/api/control-channel.ts +4 -0
  22. package/src/api/delegation.ts +26 -194
  23. package/src/api/external-runs.ts +129 -0
  24. package/src/api/intercom-bridge.ts +3 -0
  25. package/src/api/pi-args.ts +5 -0
  26. package/src/api/preflight.ts +3 -3
  27. package/src/api/shared-types.ts +19 -0
  28. package/src/extension/config.ts +10 -0
  29. package/src/extension/control-notices.ts +5 -39
  30. package/src/extension/doctor.ts +10 -9
  31. package/src/extension/fanout-child.ts +7 -4
  32. package/src/extension/index.ts +232 -68
  33. package/src/extension/rpc.ts +18 -12
  34. package/src/extension/schemas.ts +48 -37
  35. package/src/extension/tool-description.ts +36 -86
  36. package/src/inspectors/herdr/actions.ts +229 -0
  37. package/src/inspectors/herdr/client.ts +130 -0
  38. package/src/inspectors/herdr/inspector-runner.ts +141 -0
  39. package/src/inspectors/herdr/project-panes.ts +154 -0
  40. package/src/integrations/herdr-status.ts +330 -0
  41. package/src/intercom/intercom-bridge.ts +3 -2
  42. package/src/intercom/result-intercom.ts +5 -1
  43. package/src/missions/actions.ts +372 -0
  44. package/src/missions/lifecycle.ts +314 -0
  45. package/src/missions/store.ts +442 -0
  46. package/src/missions/types.ts +135 -0
  47. package/src/policy/authority.ts +46 -0
  48. package/src/profiles/profiles.ts +29 -3
  49. package/src/runs/background/async-execution.ts +98 -49
  50. package/src/runs/background/async-job-tracker.ts +10 -2
  51. package/src/runs/background/async-resume.ts +6 -6
  52. package/src/runs/background/async-status.ts +29 -1
  53. package/src/runs/background/auto-drain.ts +3 -3
  54. package/src/runs/background/chain-append.ts +3 -2
  55. package/src/runs/background/control-channel.ts +9 -7
  56. package/src/runs/background/fleet-view.ts +3 -4
  57. package/src/runs/background/notify.ts +2 -1
  58. package/src/runs/background/process-terminal.ts +5 -5
  59. package/src/runs/background/result-watcher.ts +13 -5
  60. package/src/runs/background/run-id-resolver.ts +3 -3
  61. package/src/runs/background/run-status.ts +35 -8
  62. package/src/runs/background/scheduled-runs.ts +602 -375
  63. package/src/runs/background/stale-run-reconciler.ts +3 -3
  64. package/src/runs/background/subagent-runner.ts +608 -445
  65. package/src/runs/background/subagent-wait.ts +50 -9
  66. package/src/runs/background/wait-subscriptions.ts +253 -0
  67. package/src/runs/background/wait-tool.ts +12 -4
  68. package/src/runs/foreground/async-steering-action.ts +3 -3
  69. package/src/runs/foreground/chain-clarify.ts +8 -4
  70. package/src/runs/foreground/chain-execution.ts +56 -30
  71. package/src/runs/foreground/execution.ts +15 -2
  72. package/src/runs/foreground/subagent-executor.ts +1023 -273
  73. package/src/runs/shared/acceptance.ts +28 -6
  74. package/src/runs/shared/child-protocol.ts +302 -22
  75. package/src/runs/shared/dynamic-fanout.ts +1 -1
  76. package/src/runs/shared/external-cli-runner.ts +130 -0
  77. package/src/runs/shared/long-running-guard.ts +42 -1
  78. package/src/runs/shared/nested-events.ts +59 -5
  79. package/src/runs/shared/nested-render.ts +9 -4
  80. package/src/runs/shared/parallel-handoff.ts +86 -2
  81. package/src/runs/shared/parallel-utils.ts +11 -2
  82. package/src/runs/shared/permissions.ts +95 -0
  83. package/src/runs/shared/pi-args.ts +11 -1
  84. package/src/runs/shared/pi-spawn.ts +11 -1
  85. package/src/runs/shared/run-history.ts +1 -1
  86. package/src/runs/shared/subagent-prompt-runtime.ts +36 -5
  87. package/src/runs/shared/subagent-startup-retry.ts +5 -2
  88. package/src/runs/shared/turn-budget.ts +6 -6
  89. package/src/runs/shared/worktree.ts +122 -12
  90. package/src/shared/accessible-dir.ts +29 -7
  91. package/src/shared/artifacts.ts +18 -1
  92. package/src/shared/fork-context.ts +3 -2
  93. package/src/shared/launch-contract.ts +1 -0
  94. package/src/shared/settings.ts +10 -0
  95. package/src/shared/types.ts +156 -14
  96. package/src/shared/utils.ts +8 -6
  97. package/src/slash/delegation-adapters.ts +32 -194
  98. package/src/slash/delegation-request.ts +43 -126
  99. package/src/slash/prompt-template-bridge.ts +158 -205
  100. package/src/slash/prompt-workflows.ts +21 -57
  101. package/src/slash/slash-bridge.ts +14 -0
  102. package/src/slash/slash-commands.ts +31 -632
  103. package/src/slash/subagents-admin.ts +18 -14
  104. package/src/tui/fleet-status.ts +156 -21
  105. package/src/tui/fleet-transcript.ts +110 -5
  106. package/src/tui/fleet.ts +56 -24
  107. package/src/tui/render.ts +291 -109
  108. package/src/types/pi-runtime-compat.d.ts +14 -0
  109. package/src/watchdog/lsp-diagnostics.ts +12 -7
  110. package/src/watchdog/model-selection.ts +2 -2
  111. package/src/watchdog/permission-arbiter.ts +145 -0
  112. package/src/watchdog/register-child.ts +1 -1
  113. package/src/watchdog/register-main.ts +1 -1
  114. package/src/watchdog/review.ts +4 -1
  115. package/src/watchdog/runtime.ts +3 -2
  116. package/src/workflows/chat-progress.ts +140 -0
  117. package/src/workflows/scripted-workflow.ts +415 -0
  118. package/agents/advisor.md +0 -73
  119. package/src/extension/chain-validation.ts +0 -181
package/README.md CHANGED
@@ -38,6 +38,21 @@ Run parallel reviewers: one for correctness, one for tests, and one for unnecess
38
38
 
39
39
  That is enough to start.
40
40
 
41
+ ## External CLI agent profiles
42
+
43
+ Agent profiles can opt into a local one-shot command instead of a Pi child. External runners add no install dependency, but the configured executable must exist at runtime. They are async-only, receive one combined system/task prompt over stdin, and use argv arrays without a shell:
44
+
45
+ ```yaml
46
+ runner:
47
+ type: external-cli
48
+ command: node
49
+ args: ["./scripts/local-reviewer.mjs"]
50
+ promptDelivery: stdin
51
+ async: true
52
+ ```
53
+
54
+ External CLI runners support status artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are written to log files, while the in-memory final stdout response and stderr error are limited to their last 64 KiB. Foreground/clarify, steer/resume/interrupt-as-pause, Pi models/tools/extensions, skills, structured output, nested subagents, and fallback models are intentionally unsupported.
55
+
41
56
  ## What happens
42
57
 
43
58
  Pi is the parent session. A subagent is a focused child Pi session with its own job.
@@ -78,7 +93,7 @@ Run a review loop on this change until reviewers stop finding fixes worth doing,
78
93
  Use scout to understand the auth flow, then have planner turn that into an implementation plan.
79
94
  ```
80
95
 
81
- Those are ordinary Pi requests. Pi decides whether to call `subagent`, which agent to use, and whether a chain or parallel run makes sense.
96
+ Those are ordinary Pi requests. Pi decides whether to call `subagent`, which agent to use, and how to express composed work with `workflowScript`.
82
97
 
83
98
  ## Common workflows
84
99
 
@@ -342,11 +357,43 @@ To keep subagents inside a budget or compliance profile, enforce a model scope.
342
357
 
343
358
  Foreground runs stream progress in the conversation while they run. They default to a generous 30-minute wall-clock timeout when neither the call nor the selected agent provides a timeout; explicit `timeoutMs`/`maxRuntimeMs` and agent defaults win.
344
359
 
345
- Background runs keep working after control returns to you. Inspect active runs with `subagent({ action: "status" })`, or a specific run with `subagent({ action: "status", id: "..." })`. In the TUI, a persistent FleetView below the editor by default shows `main` plus active children with task, elapsed time, and token totals. Set `fleetViewPlacement` to `"aboveEditor"` to move it above the editor. When the focused editor is empty, press `↓` or `←` to activate FleetView, then use `↑`/`↓` or `j`/`k` to select a child and `Enter` to inspect it; printable navigation keys are never intercepted before activation.
360
+ Background runs keep working after control returns to you. Inspect active runs with `subagent({ action: "status" })`, or a specific run with `subagent({ action: "status", id: "..." })`. In the TUI, a persistent FleetView below the editor keeps active work visible as a compact summary. Set `fleetViewPlacement` to `"aboveEditor"` to move it above the editor. When the focused editor is empty, press `↓` or `←` to expand the summary into `main` plus active children with task, elapsed time, and token totals; then use `↑`/`↓` or `j`/`k` to select a child and `Enter` to inspect it. Printable navigation keys are never intercepted before activation.
346
361
 
347
362
  `/subagents-fleet` opens the live fleet inspector with current-session foreground work, recent async children, structured Markdown/tool transcripts, and completed output/session paths. Use `↑`/`↓` or `j`/`k` to select a child, `Shift+K`/`Shift+J` to scroll one line, `PgUp`/`PgDn` to scroll one page, `x`/`Ctrl+O` to toggle tool details, `r` to refresh, and `Esc` to close. For a selected live async child, `s` sends an acknowledged steer message and `D` stops its top-level async run after confirmation. `Ctrl+Alt+F` opens the same inspector even while a foreground turn is active and slash input is queued. Without a TUI, `/subagents-fleet` retains the textual `subagent({ action: "status", view: "fleet" })` fallback, and mutations use explicit commands: run `/subagents-stop` and pick from the selector, or use `/subagents-stop <run-id>` / `subagent({ action: "stop", id: "..." })` when you already know the id. Use `/subagents-detach [run-id]` only for an active foreground single-subagent run you want to leave running without terminating; the eventual result remains available through status/wait. To inspect one background child in text, use `subagent({ action: "status", id: "...", view: "transcript" })`; add `index` for a specific child in a parallel or chain run.
348
363
 
349
- FleetView replaces the legacy above-editor async widget by default, while completion notifications remain enabled. Parallel runs show every active child independently. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones. When a child is explicitly allowed to fan out with `tools: subagent`, its nested runs appear under that parent child in the main status tree instead of being hidden inside the child process.
364
+ FleetView replaces the legacy above-editor async widget by default. Successful background completions stay quiet so inactive Pi tabs are not marked unread, while failed or paused completions still notify the originating session. Parallel runs show every active child independently. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones. When a child is explicitly allowed to fan out with `tools: subagent`, its nested runs appear under that parent child in the main status tree instead of being hidden inside the child process.
365
+
366
+ When Pi runs inside [Herdr](https://herdr.dev), pi-subagents automatically reports active async-run counts through Herdr pane metadata. The bridge is enabled only when Herdr supplies `HERDR_ENV=1` and `HERDR_PANE_ID`; outside Herdr it registers no listeners or timers. It restores current-session active runs after `/reload` or `/resume`, refreshes metadata while work is active, and clears it on completion or shutdown. To show the reported label in the expanded Agent sidebar, include `state_text` or `$summary` in its row layout, for example:
367
+
368
+ ```toml
369
+ [ui.sidebar.agents]
370
+ rows = [
371
+ ["state_icon", "workspace", "tab"],
372
+ ["agent", "state_text"],
373
+ ]
374
+ ```
375
+
376
+ The bridge uses Herdr's existing `herdr:blocked` sibling event when an async child needs attention. It also emits `herdr:busy` while async work remains. Herdr versions that support that sibling event keep the pane's semantic state `working`; older versions ignore it safely and still display the metadata label while the Pi integration remains the lifecycle authority.
377
+
378
+ Herdr 0.7.5+ can also open an on-demand inspector for an existing async run:
379
+
380
+ ```ts
381
+ subagent({ action: "inspector.open", id: "<run-id>", index: 0, focus: true })
382
+ subagent({ action: "inspector.status", id: "<run-id>", index: 0 })
383
+ subagent({ action: "inspector.close", id: "<run-id>", index: 0 })
384
+ ```
385
+
386
+ The inspector is a raw dashboard pane, not the child process and not a literal attach. It reads lifecycle/status/output/mission artifacts and sends `steer` or `stop` through pi-subagents' existing control inbox. Closing it never stops the run. Herdr remains optional, ordinary launches stay headless, and missing/older Herdr versions affect only Herdr-specific inspector and project-pane actions. FleetView opens the selected active async child with `H`. Use `focus` only with `inspector.open`; Herdr 0.7.5 cannot focus an arbitrary existing raw pane id.
387
+
388
+ For substantial work in another codebase, Herdr 0.7.5+ can open a project-owned Pi pane rooted in that repository:
389
+
390
+ ```ts
391
+ subagent({ action: "project.open", cwd: "/path/to/repo", message: "Own the auth refresh mission for this project." })
392
+ subagent({ action: "project.status", cwd: "/path/to/repo" })
393
+ subagent({ action: "project.close", cwd: "/path/to/repo" })
394
+ ```
395
+
396
+ A project pane runs its own Pi session in the target directory, so subagents launched from that pane use that project's config, agents, skills, files, git state, and missions. The parent session keeps coordination authority; existing headless runs are not moved into the pane. Pane bindings live under `<projectRoot>/.pi-subagents/project-panes/herdr.json` and are only a local pointer to the Herdr pane.
350
397
 
351
398
  You can also ask naturally:
352
399
 
@@ -358,11 +405,11 @@ Lifecycle artifact v3 adds `process-terminal-candidate.json` (private runner evi
358
405
 
359
406
  Async runs also write machine-readable lifecycle artifacts for observability and workflow gates. For a top-level async run, `details.asyncDir` points at a directory containing `status.json`, `events.jsonl`, `output-<index>.log`, and `subagent-log-<runId>.md`; the final summary is written to Pi's subagent results directory as `<runId>.json`. Nested async runs use the same shape under the nested async root and are discoverable through status projections that read the nested-run registry. These files are append/update artifacts only; interactive foreground behavior is unchanged.
360
407
 
361
- Foreground and async runners share bounded child-protocol handling. A child JSONL line above 4 MiB fails with structured `protocolError` code `protocol_output_limit`, stderr retains only its latest 128 KiB, split UTF-8 and final unterminated JSON events remain valid, and `agent_end.willRetry` defers completion until the child settles. Current Pi builds use `agent_settled` as the terminal watermark; older builds retain the bounded terminal-message fallback.
408
+ Foreground and async runners share bounded child-protocol handling. A child JSONL line above 16 MiB fails with structured `protocolError` code `protocol_output_limit`; oversized Pi `turn_end` and `agent_end` aggregates are the exception because they duplicate granular events, so runners replace them with bounded lifecycle records while preserving `agent_end.willRetry`. Stderr retains only its latest 128 KiB, split UTF-8 and final unterminated JSON events remain valid, and `agent_end.willRetry` defers completion until the child settles. Current Pi builds use `agent_settled` as the terminal watermark; older builds retain the bounded terminal-message fallback.
362
409
 
363
- The stable v1 status/result fields are `lifecycleArtifactVersion`, `runId`/`id`, `sessionId`, `mode`, `state`, `startedAt`, `lastUpdate`, `endedAt`, `durationMs`, `cwd`, `asyncDir`, `sessionFile`, `outputFile`, `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `model`/`attemptedModels`/`modelAttempts`, `toolCount`, `turnCount`, optional `launchResolvedExtensions`, optional `runtimeAcknowledgedExtensions`, and nested `children` when a child is allowed to launch subagents. `launchResolvedExtensions` is parent-resolved launch intent only: it reports opaque extension identifiers and whether ambient extensions were disabled, without exposing raw extension paths or claiming the child runtime acknowledged that those extensions loaded. Cooperating child extensions can acknowledge child-runtime registration by emitting `subagent:acknowledge-extension` on the child process `pi.events` bus with payload `{ id: string }`. Acknowledgement ids are self-declared opaque strings, must be non-empty, at most 128 characters, contain only `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `@`, `+`, or `-`, and must not contain `/`, `\\`, or `..`. The reported `runtimeAcknowledgedExtensions` projection is `{ version: 1, source: "child-runtime", ids, omitted }`, deduplicates ids, keeps at most 32 ids, and counts additional valid unique ids in `omitted`. It is best-effort observability only: absence means no cooperating extension acknowledged, and presence means only that the extension registered in the child runtime, not that its tools, health checks, or features succeeded. Late acknowledgements after terminal serialization are ignored. `events.jsonl` records lifecycle transitions such as `subagent.run.started`, `subagent.step.started`, `subagent.step.completed`/`failed`/`paused`/`stopped`, control attention events, nested interrupt failures, and `subagent.run.completed`/`stopped`; run boundary events include the lifecycle artifact version. Consumers should read these JSON files instead of scraping terminal output; unknown fields and event types should be ignored for forward compatibility.
410
+ The status/result fields are `lifecycleArtifactVersion`, `runId`/`id`, `sessionId`, `mode`, `state`, `startedAt`, `lastUpdate`, `endedAt`, `durationMs`, `cwd`, `asyncDir`, `sessionFile`, `outputFile`, `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `model`/`attemptedModels`/`modelAttempts`, `toolCount`, `turnCount`, optional `launchResolvedExtensions`, optional `runtimeAcknowledgedExtensions`, and nested `children` when a child is allowed to launch subagents. `launchResolvedExtensions` is parent-resolved launch intent only: it reports opaque extension identifiers and whether ambient extensions were disabled, without exposing raw extension paths or claiming the child runtime acknowledged that those extensions loaded. Cooperating child extensions can acknowledge child-runtime registration by emitting `subagent:acknowledge-extension` on the child process `pi.events` bus with payload `{ id: string }`. Acknowledgement ids are self-declared opaque strings, must be non-empty, at most 128 characters, contain only `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `@`, `+`, or `-`, and must not contain `/`, `\\`, or `..`. The reported `runtimeAcknowledgedExtensions` projection is `{ version: 1, source: "child-runtime", ids, omitted }`, deduplicates ids, keeps at most 32 ids, and counts additional valid unique ids in `omitted`. It is best-effort observability only: absence means no cooperating extension acknowledged, and presence means only that the extension registered in the child runtime, not that its tools, health checks, or features succeeded. Late acknowledgements after terminal serialization are ignored. `events.jsonl` records lifecycle transitions such as `subagent.run.started`, `subagent.step.started`, `subagent.step.completed`/`failed`/`paused`/`stopped`, control attention events, nested interrupt failures, and `subagent.run.completed`/`stopped`; run boundary events include the lifecycle artifact version. Consumers should read these JSON files instead of scraping terminal output; unknown fields and event types should be ignored for forward compatibility.
364
411
 
365
- Other Pi extensions can use the versioned in-process event-bus RPC instead of scraping slash output or calling internal modules. Listen for `subagents:rpc:v1:ready`, send requests on `subagents:rpc:v1:request`, and read replies from `subagents:rpc:v1:reply:<requestId>`. The `ping` capability metadata also advertises `events.asyncComplete` for exact process-local completion correlation after RPC `spawn`. Delegation v1/v2 progress updates carry `runId` as soon as foreground execution allocates it, so a caller can retain the package-owned revival target even if its own tool turn is interrupted before the terminal response. Foreground `details.results[]` rows also include a numeric `index` that is unique within the run and stable across partial progress snapshots and the final result; use `(runId, index)` instead of row position to correlate single, counted parallel, and chain children.
412
+ Other Pi extensions can use the in-process event-bus RPC instead of scraping slash output or calling internal modules. Listen for `subagents:rpc:v1:ready`, send requests on `subagents:rpc:v1:request`, and read replies from `subagents:rpc:v1:reply:<requestId>`. The `ping` capability metadata also advertises `events.asyncComplete` for exact process-local completion correlation after RPC `spawn`. Structured delegation progress updates carry `runId` as soon as foreground execution allocates it, so a caller can retain the package-owned revival target even if its own tool turn is interrupted before the terminal response. Foreground `details.results[]` rows also include a numeric `index` that is unique within the run and stable across partial progress snapshots and the final result; use `(runId, index)` instead of row position to correlate single, counted parallel, and chain children.
366
413
 
367
414
  ```typescript
368
415
  const requestId = crypto.randomUUID();
@@ -378,7 +425,7 @@ pi.events.emit("subagents:rpc:v1:request", {
378
425
  });
379
426
  ```
380
427
 
381
- The v1 methods are `ping`, `status`, `spawn`, `steer`, `interrupt`, `stop`, and `resume`. `status`, `steer`, `interrupt`, and `resume` reuse the normal package-owned actions. `ping.capabilities.launchResolvedExtensions` advertises the optional launch-resolved extension projection in status details. `ping.capabilities.runtimeAcknowledgedExtensions` advertises the optional child-runtime acknowledgement projection and event name. When `ping.capabilities.fleetStatus` is `{ version: 1 }`, successful `status` replies additionally include `data.fleet`: `{ version: 1, entries, totalActive, omitted }`. Entries are bounded, current-session public display records with an opaque reconciliation `key`, resolved `agent`, optional `role`, `model`, `effort`, caller-facing `goal`, safe `startedAt`, and `{ input, output, total }` tokens. `totalActive` and `omitted` preserve overflow information beyond the bounded entry window. The DTO intentionally never exposes run, async, or tool IDs; clients must ignore unknown fields and fall back to status text when the capability is absent. `steer` requires an async run `id` (plus optional child `index`) and a non-empty `message`; its reply preserves the normal acknowledged-delivery result. RPC steering disables the direct tool's pause-and-revive recovery so an extension keeps authority over the exact child it spawned; `ping.capabilities.nonRecoveringSteer` advertises this guarantee. `resume` requires a run target and non-empty `message`; it delegates to the existing revival path, which validates current-session ownership, persisted session/recovery metadata, stopped/live state, capability ceilings, and the exclusive session lease before returning the new async run details. Callers may request a `file-only` output path for the revived result without overriding its model, tools, or budgets. `ping.capabilities.resume` advertises this seam. `spawn` is async-only: omit `async` or set `async: true`, omit `clarify` or set `clarify: false`, and do not pass management `action` values. It goes through the same executor as the `subagent` tool, so agent discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status all behave the same. `stop` targets current-session top-level async runs through the stop control channel and records a `stopped` lifecycle instead of reporting a timeout.
428
+ The RPC methods are `ping`, `status`, `spawn`, `steer`, `interrupt`, `stop`, and `resume`. `status`, `steer`, `interrupt`, and `resume` reuse the normal package-owned actions. `ping.capabilities.launchResolvedExtensions` advertises the optional launch-resolved extension projection in status details. `ping.capabilities.runtimeAcknowledgedExtensions` advertises the optional child-runtime acknowledgement projection and event name. When `ping.capabilities.fleetStatus` is `{ version: 1 }`, successful `status` replies additionally include `data.fleet`: `{ version: 1, entries, totalActive, omitted }`. Entries are bounded, current-session public display records with an opaque reconciliation `key`, resolved `agent`, optional `role`, `model`, `effort`, caller-facing `goal`, safe `startedAt`, and `{ input, output, total }` tokens. `totalActive` and `omitted` preserve overflow information beyond the bounded entry window. The DTO intentionally never exposes run, async, or tool IDs; clients must ignore unknown fields and fall back to status text when the capability is absent. `steer` requires an async run `id` (plus optional child `index`) and a non-empty `message`; its reply preserves the normal acknowledged-delivery result. RPC steering disables the direct tool's pause-and-revive recovery so an extension keeps authority over the exact child it spawned; `ping.capabilities.nonRecoveringSteer` advertises this guarantee. `resume` requires a run target and non-empty `message`; it delegates to the existing revival path, which validates current-session ownership, persisted session/recovery metadata, stopped/live state, capability ceilings, and the exclusive session lease before returning the new async run details. Callers may request a `file-only` output path for the revived result without overriding its model, tools, or budgets. `ping.capabilities.resume` advertises this seam. `spawn` is async-only: omit `async` or set `async: true`, omit `clarify` or set `clarify: false`, and do not pass management `action` values. It goes through the same executor as the `subagent` tool, so agent discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status all behave the same. `stop` targets current-session top-level async runs through the stop control channel and records a `stopped` lifecycle instead of reporting a timeout.
382
429
 
383
430
  `pi.events` is in-process only. It does not reach separate Pi processes or child subagents; use the file lifecycle artifacts or `pi-intercom` for cross-process coordination.
384
431
 
@@ -454,107 +501,50 @@ If messages do not show up, run:
454
501
 
455
502
  For normal use, you do not need to configure anything. Advanced users can tune the bridge with `intercomBridge` in the configuration section below.
456
503
 
457
- At this point, you know enough to use the plugin. The rest of this README is reference material for exact command syntax, custom agents, saved chains, worktrees, and configuration.
458
-
459
- ## Optional pi-permission-system integration
460
-
461
- [`@gotgenes/pi-permission-system`](https://github.com/gotgenes/pi-packages/tree/main/packages/pi-permission-system)
462
- adds a second policy layer — `allow` / `ask` / `deny` — on top of
463
- pi-subagents' visibility-based tool restrictions.
504
+ At this point, you know enough to use the plugin. The rest of this README is reference material for exact command syntax, custom agents, scripted workflows, and configuration.
464
505
 
465
- The two compose independently:
506
+ ## Native child tool permissions
466
507
 
467
- | Layer | What it controls | Who provides it |
468
- |-------|-----------------|-----------------|
469
- | Visibility | Which tools are registered before the session starts | pi-subagents (`tools:` frontmatter key) |
470
- | Policy | Runtime allow/ask/deny decisions on every tool call, bash command, MCP operation | pi-permission-system (`permission:` frontmatter key) |
508
+ Native permissions are opt-in and apply only to Pi child runtimes. With no rules configured, every tool call passes through unchanged. Configure explicit non-bash rules globally in `~/.pi/agent/extensions/subagent/config.json`:
471
509
 
472
- ### Installing
473
-
474
- ```bash
475
- pi install npm:@gotgenes/pi-permission-system
510
+ ```json
511
+ {
512
+ "permissions": {
513
+ "rules": {
514
+ "read": "allow",
515
+ "write": "ask",
516
+ "edit": "deny"
517
+ }
518
+ }
519
+ }
476
520
  ```
477
521
 
478
- No configuration is required for the integration it is automatic when both
479
- extensions are installed. pi-subagents passes the parent session identity
480
- to child processes via the `PI_SUBAGENT_PARENT_SESSION` environment variable,
481
- which the permission system uses to forward `ask` prompts from headless
482
- subagent processes back to the parent session's UI.
483
-
484
- ### Per-agent permission frontmatter
485
-
486
- Agent files can include a `permission:` block alongside the standard `tools:`
487
- key. The permission system reads it independently:
522
+ Custom agents can override matching global rules with a `permission:` or `permissions:` frontmatter block:
488
523
 
489
524
  ```yaml
490
525
  ---
491
526
  name: worker
492
- tools: bash,read,write,edit
493
527
  permission:
494
- "*": ask
495
- read: allow
496
- bash:
497
- "*": ask
498
- "git *": allow
499
- "npm test": allow
528
+ write: allow
529
+ edit: ask
500
530
  ---
501
531
  ```
502
532
 
503
- In this example the subagent extension restricts visibility to four tools,
504
- and the permission system then applies `ask`/`allow` policy within that
505
- visible set. Both keys coexist without collision.
533
+ Rules support `allow`, `ask`, and `deny`. Agent rules override matching global rules; omitted and unknown tools default to `allow`. Explicit `allow` removes an inherited restriction. The gate is not registered when the resolved policy has no `ask` or `deny` rules.
506
534
 
507
- ### Checking the integration
535
+ An explicit `ask` pauses that exact tool call and sends a bounded, redacted preview to a one-call permission arbiter owned by the built-in child watchdog. The arbiter uses the configured child-watchdog model and returns only `approve` or `deny`; it does not notify the parent agent. Enable and configure `subagents.watchdog.children` before using `ask` rules. A disabled watchdog, missing model/auth, timeout, malformed response, or runtime error denies the call with a clear error.
508
536
 
509
- Run `/subagents-doctor` to check the permission system status.
510
- If `ask` prompts from children are not reaching the parent UI, verify both
511
- extensions are installed:
537
+ Asked requests and decisions are written to bounded audit JSONL, including `decisionSource: "watchdog"` and bounded failure reasons. Ordinary direction and clarification through `contact_supervisor` or the optional `pi-intercom` extension remain separate and are never permission-gated.
512
538
 
513
- ```bash
514
- pi list
515
- ```
516
-
517
- ### How it works
539
+ `bash` is always passed through by pi-subagents. Bash rules are rejected rather than parsed, gated, denied, or audited. Install and configure `pi-guard` when command-level bash policy is needed.
518
540
 
519
- At session start, the interactive (root) session records its own identity in
520
- `PI_SUBAGENT_PARENT_SESSION`. When pi-subagents launches a child, it passes the
521
- launching session's identity to that child explicitly, falling back to the
522
- inherited environment variable. When the permission system inside a child
523
- encounters an `ask` permission, it reads this variable to locate the parent
524
- session and forwards the confirmation request there.
541
+ A pi-subagents child is headless, so a pi-guard rule that resolves to `ask` cannot request approval from the parent Pi UI. Native permissions do not forward pi-guard decisions; they only apply to the separate non-bash child permission gate. For child-specific policy, use `PI_GUARD` through a `PI_SUBAGENT_PI_BINARY` wrapper or an equivalent launch wrapper, and configure explicit `allow` or `deny` rules. An `allow` rule grants execution; it is not approval forwarding, so retain explicit denies for commands the child must not run.
525
542
 
526
- This resolves an interactive prompt only when the parent it points at is the
527
- interactive session — i.e. for the direct children of the root session. A
528
- nested child's parent is itself a headless subagent process with no UI to
529
- surface the prompt, so `ask` policies are best placed on agents that run as
530
- direct children of the interactive session.
543
+ External CLI profiles are opaque processes, so native permissions cannot intercept their tools. A launch with effective `ask` or `deny` rules is rejected for an external CLI agent instead of claiming enforcement.
531
544
 
532
545
  ## Direct commands
533
546
 
534
- Skip this section until you want exact syntax.
535
-
536
- | Command | Description |
537
- |---------|-------------|
538
- | `/run <agent> [task]` | Run one agent; omit the task for self-contained agents |
539
- | `/chain agent1 "task1" -> agent2 "task2"` | Run agents in sequence |
540
- | `/chain scout "scan" -> (reviewer "A" \| reviewer "B") -> writer "fix"` | Run a chain with a static parallel group inline |
541
- | `/parallel agent1 "task1" -> agent2 "task2"` | Run agents in parallel |
542
- | `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` or `.chain.json` workflow |
543
- | `/subagent-cost` | Show parent plus child subagent token usage and cost for this session |
544
- | `/subagents [agent] [model\|thinking\|prompt\|details]` | Interactively inspect or edit an agent's model, thinking level, or system prompt |
545
- | `/subagents-doctor` | Show read-only setup diagnostics |
546
- | `/subagents-detach [run-id]` | Detach an active foreground single-subagent run without terminating its child |
547
- | `/subagents-models [agent]` | Show the runtime-loaded builtin model mapping, optionally filtered to one builtin |
548
- | `/subagents-watchdog [status|on|off|recommend-model|model ...|session model ...|check]` | Show or configure the opt-in watchdog; use a strong complementary model such as Opus 4.8 high or GPT 5.5 high |
549
- | `/subagents-profiles` | List saved subagent profiles from `~/.pi/agent/profiles/pi-subagents/` |
550
- | `/subagents-load-profile <name>` | Replace only `settings.subagents` with a saved profile and optionally switch this session to the profile worker model |
551
- | `/subagents-refresh-provider-models <provider> [--force]` | Create or refresh the cached provider model catalog |
552
- | `/subagents-generate-profiles <provider>` | Generate `<provider>.quota.json` and `<provider>.quality.json` profiles |
553
- | `/subagents-check-profile <name>` | Check a saved profile against the current registry and live model probes |
554
-
555
- Commands validate agent names locally, support tab completion, and send results back into the conversation.
556
-
557
- `/subagents` opens a compact administration flow for builtin, package, user, and project agents. Model choices refresh Pi's model registry first, thinking choices are filtered to levels declared by the selected model, and prompt editing uses Pi's native multiline editor; press Ctrl+G to open the configured external editor. Full metadata is opt-in through `details`. Edits are persisted to the field-owning layer: explicit custom-agent frontmatter remains in the agent file, while settings/profile-managed fields remain in `settings.subagents.agentOverrides`. Package-owned fields and definitions loaded through `PI_SUBAGENT_EXTRA_AGENT_DIRS` stay read-only; settings can still supply model or thinking fields omitted by a package definition.
547
+ Use `/run <agent> [task] [--bg] [--fork]` for one child. Multi-agent orchestration is expressed through `workflowScript` in the `subagent` tool; the legacy `/chain`, `/parallel`, and `/run-chain` commands are not registered.
558
548
 
559
549
  ### Profiles and provider model catalogs
560
550
 
@@ -582,132 +572,24 @@ Use the profile workflow like this:
582
572
 
583
573
  `/subagents-generate-profiles` uses the provider catalog to produce quota and quality profiles. `/subagents-check-profile` re-checks each assigned model in a saved profile against the current registry and a live probe so you can detect model removals, auth problems, or stale assignments.
584
574
 
585
- ### Per-step tasks
586
-
587
- Use `->` to separate steps and give each step its own task:
588
-
589
- ```text
590
- /chain scout "scan the codebase" -> planner "create an implementation plan"
591
- /parallel scanner "find security issues" -> reviewer "check code style"
592
- ```
593
-
594
- Both double and single quotes work. You can also use `--` as a delimiter:
595
-
596
- ```text
597
- /chain scout -- scan code -> planner -- analyze auth
598
- ```
599
-
600
- Steps without a task inherit behavior from the execution mode. Chain steps get `{previous}`, the prior step’s output. Parallel steps use the first available task as a fallback.
601
-
602
- ### Inline parallel groups in `/chain`
603
-
604
- Wrap a group of agents in parentheses and separate them with `|` to fan them out within a single chain step. The group runs all of its tasks concurrently, then the next `->` step continues once they finish:
605
-
606
- ```text
607
- /chain scout "scan" -> (reviewer "review A" | reviewer "review B") -> writer "fix"
608
- ```
609
-
610
- Notes:
611
-
612
- - Groups must contain at least two tasks separated by ` | `, each with its own task.
613
- - Group syntax is only valid between ` -> ` separators, and the group must appear as a complete step.
614
- - Only a step that *opens* with `(` is a group. Parentheses inside a shared `--` task (e.g. `/chain scout -- inspect auth (backend)`) stay literal text and keep the legacy single-agent behavior.
615
- - A group is treated as the prior step’s output for the next sequential step.
616
- - Tab completion suggests agents inside groups — after `(`, after `|`, and on each new `->` step.
617
-
618
- Add a `[...]` suffix right after the closing `)` to set step-level options on the group:
575
+ ### WorkflowScript replacements
619
576
 
620
- ```text
621
- /chain scout "scan" -> (reviewer "A" | reviewer "B")[concurrency=2,failFast,worktree] -> writer "fix"
622
- ```
623
-
624
- | Group option | Description |
625
- |--------------|-------------|
626
- | `concurrency=N` | Max tasks running at once within the group. |
627
- | `failFast` | Stop the group as soon as one task fails. |
628
- | `worktree` | Run each group task in its own git worktree. |
629
-
630
- Dynamic fanout (`expand` / `collect`) is intentionally not available inline — use the
631
- `subagent({ chain: [...] })` tool API or a saved `.chain.json` for data-driven fan-out.
632
-
633
- ```text
634
- /chain scout "analyze auth" -> planner -> worker
635
- # scout gets "analyze auth"; planner gets scout output; worker gets planner output
636
- ```
637
-
638
- For a shared task, list agents and place one `--` before the task:
639
-
640
- ```text
641
- /chain scout planner -- analyze the auth system
642
- /parallel scout reviewer -- check for security issues
643
- ```
644
-
645
- ### Inline per-step config
646
-
647
- Append `[key=value,...]` to an agent name to override defaults. `/chain` applies every key below; `/run` and `/parallel` use the execution-behavior keys (`output`, `outputMode`, `reads`, `model`, `skills`, `progress`) and ignore chain-only metadata such as `as`, `label`, `phase`, `count`, `outputSchema`, and `acceptance`.
648
-
649
- ```text
650
- /chain scout[output=context.md] "scan code" -> planner[reads=context.md] "analyze auth"
651
- /run scout[model=anthropic/claude-sonnet-4] summarize this codebase
652
- /parallel reviewer[skills=code-review+security] "review backend" -> reviewer[model=openai/gpt-5-mini] "review frontend"
653
- ```
654
-
655
- | Key | Example | Description |
656
- |-----|---------|-------------|
657
- | `output` | `output=context.md` | Write results to a file. Absolute paths are used as-is. Relative paths in `/run` resolve under `singleRunOutputBaseDir` when configured, otherwise under the run's output artifact directory. Relative paths in `/chain` and `/parallel` live under the chain or parallel run directory. |
658
- | `outputMode` | `outputMode=file-only` | Return only a concise file reference for saved output instead of the full saved content. Requires `output`; default is `inline`. |
659
- | `reads` | `reads=a.md+b.md` | Read files before executing. `+` separates multiple paths. |
660
- | `model` | `model=anthropic/claude-sonnet-4` | Override model for this step. |
661
- | `skills` | `skills=planning+review` | Override available skills. `+` separates multiple skills. |
662
- | `progress` | `progress` | Enable progress tracking. |
663
- | `as` | `as=context` | Name this step’s output so later steps can reference it. |
664
- | `label` | `label=Recon` | Human-readable label for the step. |
665
- | `phase` | `phase=analysis` | Group steps into a named phase. |
666
- | `cwd` | `cwd=packages/api` | Run the step in a subdirectory. |
667
- | `count` | `count=3` | Fan a group task into N copies (only inside a `( ... )` group). |
668
- | `outputSchema` | `outputSchema=schema.json` | Validate structured output against a JSON Schema file (path resolved against the session cwd, not an inline step `cwd`). |
669
- | `acceptance` | `acceptance=checked` | Inline evidence level: `auto`, `attested`, or `checked`. Use the tool API or saved `.chain.json` for object contracts such as `none`, `verified`, or an orthogonal review requirement. `reviewed` is an achieved status, not an input level. |
670
-
671
- Set `output=false`, `reads=false`, or `skills=false` to disable that behavior explicitly. Do not use `output=false` for file-only returns; use `outputMode=file-only` with an `output` path.
672
-
673
- Inline `[...]` values must not contain spaces or commas — keep `label`/`phase` to single tokens.
674
-
675
- ### Background and forked runs
676
-
677
- Add `--bg` to run in the background:
678
-
679
- ```text
680
- /run scout "audit the codebase" --bg
681
- /chain scout "analyze auth" -> planner "design refactor" -> worker --bg
682
- /parallel scout "scan frontend" -> scout "scan backend" --bg
683
- ```
684
-
685
- Add `--fork` to start each child from a real branched session created from the parent’s current leaf:
686
-
687
- ```text
688
- /run reviewer "review this diff" --fork
689
- /chain scout "analyze this branch" -> planner "plan next steps" --fork
690
- /parallel scout "audit frontend" -> reviewer "audit backend" --fork
691
- ```
577
+ Use stable keys and ordinary JavaScript for sequence and parallelism. For watched same-repo workflows, pass `async:false` to show the live in-chat workflow card; `chatProgress` can force `off`, `terminal`, `milestones`, or `live-card` when the automatic policy is not what you want.
692
578
 
693
- You can combine them in either order:
694
-
695
- ```text
696
- /run reviewer "review this diff" --fork --bg
697
- /run reviewer "review this diff" --bg --fork
579
+ ```js
580
+ subagent({ workflowScript: `
581
+ const scan = await runs.run("scan", { agent: "scout", task: "Scan the codebase" });
582
+ const reviews = await runs.all([
583
+ { key: "correctness", agent: "reviewer", task: "Review correctness: " + scan.output },
584
+ { key: "tests", agent: "reviewer", task: "Review tests: " + scan.output }
585
+ ]);
586
+ return reviews.map(result => result.output);
587
+ ` });
698
588
  ```
699
589
 
700
- Background runs are detached. If the parent agent has other independent work, it should keep working. In an interactive chat, it should normally return control when ready to yield and let Pi deliver the completion notification instead of blocking merely to wait. Override that default and use `subagent_wait` when the current request is run-to-completion — for example, the user asked you to report results back before continuing or a skill cannot return before its work finishes. In a non-interactive run, Pi auto-drains current-session work at `agent_end`; use `subagent_wait` when this turn must receive results before it ends. It returns when the next initially active run or registered provider item finishes or a subagent needs attention; use `subagent_wait({ all: true })` for all work active at call time, `subagent_wait({ id })` for one async or remembered detached foreground run, and `subagent_wait({ timeoutMs })` to cap the block.
701
-
702
- A foreground child can detach while it waits for a supervisor reply. Reply first, then call `subagent_wait({ id: runId })`. While that wait blocks, it streams the detached child's current tool and recent transcript activity into the pending tool row when transcript artifacts are available. The remembered run stays pending until the child exits, then emits a session-scoped completion notification with recovered output and remains inspectable through `subagent({ action: "status", id: runId })`. Do not call `resume` or launch a replacement while the child remains detached.
703
-
704
- Headless sessions also auto-drain current-session subagent and registered provider work at `agent_end`, using one absolute timeout and continuing through attention states. This is a final lifecycle safeguard rather than a replacement for explicit orchestration: `subagent_wait` still lets a model react to each result during the turn. Provider, reconciliation, timeout, and malformed-state failures remain visible errors instead of being treated as successful drains.
705
-
706
- The `oracle`/`advisor` and `worker` builtins are designed for an explicit decision loop. A typical pattern is to ask `oracle` or its `advisor` alias for diagnosis and a recommended execution prompt, then only run `worker` after the main agent approves that direction.
707
-
708
590
  ## Clarify and launch UI
709
591
 
710
- Tool calls launch directly by default. Set `clarify: true` on single, parallel, or chain runs when you want to preview and edit the workflow before it runs; slash commands launch directly.
592
+ Tool calls start background work by default. Set `async: false` when the current turn needs a foreground result, or `clarify: true` on single, parallel, or chain runs when you want to preview and edit the workflow before it runs; clarify stays foreground.
711
593
 
712
594
  Common clarify keys:
713
595
 
@@ -724,7 +606,7 @@ Common clarify keys:
724
606
  - `p` toggles progress tracking where supported
725
607
  Picker screens use `↑↓`, `Enter`, `Esc`, and type-to-filter. The full-screen editor supports word wrapping, paste, `Esc` to save, and `Ctrl+C` to discard.
726
608
 
727
- ## Agents and chains
609
+ ## Agents
728
610
 
729
611
  Agents are markdown files with YAML frontmatter and a system prompt body. They define the specialist that will run in the child Pi process.
730
612
 
@@ -846,7 +728,7 @@ Important fields:
846
728
  | Field | Notes |
847
729
  |-------|-------|
848
730
  | `package` | Optional package identifier. A file with `name: scout` and `package: code-analysis` registers as `code-analysis.scout`; serialization keeps `name` and `package` separate. |
849
- | `aliases` | Optional comma-separated or block-list names that resolve to this agent for selection and explicit `agent`/chain/task inputs. Runtime status, persistence, and config still use the canonical `name`; exact canonical names take precedence over aliases, and alias collisions between distinct canonical agents fail as ambiguous. |
731
+ | `aliases` | Optional comma-separated or block-list names that resolve to this agent for selection and explicit `agent` and task inputs. Runtime status, persistence, and config still use the canonical `name`; exact canonical names take precedence over aliases, and alias collisions between distinct canonical agents fail as ambiguous. |
850
732
  | `tools` | Strict child tool allowlist. Named extension tools must also have their provider loaded. `mcp:` entries select direct MCP tools when `pi-mcp-adapter` is installed. |
851
733
  | `extensions` | Omitted means normal extensions; empty means no extensions; list values allowlist specific extensions. |
852
734
  | `subagentOnlyExtensions` | Extension paths loaded only in spawned child sessions for this agent. Tools registered there are unavailable to the main agent unless also installed through normal Pi extension configuration. |
@@ -860,7 +742,7 @@ Important fields:
860
742
  | `skills` | Selects specific skills for the child, regardless of `inheritSkills`. |
861
743
  | `skillPath` | Invocation-private skill files or discovery directories. Relative paths resolve from the agent definition file. Local matches take precedence, while unresolved or unreadable matches fall back to normal skill discovery. This field discovers candidates only; `skills` still selects what the child receives. |
862
744
  | `output` | Default single-agent output file. |
863
- | `defaultReads` | Files to read before running in chain/parallel behavior. |
745
+ | `defaultReads` | Files to read before running the agent. |
864
746
  | `defaultProgress` | Maintain `progress.md`. |
865
747
  | `async` | Default a single-agent launch to background (`true`) or foreground (`false`) when the call omits `async`. Explicit call values and `forceTopLevelAsync` win. |
866
748
  | `timeoutMs` | Positive integer default runtime deadline in milliseconds for single-agent launches. Foreground launches use 30 minutes when neither the call nor agent provides a timeout; explicit `timeoutMs`/`maxRuntimeMs` and agent defaults win. |
@@ -868,7 +750,7 @@ Important fields:
868
750
  | `acceptance` | Acceptance default for single-agent launches. Use a scalar level such as `checked` or an inline/block YAML map such as `{ level: "none", reason: "lightweight lookup" }`. Explicit call values win; chain and parallel acceptance remains task/step configuration. |
869
751
  | `acceptanceRole` | Optional `read-only` or `writer` role for automatic acceptance inference. Explicit task mutation or no-edit intent wins; otherwise the declared role replaces agent-name guessing. This does not grant or revoke tools. |
870
752
  | `completionGuard` | Set `false` only for non-implementation agents that may mention implementation words while using mutation-capable tools such as `bash`. |
871
- | `interactive` | Parsed for compatibility but not enforced in v1. |
753
+ | `interactive` | Parsed for compatibility but not currently enforced. |
872
754
  | `maxSubagentDepth` | Tightens nested delegation for this agent's children. |
873
755
  | `memory` | Opt-in role-specific persistent memory. `memory: { scope: "project" \| "user", path: "<name>" }` injects the first lines of a `MEMORY.md` from a dedicated `agent-memory/` directory into the child system prompt. Agents with write tools (`edit`/`write`/`bash`) get a read-write block; read-only agents get a read-only fallback. Project scope resolves under `<project>/.pi/agent-memory/`, user scope under `~/.pi/agent/agent-memory/`. Paths are validated against traversal and symlink escape. |
874
756
 
@@ -922,114 +804,6 @@ To apply the same `extensions` allowlist to every agent that does not declare it
922
804
 
923
805
  Before the first model turn, the child runtime compares every explicit tool name with Pi's final filtered registry. A missing provider now fails the run with the unavailable names and concrete `subagentOnlyExtensions`/`extensions` guidance instead of letting a direct or chained child silently continue without its requested tools.
924
806
 
925
- ## Chain files
926
-
927
- Chains are reusable workflows stored separately from agent files. Use `.chain.md` for simple sequential saved chains. Use `.chain.json` when a chain needs dynamic fanout.
928
-
929
- | Scope | Path |
930
- |-------|------|
931
- | Installed package | `package.json` `pi-subagents.chains` or `pi.subagents.chains` |
932
- | User | `~/.pi/agent/chains/**/*.chain.md`, `~/.pi/agent/chains/**/*.chain.json` |
933
- | Project | Project config `chains/**/*.chain.md`, `chains/**/*.chain.json` (`.pi/chains/...` in standard Pi) |
934
-
935
- Nested subdirectories are discovered recursively. Installed Pi packages can expose chain directories from either `{"pi-subagents":{"chains":["./chains"]}}` or `{"pi":{"subagents":{"chains":["./chains"]}}}` in their package manifest. Package chains load below user/project chains. If both `.chain.md` and `.chain.json` define the same parsed runtime chain name in the same scope, `.chain.json` wins. If user and project scopes define the same parsed runtime chain name, the project chain wins. Chains support the same optional `package` frontmatter as agents; `name: review-flow` plus `package: code-analysis` runs as `code-analysis.review-flow`.
936
-
937
- Example:
938
-
939
- ```md
940
- ---
941
- name: scout-planner
942
- description: Gather context then plan implementation
943
- ---
944
-
945
- ## scout
946
- phase: Context
947
- label: Map auth flow
948
- as: context
949
- output: context.md
950
-
951
- Analyze the codebase for {task}
952
-
953
- ## planner
954
- phase: Planning
955
- label: Implementation plan
956
- reads: context.md
957
- model: anthropic/claude-sonnet-4-5:high
958
- progress: true
959
-
960
- Create an implementation plan based on {outputs.context}
961
- ```
962
-
963
- Each `.chain.md` `## agent-name` section is a step. Config lines such as `phase`, `label`, `as`, `outputSchema`, `output`, `outputMode`, `reads`, `model`, `skills`, and `progress` go immediately after the header. A blank line separates config from task text. In saved `.chain.md` files, `outputSchema` is a path to a JSON Schema file; direct tool calls and `.chain.json` files can pass the schema object inline.
964
-
965
- For `output`, `reads`, `skills`, and `progress`, chain behavior is three-state: omitted inherits from the agent, a value overrides, and `false` disables.
966
-
967
- Use `phase` to group related work in status output, `label` for a readable step name, and `as` to store a successful step or parallel task result for later `{outputs.name}` references. Duplicate `as` names, invalid identifiers, and unknown output references fail before child execution.
968
-
969
- Dynamic fanout is available only through direct `subagent({ chain: [...] })` JSON or saved `.chain.json` files. It expands an array from a prior structured named output, runs one child template per item, and stores the ordered collection under `collect.as`. The source must be structured output; prose is never parsed. `expand.maxItems` is required, over-limit arrays fail, nested fanout and arbitrary expressions are not supported, and `.chain.md` has no dynamic syntax in this release.
970
-
971
- ```json
972
- {
973
- "name": "dynamic-review",
974
- "description": "Find review targets, fan out reviewers, then synthesize.",
975
- "chain": [
976
- {
977
- "agent": "scout",
978
- "task": "Return {\"items\":[{\"path\":\"...\",\"reason\":\"...\"}]} via structured_output.",
979
- "as": "targets",
980
- "outputSchema": { "type": "object" }
981
- },
982
- {
983
- "expand": {
984
- "from": { "output": "targets", "path": "/items" },
985
- "item": "target",
986
- "key": "/path",
987
- "maxItems": 12
988
- },
989
- "parallel": {
990
- "agent": "reviewer",
991
- "label": "Review {target.path}",
992
- "task": "Review {target.path}. Reason: {target.reason}",
993
- "outputSchema": { "type": "object" }
994
- },
995
- "collect": { "as": "reviews" },
996
- "concurrency": 4
997
- },
998
- {
999
- "agent": "worker",
1000
- "task": "Synthesize fixes from {outputs.reviews}"
1001
- }
1002
- ]
1003
- }
1004
- ```
1005
-
1006
- Create simple `.chain.md` chains by writing files directly or with the `subagent({ action: "create", config: ... })` management action. Create dynamic `.chain.json` chains by writing the JSON file directly. Run saved chains with natural language or:
1007
-
1008
- ```text
1009
- /run-chain scout-planner -- refactor authentication
1010
- ```
1011
-
1012
- ## Chain variables
1013
-
1014
- Task templates support:
1015
-
1016
- | Variable | Description |
1017
- |----------|-------------|
1018
- | `{task}` | Original task from the first step. |
1019
- | `{previous}` | Output from the prior step, or aggregated output from a parallel step. |
1020
- | `{chain_dir}` | Path to the chain artifact directory. |
1021
- | `{outputs.name}` | Text value from a prior step or completed parallel task with `as: "name"`. |
1022
-
1023
- Parallel outputs are aggregated with clear separators before being passed to the next step:
1024
-
1025
- ```text
1026
- === Parallel Task 1 (worker) ===
1027
- ...
1028
-
1029
- === Parallel Task 2 (worker) ===
1030
- ...
1031
- ```
1032
-
1033
807
  ## Skills
1034
808
 
1035
809
  Skills are `SKILL.md` files made available to an agent. The prompt includes skill metadata and the file location; the agent reads the full skill file only when the task matches.
@@ -1119,11 +893,14 @@ if (!result.ok) {
1119
893
  console.log(result.contract.digest, result.contract.tools.effectiveAllowlist);
1120
894
  ```
1121
895
 
1122
- Preflight covers ordinary single-agent launch resolution under public contract version 2: selected agent identity and shadowed candidates, a versioned parsed-definition digest (including system prompt and launch-affecting model, tool, skill, extension, output, and memory fields), fresh/fork context, effective model and thinking, skill and tool resolution, direct MCP selections, runtime/configured extensions, artifact/session paths, async lifecycle/status/result/event/process-terminal paths, package/lifecycle versions, capability-ceiling audit data, and stable digests. `launchContractDigest` is the canonical digest of the caller task, effective system prompt (including the resolved `turnBudget` prompt augmentation when supplied), model candidates, effective tools/extensions/MCP (including inherited capability ceilings), output binding, and structured-output schema that ordinary foreground and async execution report in results/status/events and metadata. Runtime acceptance prose and output-task annotations are intentionally excluded because side-effect-free preflight does not resolve those host/runtime augmentations; the contract version and task digest make that boundary explicit. Raw prompts are not exposed in public contract output. It is side-effect-free for launch state: it does not create child sessions, temp prompt files, structured-output runtimes, tool-diagnostic files, or run artifacts. Some host-owned facts, such as exact fork snapshots, nested async roots, and live model registries, can only be proven by the Pi host; those appear as `host_required` diagnostics instead of silently pretending to be exact.
896
+ Preflight covers ordinary single-agent launch resolution: selected agent identity and shadowed candidates, a parsed-definition digest (including system prompt and launch-affecting model, tool, skill, extension, output, and memory fields), fresh/fork context, effective model and thinking, skill and tool resolution, direct MCP selections, runtime/configured extensions, artifact/session paths, async lifecycle/status/result/event/process-terminal paths, package/lifecycle versions, capability-ceiling audit data, and stable digests. `launchContractDigest` is the canonical digest of the caller task, effective system prompt (including the resolved `turnBudget` prompt augmentation when supplied), model candidates, effective tools/extensions/MCP (including inherited capability ceilings), output binding, and structured-output schema that ordinary foreground and async execution report in results/status/events and metadata. Runtime acceptance prose and output-task annotations are intentionally excluded because side-effect-free preflight does not resolve those host/runtime augmentations; the launch and task digests make that boundary explicit. Raw prompts are not exposed in public contract output. It is side-effect-free for launch state: it does not create child sessions, temp prompt files, structured-output runtimes, tool-diagnostic files, or run artifacts. Some host-owned facts, such as exact fork snapshots, nested async roots, and live model registries, can only be proven by the Pi host; those appear as `host_required` diagnostics instead of silently pretending to be exact.
1123
897
 
1124
- ### Delegation v1
898
+ ### Structured delegation API
1125
899
 
1126
- The compatibility v1 contract runs one configured foreground agent per request:
900
+ Other Pi extensions can ask `pi-subagents` to run one configured foreground leaf
901
+ agent through the structured delegation API. It uses the established
902
+ `prompt-template:subagent:*` event family and the same executor as the
903
+ `subagent` tool; it does not add another launcher.
1127
904
 
1128
905
  ```ts
1129
906
  import {
@@ -1134,51 +911,6 @@ import {
1134
911
  } from "pi-subagents/delegation";
1135
912
 
1136
913
  const request: SubagentDelegationRequest = {
1137
- version: 1,
1138
- requestId: crypto.randomUUID(),
1139
- agent: "reviewer",
1140
- task: "Review the supplied evidence.",
1141
- context: "fresh",
1142
- cwd: ctx.cwd,
1143
- timeoutMs: 120_000,
1144
- toolBudget: { soft: 10, hard: 16, block: "*" },
1145
- };
1146
-
1147
- const unsubscribe = pi.events.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => {
1148
- const response = payload as SubagentDelegationResponse;
1149
- if (response.requestId !== request.requestId) return;
1150
- unsubscribe();
1151
- // Inspect response.status and the metadata present for this run.
1152
- });
1153
- pi.events.emit(SUBAGENT_DELEGATION_REQUEST_EVENT, request);
1154
- ```
1155
-
1156
- The contract uses the established `prompt-template:subagent:*` event transport and the same executor as the `subagent` tool; it does not add another launcher. New integrations must send `version: 1`. Requests are strict and single-agent only. They can set fresh or fork context, model, cwd, timeout, turn and tool-call budgets, skills, output behavior, acceptance, and artifact capture. Unknown or malformed fields return `invalid_request` before execution.
1157
-
1158
- Responses distinguish completion, failure, timeout, cancellation, interruption,
1159
- turn or tool-budget exhaustion, explicit acceptance failure, invalid requests,
1160
- and unavailable active context. Optional metadata is omitted when unavailable.
1161
- Request IDs must be unique while active; duplicate active IDs are ignored so the
1162
- original request keeps ownership of its terminal response. Emit
1163
- `SUBAGENT_DELEGATION_CANCEL_EVENT` with the same version and request ID to cancel
1164
- queued or active work.
1165
-
1166
- ### Delegation v2
1167
-
1168
- V2 is the owned-leaf contract for workflow supervisors. Independent requests
1169
- can overlap through the delegated executor without weakening the ordinary
1170
- model-facing tool's one-foreground-call-per-turn guard.
1171
-
1172
- ```ts
1173
- import {
1174
- SUBAGENT_DELEGATION_REQUEST_EVENT,
1175
- SUBAGENT_DELEGATION_RESPONSE_EVENT,
1176
- type SubagentDelegationV2Request,
1177
- type SubagentDelegationV2Response,
1178
- } from "pi-subagents/delegation";
1179
-
1180
- const request: SubagentDelegationV2Request = {
1181
- version: 2,
1182
914
  requestId: crypto.randomUUID(),
1183
915
  ownerRunId: workflowRunId,
1184
916
  nodeId: "review-accuracy",
@@ -1199,8 +931,8 @@ const request: SubagentDelegationV2Request = {
1199
931
  };
1200
932
 
1201
933
  const unsubscribe = pi.events.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => {
1202
- const response = payload as SubagentDelegationV2Response;
1203
- if (response.version !== 2 || response.requestId !== request.requestId) return;
934
+ const response = payload as SubagentDelegationResponse;
935
+ if (response.requestId !== request.requestId) return;
1204
936
  if (response.ownerRunId !== request.ownerRunId || response.nodeId !== request.nodeId) return;
1205
937
  unsubscribe();
1206
938
  // Inspect response.status, response.result, response.usage, model, and thinking.
@@ -1221,22 +953,28 @@ Terminal usage reports input, output, cache-read, cache-write, cost, turns, tool
1221
953
  calls, and duration alongside the effective model and thinking level when
1222
954
  known. Schemas are capped at 64 KiB; tasks and returned text/structured values
1223
955
  are capped at 1 MiB, with smaller bounds on identity/configuration strings and
1224
- a maximum v2 `timeoutMs` of 2,147,483,647. V2 alone accepts
956
+ a maximum `timeoutMs` of 2,147,483,647. Structured delegation accepts
1225
957
  `toolBudget: { hard: 0, block: "*" }` to block the first tool call and run a
1226
- zero-tool leaf; delegation v1 and ordinary model-facing/configured budgets keep
1227
- their existing minimum of one. The foreground bridge retains up to 8,192 exact
1228
- pending-cancellation and settled-attempt identities per extension
1229
- context. If either history fills, it fails closed with `unavailable_context`
1230
- for later v2 starts rather than evicting identity facts; lifecycle reset clears
1231
- the bounded history.
1232
-
1233
- Delegation requires an active extension context. Emit requests from a supported event callback or queued application step, not by recursively invoking the `subagent` tool inside another tool's `tool_call` hook. The caller selects a configured agent, but agent discovery and effective tools remain package-owned. A request cannot grant arbitrary tools, and tool restrictions are not an operating-system sandbox. The detached RPC remains async-only; this API is foreground-only.
1234
-
1235
- Existing prompt-template payloads and delegation v1 continue over the same event
1236
- family. V2 remains foreground-only and inherits the configured agent's current
1237
- tools, skills, context, model policy, and workspace authority; it is not a
1238
- sandbox or a durable task broker. `pi-subagents/delegation` is the canonical
1239
- contract for extension integrations.
958
+ zero-tool leaf; ordinary model-facing/configured budgets keep their existing
959
+ minimum of one. The foreground bridge retains up to 8,192 exact
960
+ pending-cancellation and settled-attempt identities per extension context. If
961
+ either history fills, it fails closed with `unavailable_context` for later
962
+ starts rather than evicting identity facts; lifecycle reset clears the bounded
963
+ history.
964
+
965
+ Delegation requires an active extension context. Emit requests from a supported
966
+ event callback or queued application step, not by recursively invoking the
967
+ `subagent` tool inside another tool's `tool_call` hook. The caller selects a
968
+ configured agent, but agent discovery and effective tools remain package-owned.
969
+ A request cannot grant arbitrary tools, and tool restrictions are not an
970
+ operating-system sandbox. The detached RPC remains async-only; this API is
971
+ foreground-only.
972
+
973
+ Unversioned prompt-template payloads with `requestId`, `agent`, `task`,
974
+ `context`, `model`, and `cwd` are still accepted as a legacy bridge while we
975
+ validate whether any integrations still use them. New integrations should use
976
+ the structured owned-leaf request above. `pi-subagents/delegation` is the
977
+ canonical contract for extension integrations.
1240
978
 
1241
979
  ## Capability ceilings
1242
980
 
@@ -1264,7 +1002,7 @@ Active registrations intersect their `allowedTools` and `allowedAgents` sets and
1264
1002
 
1265
1003
  ## Background-work provider API
1266
1004
 
1267
- Other Pi extensions can make their current-session jobs visible to `subagent_wait` through the versioned process-local provider contract:
1005
+ Other Pi extensions can make their current-session jobs visible to `subagent_wait` through the process-local provider contract:
1268
1006
 
1269
1007
  ```ts
1270
1008
  import { registerBackgroundWorkProvider } from "pi-subagents/background-work";
@@ -1291,83 +1029,24 @@ These are the parameters the LLM passes when it calls the `subagent` tool. Most
1291
1029
 
1292
1030
  ### Execution examples
1293
1031
 
1294
- ```ts
1295
- // Single agent
1296
- { agent: "worker", task: "refactor auth" }
1297
- { agent: "scout", task: "find todos", maxOutput: { lines: 1000 } }
1298
- { agent: "scout", task: "investigate", output: false }
1299
- { agent: "scout", task: "write a large report", output: "reports/scout.md", outputMode: "file-only" }
1300
-
1301
- // Forked context
1302
- { agent: "worker", task: "continue this thread", context: "fork" }
1303
-
1304
- // Parallel
1305
- { tasks: [{ agent: "scout", task: "a" }, { agent: "reviewer", task: "b" }] }
1306
- { tasks: [{ agent: "scout", task: "audit auth", count: 3 }] }
1307
- { tasks: [{ agent: "scout", task: "audit frontend" }, { agent: "reviewer", task: "audit backend" }], context: "fork" }
1308
-
1309
- // Chain
1310
- { chain: [
1311
- { agent: "scout", task: "Gather context for auth refactor" },
1312
- { agent: "planner" },
1313
- { checkpoint: "implementation", message: "Approve implementation before review?" },
1314
- { agent: "worker" },
1315
- { agent: "reviewer" }
1316
- ]}
1317
-
1318
- // Chain in the background, suitable for unblocking the main chat
1319
- { chain: [...], async: true }
1320
-
1321
- // Chain with fan-out/fan-in
1322
- { chain: [
1323
- { agent: "scout", task: "Gather context", phase: "Context", label: "Map code", as: "context" },
1324
- { parallel: [
1325
- { agent: "worker", task: "Implement feature A from {outputs.context}", label: "Feature A", as: "featureA" },
1326
- { agent: "worker", task: "Implement feature B from {outputs.context}", label: "Feature B", as: "featureB" }
1327
- ], concurrency: 2, failFast: true },
1328
- { agent: "reviewer", task: "Review {outputs.featureA} and {outputs.featureB}" }
1329
- ]}
1330
-
1331
- // Dynamic fanout from structured output
1332
- { chain: [
1333
- {
1334
- agent: "scout",
1335
- task: "Return review targets as structured_output: { items: [{ path, reason }] }",
1336
- as: "targets",
1337
- outputSchema: { type: "object" }
1338
- },
1339
- {
1340
- expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 12 },
1341
- parallel: { agent: "reviewer", task: "Review {target.path}. Reason: {target.reason}", outputSchema: { type: "object" } },
1342
- collect: { as: "reviews" },
1343
- concurrency: 4
1344
- },
1345
- { agent: "worker", task: "Synthesize fixes from {outputs.reviews}" }
1346
- ] }
1347
-
1348
- // Strict structured output for reliable handoff data
1349
- { chain: [
1350
- {
1351
- agent: "scout",
1352
- task: "Return the key files and risks for {task}",
1353
- as: "scan",
1354
- outputSchema: {
1355
- type: "object",
1356
- required: ["files", "risks"],
1357
- properties: {
1358
- files: { type: "array", items: { type: "string" } },
1359
- risks: { type: "array", items: { type: "string" } }
1360
- }
1361
- }
1362
- },
1363
- { agent: "planner", task: "Plan from this scan: {outputs.scan}" }
1364
- ] }
1032
+ ```js
1033
+ // Single child
1034
+ { agent: "scout", task: "Analyze the auth flow", async: true }
1035
+
1036
+ // Sequential workflow
1037
+ { workflowScript: `
1038
+ const scan = await runs.run("scan", { agent: "scout", task: "Analyze auth" });
1039
+ return (await runs.run("plan", { agent: "planner", task: "Plan from: " + scan.output })).output;
1040
+ ` }
1365
1041
 
1366
- // Worktree isolation
1367
- { tasks: [
1368
- { agent: "worker", task: "Implement auth" },
1369
- { agent: "worker", task: "Implement API" }
1370
- ], worktree: true }
1042
+ // Parallel workflow
1043
+ { workflowScript: `
1044
+ const results = await runs.all([
1045
+ { key: "backend", agent: "reviewer", task: "Review backend" },
1046
+ { key: "frontend", agent: "reviewer", task: "Review frontend" }
1047
+ ]);
1048
+ return results.map(result => result.output);
1049
+ ` }
1371
1050
  ```
1372
1051
 
1373
1052
  ### Management actions
@@ -1439,26 +1118,26 @@ Agent definitions are not loaded into context by default. Management actions let
1439
1118
  |-------|------|---------|-------------|
1440
1119
  | `agent` | string | - | Agent name or alias for single mode, or target for management actions. Execution records use the canonical agent name. |
1441
1120
  | `task` | string | - | Task string for single mode. |
1442
- | `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `interrupt`, `stop`, `resume`, `steer`, `append-step`, `approve-checkpoint`, `reject-checkpoint`, or `doctor`. |
1121
+ | `action` | string | - | Agent, mission (`mission.create/list/show/update/attach-run/close`), Herdr inspector (`inspector.open/status/close`), status/control, schedule, watchdog, or doctor action. |
1443
1122
  | `chainName` | string | - | Chain name for management actions. |
1444
- | `config` | object/string | - | Agent or chain config for create/update. |
1123
+ | `config` | object/string | - | Agent or existing durable chain config for management create/update. |
1445
1124
  | `output` | `string \| false` | agent default | Override single-agent output file. |
1446
1125
  | `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
1447
1126
  | `skill` | `string \| string[] \| false` | agent default | Override skills or disable all. |
1448
1127
  | `model` | string | agent default | Override model. |
1449
1128
  | `outputSchema` | object | - | Require schema-valid structured output for a direct single-agent run. |
1450
- | `agentContract` | `{ version: 1 }` | - | Opt into generic agent contract v1. Omit to keep the current/default contract. |
1451
- | `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `outputSchema`, `reads`, `progress`, `skill`, `model`, `toolBudget`, `acceptance`, and `agentContract`. |
1452
- | `concurrency` | number | config or `4` | Top-level parallel concurrency. |
1453
- | `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
1454
- | `chain` | array | - | Sequential, checkpoint, static parallel, and dynamic fanout chain steps. Steps and chain parallel tasks support `phase`, `label`, `as`, `outputSchema`, `acceptance`, `agentContract`, and v1-only `gateOn` in addition to the usual execution fields. Dynamic fanout uses `expand`, one child `parallel` template, and `collect`. With `action: "append-step"`, pass exactly one step to append to a running async chain. |
1129
+ | `agentContract` | `{ version: 1 }` | - | Enable the compatibility behavior for this run. Omit for the default behavior. |
1455
1130
  | `context` | `fresh \| fork` | per-agent default or `fresh` | Explicit `fresh` or `fork` overrides every child. When omitted, each agent uses its own `defaultContext`; `fork` creates real branched sessions from the parent leaf. Packaged `planner`, `worker`, `oracle`, and `advisor` default to `fork`. |
1456
- | `chainDir` | string | temp chain dir | Persistent directory for chain artifacts. Relative chain `output`, `reads`, and `progress` paths live under this directory. |
1131
+ | `missionId` | string | - | Attach a single-agent or workflow launch to an existing project mission. |
1132
+ | `mission` | object/false | - | Create-and-attach shortcut: `{ title, goal?, labels? }`; pass `false` for an intentionally ephemeral launch with no mission record. Explicit mission persistence failures are strict. |
1133
+ | `handoffPath` | string | - | Aggregate handoff manifest required by `action: "worktree.discard"`. |
1134
+ | `focus` | boolean | true | Focus the newly split pane for `action: "inspector.open"`; not a standalone action. |
1457
1135
  | `view` | `fleet \| transcript` | - | Optional `status` view for the active fleet surface or transcript tail inspection. |
1458
1136
  | `lines` | number | `80` | Maximum transcript lines for `action: "status", view: "transcript"`; capped at 500. |
1459
1137
  | `clarify` | boolean | false | Show TUI preview/edit flow. Explicit `clarify: true` keeps the run foreground for the clarify UI. |
1460
1138
  | `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
1461
- | `async` | boolean | false | Background execution. For chains, `clarify: true` explicitly keeps the run foreground for the clarify UI. |
1139
+ | `async` | boolean | default-on | Background execution. Scripted workflows always default to background and accept `async:false` as an explicit foreground escape hatch. `clarify:true` applies only to single-agent execution; workflowScript does not open clarify UI. |
1140
+ | `chatProgress` | `auto \| off \| terminal \| milestones \| 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; background and other-repo workflows stay compact. Explicit `live-card` requires `async:false` and the same Git repository. |
1462
1141
  | `timeoutMs` / `maxRuntimeMs` | number | 30 min foreground; none async | Optional run-level max runtime in milliseconds. Foreground uses 30 minutes only when neither the call nor selected agent provides a timeout. |
1463
1142
  | `turnBudget` | object | none | Optional assistant-turn budget `{ maxTurns, graceTurns }`. At `maxTurns` the child is warned to wrap up. After the grace window (default 1), termination occurs at the next assistant boundary; a response that starts tool work records `termination-deferred` until a later boundary. Partial output is returned on abort. |
1464
1143
  | `toolBudget` | object | none | Optional child tool-call budget `{ soft?, hard, block? }`. At `soft` the child is nudged to finalize. After `hard`, configured tools are blocked; `block` defaults to `read`, `grep`, `find`, and `ls`, while `"*"` blocks every tool call. Final assistant text is never blocked. |
@@ -1471,19 +1150,13 @@ Agent definitions are not loaded into context by default. Management actions let
1471
1150
  | `sessionDir` | string | derived | Override session log directory. |
1472
1151
  | `acceptance` | string/object/false | inferred | Configure evidence gates with `"auto"`, `"attested"`, `"checked"`, `"verified"`, or `{ level: "none", reason: "..." }`. Independent review is orthogonal: use `review: { required: true, agent?: "reviewer", focus?: "..." }`. `review-required` means evidence passed but review is pending; `reviewed` is achieved only after a real independent result. Explicit `"reviewed"` remains schema-recognized solely for actionable preflight recovery. For reviewer/read-only calls, omit acceptance. `false` disables gates. With `agentContract: { version: 1 }`, omitted, `"auto"`, and `false` mean no acceptance request for that run; explicit acceptance is reported separately from execution. |
1473
1152
 
1474
- `agentContract: { version: 1 }` keeps existing fields and artifacts but adds derived `execution`, `acceptance`, `review`, and `effects` projections. In v1, acceptance failures do not rewrite execution success, and an explicit completion guard reports `effects.fileMutation` instead of failing the run by itself. Chain steps default to advancing on execution under v1; set `gateOn: "acceptance"` on a v1 step or parallel task when rejected acceptance should stop the chain.
1475
-
1476
- Checkpoint steps use `{ checkpoint: "stable-name", message?: "..." }`. A checkpoint does not launch a child, consume spawn budget, or produce an output reference. Foreground chains return a paused result at the checkpoint so the current parent can explicitly choose the next action. Async chains persist `checkpoint` in status/details and pause before the next step; approve with `subagent({ action: "approve-checkpoint", id: "<run-id>" })` or reject with `subagent({ action: "reject-checkpoint", id: "<run-id>" })`. Approval resumes from that boundary without rerunning completed steps. Rejection is terminal with `state: "rejected"`.
1477
-
1478
1153
  As a conservative orchestration policy, do not set `turnBudget`, a hard `toolBudget`, or a tight `usageBudget` on implementation workers, fix workers, reviewers with edit authority, or other mutation-capable children. A default tool budget blocks read/search tools rather than mutation tools, and reported usage has no reservation model, so neither assistant turns, tool-call counts, nor token/cost totals measure whether a delivery slice is buildable or safe to hand off. Hard caps remain appropriate for explicitly read-only scouts, reviewers, and validators.
1479
1154
 
1480
1155
  Bound writer work with a narrow task and an outer `timeoutMs` or `maxRuntimeMs` that leaves enough margin for the slice. An elapsed timeout is not a mutation-safe boundary and may still signal a child during tool work. Before the deadline, use `steer` or an attention notice to request a checkpoint after the current tool returns, including changed files, build/test state, remaining work, and commit or PR state.
1481
1156
 
1482
- `context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. When the inherited transcript contains signed Anthropic `thinking` / `redacted_thinking` blocks, `pi-subagents` strips those provider-private blocks from the forked child session. It forces thinking `off` only when the child’s effective primary or fallback model resolves through the model registry to the Anthropic provider or `anthropic-messages` API; unresolved models are treated conservatively. The result reports every affected child, including on failed runs. Use `context: "fresh"` when an Anthropic child needs thinking. Forking never silently downgrades to `fresh`. In multi-agent runs that omit `context`, each agent/task/step follows its own `defaultContext`, so a fresh-default scout can run fresh beside a fork-default worker. Pass explicit `context: "fork"` or `context: "fresh"` when you intentionally want one context for every child.
1157
+ `context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. When the inherited transcript contains signed Anthropic `thinking` / `redacted_thinking` blocks, `pi-subagents` strips those provider-private blocks from the forked child session. It forces thinking `off` only when the child’s effective primary or fallback model resolves through the model registry to the Anthropic provider or `anthropic-messages` API; unresolved models are treated conservatively. The result reports every affected child, including on failed runs. Use `context: "fresh"` when an Anthropic child needs thinking. Forking never silently downgrades to `fresh`. In workflow runs that omit `context`, each `runs.run` child follows its own `defaultContext`, so a fresh-default scout can run fresh beside a fork-default worker. Pass explicit `context: "fork"` or `context: "fresh"` when you intentionally want one context for every child.
1483
1158
 
1484
- 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. In chains, relative `output` paths are resolved inside the chain artifact directory, not the caller's CWD; later `{previous}` steps receive the same compact reference when the prior step used file-only mode. To persist chain outputs outside the temp artifact area, pass a persistent `chainDir` or use an absolute `output` path. 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.
1485
-
1486
- Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, `model`, `toolBudget`, `acceptance`, `agentContract`, and v1-only `gateOn`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`. If `outputSchema` is present, the child must call `structured_output` with schema-valid JSON; prose-only completion or invalid JSON fails the step. Validated structured values are preserved on the step result, and `as` also exposes a compact text representation through `{outputs.name}`.
1159
+ 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. 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.
1487
1160
 
1488
1161
  Status and control actions:
1489
1162
 
@@ -1501,7 +1174,7 @@ subagent({ action: "resume", id: "<run-id>", index: 1, message: "follow-up for c
1501
1174
  subagent({ action: "resume", id: "<nested-run-id>", message: "follow-up for a nested child" })
1502
1175
  subagent({ action: "steer", id: "<run-id>", message: "guidance for the running child" })
1503
1176
  subagent({ action: "steer", id: "<run-id>", index: 1, message: "guidance for child 2" })
1504
- subagent({ action: "append-step", id: "<run-id>", chain: [{ agent: "worker", task: "Continue from {previous}" }] })
1177
+ subagent({ action: "append-step", id: "<run-id>", step: { agent: "worker", task: "Continue from {previous}" } })
1505
1178
  subagent({ action: "approve-checkpoint", id: "<run-id>" })
1506
1179
  subagent({ action: "reject-checkpoint", id: "<run-id>" })
1507
1180
  subagent({ action: "doctor" })
@@ -1511,45 +1184,53 @@ subagent({ action: "doctor" })
1511
1184
 
1512
1185
  `resume` revives a paused, completed, or failed async/foreground child by starting a new child from its stored session file; stopped runs remain non-resumable, and it does not interrupt a live top-level async child. Use `steer` for acknowledged live async guidance. Multi-child async runs and remembered foreground single, parallel, or chain runs can be revived by passing `index` to choose the child. Nested runs can be resumed by nested id when their live route or persisted nested session metadata is available. Revive starts a new child process from the old session context; it does not restart the same OS process, and it requires the chosen child to have a persisted `.jsonl` session file. Direct revival takes an exclusive cross-process lease on the canonical session file until the new child finishes. A concurrent attempt fails before Pi is spawned and identifies the owning revived run; dead-owner leases are reclaimed only when staleness can be proved.
1513
1186
 
1514
- `stop` ends a current-session top-level async run. It is deliberately stronger than `interrupt`: it is not a resumable pause, stopped runs should be restarted as new runs, foreground and nested targets are rejected, direct id calls execute immediately, and `/subagents-stop` without an id opens a selector with confirmation when a TUI is available. Use `↑`/`↓` or `j`/`k` to move through that selector. In non-TUI contexts the slash command prints exact `subagent({ action: "stop", id })` and `/subagents-stop <id>` commands. Scheduled jobs can appear in the selector, but they are labeled as scheduled cancellations and route through `schedule-cancel`, not `stop`.
1187
+ `stop` ends a current-session top-level async run. It is deliberately stronger than `interrupt`: it is not a resumable pause, stopped runs should be restarted as new runs, foreground and nested targets are rejected, direct id calls execute immediately, and `/subagents-stop` without an id opens a selector with confirmation when a TUI is available. Use `↑`/`↓` or `j`/`k` to move through that selector. In non-TUI contexts the slash command prints exact `subagent({ action: "stop", id })` and `/subagents-stop <id>` commands. Inactive schedules can appear in the selector, but they are labeled as schedules and route through `schedule.pause`, not `stop`.
1515
1188
 
1516
- `steer` waits up to three seconds for a correlated child-Pi input acceptance and returns a request id with `delivered`, `scheduled`, `pending`, `partial`, `recovered`, or `failed` plus per-child states. Delivery means Pi accepted the user message, not model compliance. A pending indexed child returns `scheduled`. Only a top-level single run may interrupt after the acknowledgment deadline and recover after a further 15-second pause/revival bound; chain, parallel, and nested runs never auto-interrupt. Recovery launches a replacement only after the source is confirmed paused, a valid persisted session exists, and deadline, turn, and tool budgets remain. It preserves the original child contract and remaining limits; otherwise the source stays paused with an explicit failure. Late acceptance is recorded but cannot cancel committed recovery. The persisted `steering` ledger retains 20 requests and replaces the old `steerCount`/`lastSteerAt` fields.
1189
+ `steer` waits up to three seconds for a correlated child-Pi input acceptance and returns a request id with `delivered`, `scheduled`, `pending`, `partial`, `recovered`, or `failed` plus per-child states. Delivery means Pi accepted the user message, not model compliance. A pending indexed child returns `scheduled`. Only a top-level single run may interrupt after the acknowledgment deadline and recover after a further 15-second pause/revival bound; durable multi-child and nested runs never auto-interrupt. Recovery launches a replacement only after the source is confirmed paused, a valid persisted session exists, and deadline, turn, and tool budgets remain. It preserves the original child contract and remaining limits; otherwise the source stays paused with an explicit failure. Late acceptance is recorded but cannot cancel committed recovery. The persisted `steering` ledger retains 20 requests and replaces the old `steerCount`/`lastSteerAt` fields.
1517
1190
 
1518
- `append-step` accepts exactly one sequential, checkpoint, static parallel, or dynamic fanout chain step for a top-level async chain whose status is still `running`. The step is persisted in the run directory and becomes eligible only after the chain's already-queued steps finish; completed, failed, rejected, paused, foreground, single, and top-level parallel runs reject appends.
1191
+ `append-step` accepts exactly one `step` object for an existing durable chain for a top-level async chain whose status is still `running`. The step is persisted in the run directory and becomes eligible only after the chain's already-queued steps finish; completed, failed, rejected, paused, foreground, single, and non-chain runs reject appends.
1519
1192
 
1520
- ## Worktree isolation
1193
+ ## Durable missions
1521
1194
 
1522
- Parallel agents can clobber each other if they edit the same checkout. `worktree: true` gives each parallel child its own git worktree branched from `HEAD`.
1195
+ Missions are durable wrappers around runs. The noun map is:
1196
+
1197
+ - **Project/codebase** — where work happens.
1198
+ - **Mission** — why delegated work exists and how to recover it later.
1199
+ - **Run** — one actual subagent execution.
1200
+ - **Receipt** — proof or a link for an external outcome, such as a PR, CI check, deployment, or release.
1201
+
1202
+ Ordinary task launches create a mission by default, with detailed JSON records under `<cwd>/.pi-subagents/missions/` linking goals, run ids, lifecycle status, decisions, artifact paths, and delivery receipts. Automatic persistence failures do not block the run and are reported as `details.missionWarning`; explicit `missionId` and `mission` requests remain strict before launch. Human receipts end with `Mission: <id> (<status>)`, while JSON/structured output text stays unchanged and `details.missionId` is authoritative. Pass `mission: false` for an intentionally ephemeral launch that should not leave a durable mission record. Set `missions.enabled: false` to disable automatic mission creation; explicit mission fields and actions still work.
1523
1203
 
1524
1204
  ```ts
1525
- { tasks: [
1526
- { agent: "worker", task: "Implement auth", count: 2 },
1527
- { agent: "worker", task: "Implement API" }
1528
- ], worktree: true }
1205
+ const created = subagent({
1206
+ action: "mission.create",
1207
+ mission: { title: "Ship auth refresh", goal: "Implement and validate token refresh" }
1208
+ })
1209
+ subagent({ agent: "worker", task: "Implement the approved auth refresh plan", missionId: "<mission-id>" })
1529
1210
 
1530
- { chain: [
1531
- { agent: "scout", task: "Gather context" },
1532
- { parallel: [
1533
- { agent: "worker", task: "Implement feature A from {previous}" },
1534
- { agent: "worker", task: "Implement feature B from {previous}" }
1535
- ], worktree: true },
1536
- { agent: "reviewer", task: "Review all changes from {previous}" }
1537
- ]}
1211
+ // Or create and attach in one launch
1212
+ subagent({ agent: "worker", task: "Implement the approved plan", mission: { title: "Ship auth refresh" } })
1538
1213
  ```
1539
1214
 
1540
- Requirements:
1215
+ Use `mission.list`, `mission.show`, `mission.update`, `mission.attach-run`, and `mission.close` for management. Use `mission.update` to record decisions, artifacts, labels, summaries, and delivery receipts while work runs; receipts are durable links for pull requests, CI, deployments, or releases, each with `kind`, `status`, `title`, `url`, and optional `description`. They record delivery state only; pi-subagents does not merge, poll CI, or deploy. Use `mission.close` with a terminal status and summary when a mission is done. After compaction or restart, resume from `mission.list`/`mission.show` first: `mission.show` refreshes linked async status where available, then use the linked run ids with normal `status`, `steer`, `resume`, or `stop` actions. `mission.list` with `missionScope: "global"` reads the user-local pointer index under the Pi agent directory; project records remain the source of truth, and missing records are reported as stale rather than hiding other projects.
1541
1216
 
1542
- - run inside a git repo
1543
- - working tree must be clean
1544
- - `node_modules/` is symlinked into each worktree when present
1545
- - task-level `cwd` overrides must be omitted or match the shared cwd
1546
- - configured `worktreeSetupHook` must return valid JSON before timeout
1217
+ For cross-project work, keep same-project tasks on ordinary subagents. Use an explicit `cwd` for small bounded work in another project. For substantial or long-running work in another project, open a project-owned Herdr pane with `project.open` and give that project Pi session a narrow mission/result contract. The project pane owns its own subagents; do not model it as ordinary child nesting or expect existing headless runs to move into the pane.
1547
1218
 
1548
- Git worktrees start from tracked files, so ignored dependency state may be absent. `pi-subagents` attempts the `node_modules` symlink above, but if module resolution fails in a fresh worktree, first confirm dependencies were linked, installed, or provisioned by `worktreeSetupHook` before treating it as a code failure.
1219
+ ## Worktree isolation
1549
1220
 
1550
- By default, worktrees are created under the system temp directory. Set `worktreeBaseDir` in config, or `PI_SUBAGENTS_WORKTREE_DIR` when config is unset, to put them under a stable trusted directory. Missing base directories are created automatically.
1221
+ Scripted workflows can give each writing child a separate managed git worktree by setting `worktree: true` on each `runs.run` / `runs.all` item:
1551
1222
 
1552
- After a worktree parallel step completes, per-agent diff stats are appended to the output and full patch files are written to artifacts. The runtime also writes a versioned aggregate handoff manifest: foreground runs use the artifact directory's `handoffs/<run-id>.json`, while async runs use `<async-dir>/handoff.json`. The manifest records each child's terminal status, summary, output/session/structured-output references, patch stats and path, and whether its worktree and temporary branch were actually removed. Foreground `details`, async `status.json` and result files, status output, intercom delivery, and completion notifications expose the manifest path. Worktrees and temp branches still receive best-effort fallback cleanup if handoff finalization cannot run.
1223
+ ```javascript
1224
+ const [api, ui] = await runs.all([
1225
+ { key: "api", agent: "worker", task: "Implement the API", worktree: true },
1226
+ { key: "ui", agent: "worker", task: "Implement the UI", worktree: true }
1227
+ ]);
1228
+ return { api: api.artifactPaths, ui: ui.artifactPaths };
1229
+ ```
1230
+
1231
+ Each child uses the existing worktree lifecycle: it branches from clean HEAD, journals ownership before launch, captures a patch and handoff manifest, then removes cleanly captured temporary worktrees and branches. The handoff manifest path remains available in the child's `artifactPaths`; return or emit it when the orchestrator needs to apply or inspect the patches. `runs.ref` stays concise and intentionally omits full paths.
1232
+
1233
+ A top-level `{ workflowScript, worktree: true }` makes isolation the default for every workflow child. An individual child can override that default with `worktree: false`. Keep one writer when parallel writes are not intentionally isolated.
1553
1234
 
1554
1235
  ## Configuration
1555
1236
 
@@ -1565,13 +1246,21 @@ Controls the parent-facing `subagent` tool description registered at startup. `f
1565
1246
 
1566
1247
  `custom` reads `subagent-tool-description.md` from the project config directory, then from `~/.pi/agent/subagent-tool-description.md`. Missing, empty, unreadable, or oversized custom files fall back to the full description. Custom templates may use `{{fullDescription}}`, `{{compactDescription}}`, `{{safetyGuidance}}`, `{{agentDir}}`, and `{{projectConfigDir}}`; the safety guidance is always present so custom prose cannot remove the runtime guardrails. Restart Pi after changing the mode or custom file.
1567
1248
 
1249
+ ### `inlineToolDisplay`
1250
+
1251
+ ```json
1252
+ { "inlineToolDisplay": "summary" }
1253
+ ```
1254
+
1255
+ Controls the `subagent` tool result shown inline in chat. The default, `"rich"`, shows live child activity and expands to detailed output. `"summary"` keeps the inline result at one stable row for running, completed, failed, stopped, and paused runs; it does not animate, show elapsed time, preview child output, or change when Pi's expand key is pressed. FleetView remains available for live progress and detailed inspection.
1256
+
1568
1257
  ### `asyncByDefault`
1569
1258
 
1570
1259
  ```json
1571
- { "asyncByDefault": true }
1260
+ { "asyncByDefault": false }
1572
1261
  ```
1573
1262
 
1574
- Makes top-level calls use background execution when the request does not explicitly set `async`. Callers can still force foreground with `async: false` unless `forceTopLevelAsync` is enabled.
1263
+ Ordinary top-level calls use background execution when the request omits `async`. Set `asyncByDefault` to `false` to restore foreground-by-default behavior. Callers can still force foreground with `async: false` unless `forceTopLevelAsync` is enabled; `clarify: true` remains foreground for its UI.
1575
1264
 
1576
1265
  ### `fleetView`
1577
1266
 
@@ -1595,7 +1284,7 @@ Places the persistent FleetView either `"belowEditor"` or `"aboveEditor"`. The d
1595
1284
  { "asyncWidget": true }
1596
1285
  ```
1597
1286
 
1598
- Controls the legacy above-editor widget for background runs. It defaults to `false` while FleetView is enabled and `true` when FleetView is disabled. Set it explicitly to show both surfaces or hide the legacy widget entirely.
1287
+ Controls the under-editor widget for active background runs. It defaults to `true`, including when FleetView is enabled, so active work remains visible after reload. Set it to `false` to hide this widget while keeping FleetView available.
1599
1288
 
1600
1289
  ### `waitTool`
1601
1290
 
@@ -1605,6 +1294,8 @@ Controls the legacy above-editor widget for background runs. It defaults to `fal
1605
1294
 
1606
1295
  Keeps the `subagent_wait` tool registered but makes direct calls return immediately instead of blocking on active subagent or provider work. The default is enabled. You can also set `"waitTool": false`; set `PI_SUBAGENT_WAIT_TOOL_ENABLED=false` (or `0`, `off`, `disabled`) to override config for one process. The effective value is passed explicitly to child runtimes. Headless `agent_end` auto-drain remains a lifecycle safeguard even when direct wait calls are disabled. Invalid config or environment values fail instead of being coerced.
1607
1296
 
1297
+ Blocking `subagent_wait({ id: "..." })` keeps the current tool call open until that run changes. In a long-lived interactive parent session, `subagent_wait({ id: "...", nonBlocking: true })` instead resolves the prefix once, persists the exact run identity, returns a subscription token immediately, and wakes that session on completion, failure, attention, reconciliation failure, or timeout. Armed subscriptions appear in ordinary `subagent({ action: "status" })` output and are not counted as active child work. This is different from `waitTool.enabled=false`, which returns immediately without registering any future wake. Provider items remain available only to blocking fleet-wide waits; non-blocking subscriptions require one async or remembered detached foreground run id.
1298
+
1608
1299
  ### `forceTopLevelAsync`
1609
1300
 
1610
1301
  ```json
@@ -1619,7 +1310,7 @@ Forces depth-0 single, parallel, and chain runs into background mode and bypasse
1619
1310
  { "globalConcurrencyLimit": 20 }
1620
1311
  ```
1621
1312
 
1622
- Caps simultaneously running subagent tasks within a single run across top-level parallel tasks, inline chain parallel groups, and dynamic fanout groups. The default is `20`; invalid values are clamped to `1`. Per-step `concurrency` and `parallel.concurrency` still apply, so effective concurrency is the lower of the local cap and the available global slots.
1313
+ Caps simultaneously running children inside existing durable legacy multi-child runs. New orchestration uses `workflowScript` and `runs.all`.
1623
1314
 
1624
1315
  ### `maxSubagentSpawnsPerSession`
1625
1316
 
@@ -1636,10 +1327,12 @@ A user may explicitly call `subagent({ action: "grant-spawn-budget", additional:
1636
1327
  ### `scheduledRuns`
1637
1328
 
1638
1329
  ```json
1639
- { "scheduledRuns": { "enabled": true, "maxPending": 20, "maxLatenessMs": 300000 } }
1330
+ { "scheduledRuns": { "enabled": false, "maxPending": 20 } }
1640
1331
  ```
1641
1332
 
1642
- Enables optional one-shot scheduled subagent runs. When enabled, `subagent({ action: "schedule", agent, task?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? })` defers a subagent launch until a future time. Absolute ISO timestamps must include a timezone (`Z` or an offset such as `+05:30`). The scheduled run launches as a normal tracked async run with fresh context once it fires, and joins the existing async widget, status, `subagent_wait`, and completion-notification paths. `schedule-list`, `schedule-status`, and `schedule-cancel` manage pending jobs. Schedules are persisted per session and restored after a Pi restart; a job missed by more than `maxLatenessMs` while Pi is unavailable is marked `missed` instead of firing late. `maxPending` caps the number of pending or running scheduled jobs per session (default `20`). The feature is opt-in: leave `enabled` unset to keep scheduling out of the tool surface and prompt. Only schedule explicit delayed runs the user asked for.
1333
+ Durable schedules are enabled by default and stored per project under `.pi-subagents/schedules/<id>/`. Create a one-shot schedule with `subagent({ action: "schedule.create", id: "evening-review", name: "Evening review", at: "+30m", agent: "reviewer", task: "Review the current diff." })`. Create a fixed recurring workflow with `subagent({ action: "schedule.create", id: "backlog", every: "6h", catchUp: "latest", workflowScript: "..." })`. Fixed intervals support `m`, `h`, `d`, and `w` units and advance from the planned time without completion drift.
1334
+
1335
+ Manage schedules with `schedule.list`, `schedule.show`, `schedule.history`, `schedule.pause`, `schedule.resume`, `schedule.run`, `schedule.run-due`, and `schedule.delete`. Runs always launch async with fresh context and disable automatic mission creation; mission attachment is deferred from this first slice. Definitions, bounded history, append-only events, and per-run receipts are stored with mode `0600`. `overlap` is currently fixed to `skip`; `catchUp` supports `latest` (default) and `none`. `schedule.run-due` lets an external launcher start due project work without making `pi-subagents` a daemon. Calendar recurrence, cron, queue/replace overlap, and the schedule TUI inspector are intentionally deferred to the next slice. The old `schedule`, `schedule-list`, `schedule-status`, and `schedule-cancel` actions were removed in this hard cutover.
1643
1336
 
1644
1337
  ### `parallel`
1645
1338
 
@@ -1704,7 +1397,7 @@ Fields:
1704
1397
 
1705
1398
  - `mode`: default `always`; use `fork-only` to inject only for forked runs, or `off` to disable the bridge.
1706
1399
  - `instructionFile`: optional Markdown template replacing the default bridge instructions. `{orchestratorTarget}` is interpolated. Relative paths resolve from `~/.pi/agent/extensions/subagent/`.
1707
- - `resultDelivery`: default `true`; attempts acknowledged grouped completion delivery through an external `subagent:result-intercom` listener. Set `false` when native parent notifications own completion delivery. Supervisor asks/progress remain active, and genuine enabled-transport acknowledgement failures remain visible.
1400
+ - `resultDelivery`: default `false`; set `true` only when an external `subagent:result-intercom` listener is installed. Enabled delivery waits for acknowledgement and reports acknowledgement failures. Supervisor asks/progress remain active.
1708
1401
 
1709
1402
  Bridge activation requires a targetable current parent session id, which `pi-subagents` passes to children automatically. It no longer depends on an external `pi-intercom` installation or per-agent extension allowlists.
1710
1403
 
@@ -1737,6 +1430,38 @@ stdin is a JSON object with `repoRoot`, `worktreePath`, `agentCwd`, `branch`, `i
1737
1430
 
1738
1431
  `syntheticPaths` must be relative to the worktree root. They are removed before diff capture so helper files do not pollute patches. Tracked files are never excluded; marking a tracked path as synthetic fails setup. Default timeout is `30000` ms.
1739
1432
 
1433
+ ### `missions`
1434
+
1435
+ ```json
1436
+ {
1437
+ "missions": {
1438
+ "enabled": true,
1439
+ "directory": ".pi-subagents/missions",
1440
+ "globalIndex": true,
1441
+ "retainTerminal": 200
1442
+ }
1443
+ }
1444
+ ```
1445
+
1446
+ Automatic missions are enabled by default for ordinary launches with a task. Use per-launch `mission: false` for intentionally ephemeral work, or set `enabled: false` to disable automatic creation globally; explicit mission actions and `missionId`/`mission` launch fields still work. `directory` may be absolute, `~/...`, or project-relative. `retainTerminal` is a positive count (default `200`); pruning removes only the oldest completed, failed, or cancelled records and their pointers, never planned, active, waiting, needs-decision, or corrupt records. The user-global index contains pointers only; missing-record pointers self-heal when globally listed. Set `globalIndex: false` to disable writes or `globalIndexDir` to redirect it.
1447
+
1448
+ ### `authorityPolicy`
1449
+
1450
+ ```json
1451
+ {
1452
+ "authorityPolicy": {
1453
+ "discardWorktree": "confirm",
1454
+ "destructiveCleanup": "confirm",
1455
+ "spawnBudgetGrant": "confirm",
1456
+ "scheduleCreate": "auto",
1457
+ "stopRun": "auto",
1458
+ "steerRun": "auto"
1459
+ }
1460
+ }
1461
+ ```
1462
+
1463
+ Each fixed action resolves to `"auto"`, `"confirm"`, or `"forbid"`. This is intentionally a small action map, not a generic policy language. Confirm-required control actions fail closed without an interactive UI.
1464
+
1740
1465
  ### `artifactDir`
1741
1466
 
1742
1467
  ```json
@@ -1747,7 +1472,9 @@ stdin is a JSON object with `repoRoot`, `worktreePath`, `agentCwd`, `branch`, `i
1747
1472
 
1748
1473
  Controls where subagent artifact files (inputs, outputs, transcripts, metadata) are stored. Defaults to `"project"`, which writes to `<cwd>/.pi-subagents/artifacts/`. Set to `"session"` to store artifacts under pi's session directory (`~/.pi/agent/sessions/<session>/subagent-artifacts/`), keeping the working directory clean. Set to `"temp"` to use the OS temp directory.
1749
1474
 
1750
- The `"session"` option uses the same directory that `cleanupAllArtifactDirs` already scans for age-based cleanup, so artifacts are still cleaned up automatically.
1475
+ This preference also controls the default chain scratch directory. `"project"` uses `<cwd>/.pi-subagents/chain-runs/`, while `"session"` and `"temp"` use the user-scoped temp chain directory.
1476
+
1477
+ The `"session"` option uses the same directory that `cleanupAllArtifactDirs` already scans for age-based cleanup, so artifacts are still cleaned up automatically. Temporary chain directories are cleaned up separately after 24 hours.
1751
1478
 
1752
1479
  ### `completionBatch`
1753
1480
 
@@ -1764,19 +1491,19 @@ The `"session"` option uses the same directory that `cleanupAllArtifactDirs` alr
1764
1491
  }
1765
1492
  ```
1766
1493
 
1767
- Controls smart batching of async-completion notifications. When several background subagents finish within a short window, their successful completions are held briefly and delivered as a single grouped message instead of separate notifications. A hard `maxWaitMs` cap (measured from the first completion in a group) guarantees nothing is held indefinitely, and late-finishing siblings that arrive within `stragglerWindowMs` of a group emit join a shorter straggler group governed by `stragglerDebounceMs` and `stragglerMaxWaitMs`.
1494
+ Controls smart batching of async-completion notifications. When several background subagents finish within a short window, their successful completions are held briefly and delivered as a single quiet grouped completion instead of separate completions. A hard `maxWaitMs` cap (measured from the first completion in a group) guarantees nothing is held indefinitely, and late-finishing siblings that arrive within `stragglerWindowMs` of a group emit join a shorter straggler group governed by `stragglerDebounceMs` and `stragglerMaxWaitMs`.
1768
1495
 
1769
1496
  Failed and paused completions bypass batching and fire immediately, flushing any held successes first, so failure and needs-attention signals are never delayed. Set `enabled` to `false` to restore the original one-notification-per-completion behavior. Changes apply on the next session start.
1770
1497
 
1771
1498
  ## Files, logs, and observability
1772
1499
 
1773
- Each chain run creates a user-scoped temp directory like:
1500
+ Each chain run creates a scratch directory under its resolved chain root. With the default `artifactDir: "project"`, that root is `<cwd>/.pi-subagents/chain-runs/`. With `artifactDir: "session"` or `"temp"`, it is user-scoped temp storage:
1774
1501
 
1775
1502
  ```text
1776
1503
  <tmpdir>/pi-subagents-<scope>/chain-runs/{runId}/
1777
1504
  ```
1778
1505
 
1779
- It may contain files such as `context.md`, `plan.md`, `progress.md`, and `parallel-{stepIndex}/.../output.md`. Directories older than 24 hours are cleaned up on extension startup.
1506
+ A run directory may contain files such as `context.md`, `plan.md`, `progress.md`, and `parallel-{stepIndex}/.../output.md`. User-scoped temp chain directories older than 24 hours are cleaned up on extension startup; project-local and explicit persistent roots are not age-scanned.
1780
1507
 
1781
1508
  Debug artifacts live under `{sessionDir}/subagent-artifacts/`, `.pi-subagents/artifacts/` for project-scoped runs, or a user-scoped temp artifact directory. Single-run relative `output` files are saved under `{artifactsDir}/outputs/{runId}/` unless `singleRunOutputBaseDir` is configured. Per task you may see:
1782
1509
 
@@ -1789,7 +1516,7 @@ Metadata records timing, usage, exit code, final model, attempted models, fallba
1789
1516
 
1790
1517
  Session files are stored under a per-run session directory. With `context: "fork"`, each child starts with `--session <branched-session-file>` produced from the parent’s current leaf. That is a real session fork, not an injected summary.
1791
1518
 
1792
- Async completions notify only the originating session. The result watcher emits `subagent:async-complete`, and the extension consumes that event to render completion notifications. Successful sibling completions are held briefly and delivered as a single grouped message when they finish within a short window (see `completionBatch`); failed and paused completions always fire immediately.
1519
+ Async completions belong only to the originating session. The result watcher emits `subagent:async-complete`, and the extension consumes that event to record completion state. Successful sibling completions are held briefly and delivered as a quiet grouped completion when they finish within a short window (see `completionBatch`), avoiding unread markers on inactive tabs. Failed and paused completions remain visible and fire immediately.
1793
1520
 
1794
1521
  Async runs write:
1795
1522
 
@@ -1914,15 +1641,9 @@ Then run it through the native adapter:
1914
1641
  /prompt-workflow take-screenshot https://example.com
1915
1642
  ```
1916
1643
 
1917
- The adapter delegates to the named subagent, applies `model`, `skill`, `cwd`, `worktree`, and fork/fresh context metadata, and supports runtime overrides such as `--subagent reviewer`, `--fork`, `--fresh`, `--worktree`, and `--bg`.
1918
-
1919
- For prompt-template chains, use:
1920
-
1921
- ```text
1922
- /chain-prompts analyze -> fix -- user arguments here
1923
- ```
1644
+ The adapter delegates to the named subagent, applies `model`, `skill`, `cwd`, and fork/fresh context metadata, and supports runtime overrides such as `--subagent reviewer`, `--fork`, `--fresh`, and `--bg`.
1924
1645
 
1925
- Each named prompt becomes a native `subagent` chain step. This is intentionally scoped to subagent workflows; compare-style prompt features such as `/best-of-n` are not part of the built-in adapter.
1646
+ Prompt templates with `chain:` frontmatter are translated into `workflowScript` and launched through `/prompt-workflow`; `/chain-prompts` is no longer registered.
1926
1647
 
1927
1648
  ## Runtime files
1928
1649