pi-subagents 0.34.0 → 0.35.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 (98) hide show
  1. package/CHANGELOG.md +78 -9
  2. package/README.md +213 -32
  3. package/index.ts +1 -0
  4. package/install.mjs +1 -1
  5. package/package.json +23 -8
  6. package/prompts/review-loop.md +3 -1
  7. package/skills/pi-subagents/SKILL.md +87 -25
  8. package/src/agents/agent-management.ts +82 -15
  9. package/src/agents/agent-serializer.ts +19 -0
  10. package/src/agents/agents.ts +91 -49
  11. package/src/agents/frontmatter.ts +67 -13
  12. package/src/agents/skills.ts +25 -12
  13. package/src/api/background-work.ts +197 -0
  14. package/src/api/delegation.ts +158 -0
  15. package/src/extension/chain-validation.ts +165 -0
  16. package/src/extension/doctor.ts +15 -0
  17. package/src/extension/fanout-child.ts +3 -1
  18. package/src/extension/index.ts +65 -124
  19. package/src/extension/rpc.ts +10 -2
  20. package/src/extension/schemas.ts +18 -14
  21. package/src/extension/steering-notices.ts +35 -0
  22. package/src/extension/tool-description.ts +20 -9
  23. package/src/intercom/intercom-bridge.ts +3 -2
  24. package/src/intercom/native-supervisor-channel.ts +9 -1
  25. package/src/intercom/result-intercom.ts +4 -0
  26. package/src/runs/background/async-execution.ts +293 -44
  27. package/src/runs/background/async-job-tracker.ts +56 -9
  28. package/src/runs/background/async-resume.ts +159 -52
  29. package/src/runs/background/async-status.ts +25 -18
  30. package/src/runs/background/auto-drain.ts +67 -0
  31. package/src/runs/background/chain-root-attachment.ts +16 -8
  32. package/src/runs/background/control-channel.ts +260 -13
  33. package/src/runs/background/fleet-view.ts +23 -2
  34. package/src/runs/background/notify.ts +79 -10
  35. package/src/runs/background/result-watcher.ts +12 -9
  36. package/src/runs/background/run-id-resolver.ts +14 -2
  37. package/src/runs/background/run-status.ts +23 -15
  38. package/src/runs/background/scheduled-runs.ts +3 -0
  39. package/src/runs/background/stale-run-reconciler.ts +32 -10
  40. package/src/runs/background/steering.ts +237 -0
  41. package/src/runs/background/subagent-runner.ts +898 -236
  42. package/src/runs/background/subagent-wait.ts +484 -0
  43. package/src/runs/background/top-level-async.ts +2 -1
  44. package/src/runs/background/wait-config.ts +36 -0
  45. package/src/runs/background/wait-tool.ts +26 -0
  46. package/src/runs/foreground/async-steering-action.ts +230 -0
  47. package/src/runs/foreground/chain-clarify.ts +22 -6
  48. package/src/runs/foreground/chain-execution.ts +50 -32
  49. package/src/runs/foreground/execution.ts +308 -94
  50. package/src/runs/foreground/subagent-executor.ts +592 -268
  51. package/src/runs/shared/acceptance.ts +355 -97
  52. package/src/runs/shared/child-protocol.ts +121 -0
  53. package/src/runs/shared/completion-guard.ts +8 -127
  54. package/src/runs/shared/dynamic-fanout.ts +6 -4
  55. package/src/runs/shared/model-fallback.ts +36 -0
  56. package/src/runs/shared/nested-events.ts +9 -4
  57. package/src/runs/shared/nested-render.ts +4 -1
  58. package/src/runs/shared/parallel-utils.ts +7 -0
  59. package/src/runs/shared/pi-args.ts +34 -7
  60. package/src/runs/shared/pi-spawn.ts +18 -12
  61. package/src/runs/shared/session-lease.ts +279 -0
  62. package/src/runs/shared/single-output.ts +61 -6
  63. package/src/runs/shared/spawn-budget.ts +128 -0
  64. package/src/runs/shared/subagent-control.ts +10 -6
  65. package/src/runs/shared/subagent-prompt-runtime.ts +127 -26
  66. package/src/runs/shared/task-intent.ts +176 -0
  67. package/src/runs/shared/tool-availability.ts +65 -0
  68. package/src/runs/shared/turn-budget.ts +49 -4
  69. package/src/shared/atomic-json.ts +4 -1
  70. package/src/shared/fork-context.ts +28 -3
  71. package/src/shared/model-info.ts +7 -4
  72. package/src/shared/status-format.ts +7 -1
  73. package/src/shared/types.ts +203 -25
  74. package/src/shared/utils.ts +35 -7
  75. package/src/slash/delegation-adapters.ts +457 -0
  76. package/src/slash/delegation-request.ts +103 -0
  77. package/src/slash/prompt-template-bridge.ts +167 -344
  78. package/src/slash/slash-commands.ts +239 -6
  79. package/src/slash/subagents-admin.ts +428 -0
  80. package/src/slash/subagents-editor.ts +86 -0
  81. package/src/tui/fleet.ts +405 -0
  82. package/src/tui/render.ts +90 -16
  83. package/src/watchdog/change-signature.ts +127 -0
  84. package/src/watchdog/child-status.ts +205 -0
  85. package/src/watchdog/emission-guard.ts +123 -0
  86. package/src/watchdog/lsp-diagnostics.ts +532 -0
  87. package/src/watchdog/model-selection.ts +167 -0
  88. package/src/watchdog/register-child.ts +117 -0
  89. package/src/watchdog/register-main.ts +433 -0
  90. package/src/watchdog/render.ts +54 -0
  91. package/src/watchdog/review.ts +293 -0
  92. package/src/watchdog/runtime.ts +712 -0
  93. package/src/watchdog/settings.ts +528 -0
  94. package/src/watchdog/tool-actions.ts +155 -0
  95. package/src/watchdog/turn-delta.ts +161 -0
  96. package/src/watchdog/types.ts +188 -0
  97. package/src/watchdog/warning-format.ts +73 -0
  98. package/src/runs/background/wait.ts +0 -394
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Pi extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
+ "exports": {
9
+ ".": "./index.ts",
10
+ "./background-work": "./src/api/background-work.ts",
11
+ "./delegation": "./src/api/delegation.ts"
12
+ },
8
13
  "repository": {
9
14
  "type": "git",
10
15
  "url": "git+https://github.com/nicobailon/pi-subagents.git"
@@ -26,6 +31,7 @@
26
31
  "pi-subagents": "install.mjs"
27
32
  },
28
33
  "files": [
34
+ "index.ts",
29
35
  "src/**/*.ts",
30
36
  "*.mjs",
31
37
  "agents/",
@@ -43,7 +49,7 @@
43
49
  },
44
50
  "pi": {
45
51
  "extensions": [
46
- "./src/extension/index.ts"
52
+ "./index.ts"
47
53
  ],
48
54
  "skills": [
49
55
  "./skills"
@@ -55,7 +61,9 @@
55
61
  "peerDependencies": {
56
62
  "@earendil-works/pi-agent-core": "*",
57
63
  "@earendil-works/pi-ai": "*",
58
- "@earendil-works/pi-coding-agent": "*"
64
+ "@earendil-works/pi-coding-agent": "*",
65
+ "@earendil-works/pi-tui": "*",
66
+ "typebox": "*"
59
67
  },
60
68
  "peerDependenciesMeta": {
61
69
  "@earendil-works/pi-agent-core": {
@@ -66,16 +74,23 @@
66
74
  },
67
75
  "@earendil-works/pi-coding-agent": {
68
76
  "optional": true
77
+ },
78
+ "@earendil-works/pi-tui": {
79
+ "optional": true
80
+ },
81
+ "typebox": {
82
+ "optional": true
69
83
  }
70
84
  },
71
85
  "dependencies": {
72
- "@earendil-works/pi-tui": "0.74.0",
73
86
  "jiti": "2.7.0",
74
- "typebox": "1.1.24"
87
+ "yaml": "2.8.3"
75
88
  },
76
89
  "devDependencies": {
77
- "@earendil-works/pi-agent-core": "0.74.0",
78
- "@earendil-works/pi-ai": "0.74.0",
79
- "@earendil-works/pi-coding-agent": "0.74.0"
90
+ "@earendil-works/pi-agent-core": "0.80.10",
91
+ "@earendil-works/pi-ai": "0.80.10",
92
+ "@earendil-works/pi-coding-agent": "0.80.10",
93
+ "@earendil-works/pi-tui": "0.80.10",
94
+ "typebox": "1.1.38"
80
95
  }
81
96
  }
@@ -10,6 +10,8 @@ Default to a maximum of 3 review rounds unless I specify a different cap. Count
10
10
 
11
11
  If the invocation includes an implementation request, first launch one async `worker` to implement the approved scope. If the current diff is already the target, start with review. The sequence can be launched up front as an async/background chain when the workflow is already clear, or continued as follow-up subagent runs after each async completion. For an initial chain, pass `async: true` so the main chat is unblocked; do not set `clarify: true` unless I explicitly want the foreground clarify UI. Use only one writer against the active worktree at a time unless I explicitly ask for isolated worktrees.
12
12
 
13
+ As a conservative orchestration policy, do not set `turnBudget` or a hard `toolBudget` on implementation or fix workers. A default tool budget blocks read/search tools rather than mutation tools, but count limits still do not measure delivery safety. Give each writer a narrow delivery slice and an outer elapsed deadline with enough margin. Before that deadline, request a checkpoint after the current tool returns with changed files, build/test state, remaining work, and commit or PR state. An elapsed timeout is not a mutation-safe boundary and must not be the checkpoint trigger.
14
+
13
15
  For each review round, launch fresh-context `reviewer` agents in parallel. Reviewers must inspect the repository, relevant instructions, and current diff directly from files and commands. They must not rely on the main conversation history and must not edit files.
14
16
 
15
17
  Choose review angles from the actual change. Common angles are correctness/regressions, tests/validation, and simplicity/maintainability. Add security, performance, docs/API contracts, or user-flow validation when the work calls for it. Prefer three strong reviewers over many vague reviewers.
@@ -24,7 +26,7 @@ Do not blindly apply every reviewer suggestion. If reviewers surface an unapprov
24
26
 
25
27
  When an async implementation worker completes, treat its handoff as the transition into review, not as final completion, unless I explicitly asked for worker-only work, review-only output, or to stop after implementation.
26
28
 
27
- When there are fixes worth doing now and the workflow is implementation-authorized, launch one async forked `worker` to apply only those synthesized fixes. Ask it to preserve the approved scope, run focused validation, and report changed files, commands run with exit codes, validation evidence, surprises, and anything left undone.
29
+ When there are fixes worth doing now and the workflow is implementation-authorized, launch one async forked `worker` without hard turn or tool-call caps to apply only those synthesized fixes. Ask it to preserve the approved scope, run focused validation, and report changed files, commands run with exit codes, validation evidence, surprises, and anything left undone.
28
30
 
29
31
  After a fix worker returns, run another review round only when it made material changes or addressed non-trivial findings. Do not keep looping for optional polish, speculative improvements, or findings already deferred by the parent.
30
32
 
@@ -16,12 +16,13 @@ Use this skill when the parent orchestrator needs to launch a specialized subage
16
16
 
17
17
  ## When to Use
18
18
 
19
+ - **Complex work orchestration**: use Fable mode as the default parent-agent loop for complex work. Complex means the task has multiple moving parts, unclear acceptance, cross-cutting code, meaningful user-visible impact, expensive or irreversible validation, broad review surface, or the user asks for orchestration. Lightweight one-off delegation can stay lightweight.
19
20
  - **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or fork to `oracle` when inherited decisions and drift matter
20
21
  - **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
21
22
  - **Recon and planning**: use `scout` or `context-builder`, then `planner`
22
23
  - **Parallel exploration**: run multiple non-conflicting tasks concurrently
23
24
  - **Regular skill specialists**: when discovery shows proactive skill subagent suggestions and the current work is broad enough, launch a small fresh-context fanout that asks one subagent per relevant regularly used skill to apply that skill's perspective to the task
24
- - **Long-running work**: launch async/background runs and inspect them later; use `timeoutMs` or `maxRuntimeMs` when a foreground or async run needs a hard max runtime, `turnBudget: { maxTurns, graceTurns }` for a soft assistant-turn budget, or `toolBudget: { soft?, hard, block? }` to nudge after a tool-call threshold and then block read/search tools so the child can finalize
25
+ - **Long-running work**: launch async/background runs and inspect them later. For mutation-capable work, bound the delivery slice and elapsed runtime, then request checkpoints after active tool work returns. Reserve hard turn and tool-call caps for explicitly read-only children.
25
26
  - **Subagent control**: watch needs-attention signals and soft-interrupt only when a delegated run is genuinely blocked
26
27
  - **Agent authoring**: create, update, or override agents and chains for a project
27
28
 
@@ -34,7 +35,12 @@ Humans often use the slash-command layer instead:
34
35
  - `/chain` — launch a chain of steps
35
36
  - `/parallel` — launch top-level parallel tasks
36
37
  - `/run-chain` — launch a saved `.chain.md` or `.chain.json` workflow
38
+ - `/subagent-cost` — show parent plus child token usage and cost for the session
39
+ - `/subagents-fleet` — open the live, inspection-only foreground/async fleet; `Ctrl+Alt+F` opens it during an active foreground turn, `↑↓`/`jk` selects children, and `PgUp`/`PgDn` scrolls transcript detail
37
40
  - `/subagents-doctor` — diagnose setup, discovery, async paths, and intercom bridge state
41
+ - `/subagents-models [agent]` — show the live runtime-loaded builtin model mapping
42
+ - `/subagents-profiles`, `/subagents-load-profile`, `/subagents-refresh-provider-models`, `/subagents-generate-profiles`, `/subagents-check-profile` — manage model profiles and provider catalogs
43
+ - `/prompt-workflow` and `/chain-prompts` — run prompt templates through native subagent single/chain workflows
38
44
 
39
45
  Prefer the tool when you are writing agent logic. Prefer the slash commands when
40
46
  you are guiding a human through an interactive flow.
@@ -84,6 +90,8 @@ subagent({
84
90
 
85
91
  Use this when the user wants implementation or current diff review to continue until reviewers stop finding fixes worth doing now. Keep the loop in the parent session: one async `worker` implements or fixes, fresh-context `reviewer` agents inspect the actual repo and diff, the parent synthesizes accepted fixes, and one async forked `worker` applies them. The parent can express the sequence up front as an async/background chain when the workflow is known, or continue with explicit follow-up subagent runs after each async completion. For an initial chain, pass `async: true` so the main chat is unblocked; do not set `clarify: true` unless the user explicitly wants the foreground clarify UI. Treat an async implementation worker handoff as an intermediate state, not final completion, unless the user explicitly asked for worker-only work, review-only output, or to stop after implementation. Stop when reviewers find no blockers or fixes worth doing now, remaining feedback is optional or deferred, an unapproved product/scope/architecture decision appears, or the max review-round cap is reached. Default to 3 review rounds unless the user sets a different cap. Do not loop for optional polish, and do not let children launch subagents or decide the loop outcome.
86
92
 
93
+ As a conservative orchestration policy, do not pass `turnBudget` or a hard `toolBudget` to an implementation worker, fix worker, reviewer with edit authority, or other mutation-capable child. The default tool budget blocks read/search tools rather than mutation tools, but count limits still do not measure delivery safety. Use a narrow task plus an outer elapsed deadline with enough margin, then request a checkpoint after the current tool returns. The checkpoint should report changed files, build/test state, remaining work, and commit or PR state. An elapsed timeout is not a mutation-safe boundary and must not be used as the checkpoint trigger.
94
+
87
95
  ### Parallel research technique
88
96
 
89
97
  Use this when the question needs both external evidence and local implications. Combine `researcher` for official docs, specs, ecosystem behavior, recent changes, benchmarks, and primary sources with `scout` for repository files, patterns, constraints, tests, and likely integration points. Give each child a distinct angle: external evidence, local code context, and practical tradeoffs. Ask for source links or file ranges, confidence level, gaps, and decision implications. Do not ask these children to edit unless implementation was explicitly requested.
@@ -184,7 +192,7 @@ and user/project agents override builtins with the same name.
184
192
  | `delegate` | Lightweight generic delegate | inherits default | No fixed output; generic delegated work |
185
193
  | `oracle` | Decision-consistency advisory review | inherits default | Advisory review, intercom coordination |
186
194
 
187
- Builtin agents inherit the current Pi default model unless a run, user setting, or project setting overrides `model`. Override builtin defaults before copying full agent files when a small tweak is enough.
195
+ Builtin agents inherit the current Pi default model unless a run, user setting, project setting, or `subagents.defaultModel` overrides `model`. Set `subagents.defaultModel` when subagents should use a different default model than the parent session. Override builtin defaults before copying full agent files when a small tweak is enough.
188
196
 
189
197
  For one run, use inline config:
190
198
 
@@ -192,9 +200,11 @@ For one run, use inline config:
192
200
  /run reviewer[model=anthropic/claude-sonnet-4] "Review this diff"
193
201
  ```
194
202
 
195
- For persistent tweaks, edit `subagents.agentOverrides` in user or project settings. User overrides apply everywhere. Project overrides apply only in that repo and win over user overrides.
203
+ For persistent tweaks, edit `subagents.agentOverrides` in user or project settings. User overrides apply everywhere. Project overrides apply only in that repo and win over user overrides. Use `/subagents-models` or `subagent({ action: "models" })` to inspect the live mapping after settings and overrides load.
204
+
205
+ Model ids do not have to be exact. Separator variations (`claude-haiku-4.5` vs `claude-haiku-4-5`), case (`Claude-Sonnet-4`), and optional trailing date stamps (`claude-haiku-4-5-20251001`) all resolve to the same registry model. Exact `provider/id` wins; a qualified `provider/model` never switches providers. To constrain subagents to a budget or compliance profile, set `subagents.modelScope: { enforce: true, allow: ["anthropic/*", "openai/gpt-5-*"] }` in user or project settings. Out-of-scope models you pass explicitly error and abort; models inherited from frontmatter, `subagents.defaultModel`, agent frontmatter, or the parent session only warn.
196
206
 
197
- Model ids do not have to be exact. Separator variations (`claude-haiku-4.5` vs `claude-haiku-4-5`), case (`Claude-Sonnet-4`), and optional trailing date stamps (`claude-haiku-4-5-20251001`) all resolve to the same registry model. Exact `provider/id` wins; a qualified `provider/model` never switches providers. To constrain subagents to a budget or compliance profile, set `subagents.modelScope: { enforce: true, allow: ["anthropic/*", "openai/gpt-5-*"] }` in user or project settings. Out-of-scope models you pass explicitly error and abort; models inherited from frontmatter, `defaultModel`, or the parent session only warn.
207
+ For model fleets, use the profile commands instead of hand-editing repeated overrides: `/subagents-refresh-provider-models <provider>`, `/subagents-generate-profiles <provider>`, `/subagents-load-profile <name>`, and `/subagents-check-profile <name>`. Profiles live under `~/.pi/agent/profiles/pi-subagents/` and replace only `settings.subagents` when loaded.
198
208
 
199
209
  ## Prompting role subagents
200
210
 
@@ -226,7 +236,8 @@ Direct settings example:
226
236
  "reviewer": {
227
237
  "model": "anthropic/claude-sonnet-4",
228
238
  "thinking": "high",
229
- "fallbackModels": ["openai/gpt-5-mini"]
239
+ "fallbackModels": ["openai/gpt-5-mini"],
240
+ "acceptanceRole": "read-only"
230
241
  }
231
242
  }
232
243
  }
@@ -235,7 +246,8 @@ Direct settings example:
235
246
 
236
247
  Useful override fields: `model`, `fallbackModels`, `thinking`,
237
248
  `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`,
238
- `disabled`, `skills`, `tools`, and `systemPrompt`. Create a user or project
249
+ `acceptanceRole`, `disabled`, `skills`, `tools`, and `systemPrompt`. Use
250
+ `acceptanceRole: false` to clear an override. Create a user or project
239
251
  agent with the same name only when you want a substantially different agent.
240
252
 
241
253
  If a provider rejects model IDs with thinking suffixes, use
@@ -243,7 +255,7 @@ If a provider rejects model IDs with thinking suffixes, use
243
255
  builtin thinking defaults globally. A higher-precedence per-agent `thinking`
244
256
  override can opt one builtin back in.
245
257
 
246
- Tool description modes live in `~/.pi/agent/extensions/subagent/config.json`, not `subagents` settings. Set `toolDescriptionMode` to `compact` to reduce tool-description prompt cost while keeping the execution, async/wait, child-safety, one-writer, management/action, and artifact/status guardrails. Set it to `custom` to read `subagent-tool-description.md` from the project config dir or agent dir; invalid custom files fall back to full mode and the safety guidance is still appended.
258
+ Tool description modes live in `~/.pi/agent/extensions/subagent/config.json`, not `subagents` settings. Set `toolDescriptionMode` to `compact` to reduce tool-description prompt cost while keeping the execution, async/`subagent_wait`, child-safety, one-writer, management/action, and artifact/status guardrails. Set it to `custom` to read `subagent-tool-description.md` from the project config dir or agent dir; invalid custom files fall back to full mode and the safety guidance is still appended.
247
259
 
248
260
  ## Discovery and Scope Rules
249
261
 
@@ -312,7 +324,7 @@ subagent({
312
324
  })
313
325
  ```
314
326
 
315
- Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. When a task is review-only, say “do not modify project/source files” rather than “do not write files” if you also configured `output`; otherwise the child may treat the output artifact as forbidden. Failed runs and save errors still return inline details for debugging.
327
+ Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. Read-only children return the complete artifact in their final response and the runtime persists it, so missing write tools are not a supervisor blocker. Mutation-capable children still receive direct-write instructions. Failed runs and save errors still return inline details for debugging.
316
328
 
317
329
  ### Chain execution
318
330
 
@@ -342,9 +354,9 @@ Async does not mean parallel writes. Do not edit the same active worktree while
342
354
 
343
355
  Do not end your turn immediately after launching an async child if you promised to keep working. Continue the local inspection, synthesis, or validation prep, then check the async run when its result is needed.
344
356
 
345
- When there is no independent work left and you just need the next async result, **call `wait()`** rather than `sleep`/status-polling loops. `wait()` returns when the next active run finishes or needs attention and keeps the turn alive for normal notification delivery. Use `wait({ all: true })` to drain every active run, `wait({ id: "..." })` to block on one run, and `wait({ timeoutMs })` to cap how long you block.
357
+ In an interactive chat, normally return control when ready to yield and let Pi wake the session on completion; do not call `subagent_wait()` merely to wait. Override that default and call it 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 background work finishes. Headless sessions auto-drain exact current-session work at `agent_end`; call `subagent_wait()` when this turn must receive results before it ends. Never substitute sleep or status-polling loops.
346
358
 
347
- Prefer `wait()` over ending the turn whenever you must keep going to finish the job — inside a skill that has to run to completion, or in any non-interactive run (`pi -p ...`) where the whole task is a single turn. In those cases ending the turn abandons the still-running children, because there is no next turn to receive their completion. Only end the turn to wait when you are in an interactive session and are certain the user will prompt you again; then Pi will wake you when the run finishes.
359
+ `subagent_wait()` returns when the next initially active async 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. If a foreground child detaches for supervisor coordination, reply first, then wait on its id; do not resume or launch a replacement while it remains detached. Headless sessions also auto-drain exact current-session work at `agent_end` as a final safeguard.
348
360
 
349
361
  ```typescript
350
362
  subagent({
@@ -370,21 +382,25 @@ const run = subagent({
370
382
 
371
383
  Inspect async runs with `subagent({ action: "status", id: "..." })` or `subagent({ action: "status" })` for active runs. Use `subagent({ action: "status", view: "fleet" })` when supervising several active foreground/background runs and `subagent({ action: "status", id: "...", view: "transcript", index: 0 })` when you need the latest child output without digging through artifacts. If a delegated fanout child launches nested runs, the parent status view shows them as a tree and you can target a nested run directly with its nested id.
372
384
 
373
- Use `resume` for follow-up work after a delegated run:
385
+ Use `steer` for top-level live async guidance and `resume` after a delegated run pauses or finishes. Routed nested runs retain their existing non-destructive live follow-up path:
374
386
 
375
387
  ```typescript
388
+ subagent({ action: "steer", id: "run-id", message: "Focus on the failing test." })
376
389
  subagent({ action: "resume", id: "run-id", message: "Follow up on this point." })
377
390
  subagent({ action: "resume", id: "run-id", index: 1, message: "Continue reviewer 2." })
378
391
  subagent({ action: "resume", id: "nested-run-id", message: "Continue this nested reviewer." })
379
392
  ```
380
393
 
381
394
  Resume behavior:
382
- - If an async child is still running and reachable, `resume` sends the follow-up to that live child over intercom.
395
+ - `resume` revives paused, completed, or failed async/foreground children from persisted session files; stopped runs remain non-resumable, and it does not interrupt live top-level async children.
396
+ - Use `steer` for acknowledged guidance to a live top-level async child.
397
+ - A live nested run can still receive a non-destructive `resume` follow-up through its owner route.
383
398
  - If an async child has completed, `resume` revives it by starting a new async child from the persisted child session file.
384
399
  - Multi-child async runs require `index` unless only one running child is selectable.
385
400
  - Completed foreground single, parallel, and chain runs can also be revived by `index` while their run metadata remains in extension state.
386
401
  - Nested runs can be resumed by nested id when a live route or persisted nested session metadata is available.
387
402
  - Revive starts a new child process from the old session context; it does not restart the same OS process.
403
+ - Direct revival holds an exclusive cross-process lease on the canonical child session file until the new child finishes. Concurrent attempts fail before Pi starts and identify the owning revived run; stale ownership is reclaimed only when the recorded process is demonstrably gone or reused.
388
404
  - If the chosen child has no persisted `.jsonl` session file, resume fails and reports that directly.
389
405
 
390
406
  Use diagnostics when setup or child startup looks wrong:
@@ -410,7 +426,7 @@ subagent({ action: "schedule-status", id: "ab12" })
410
426
  subagent({ action: "schedule-cancel", id: "ab12" })
411
427
  ```
412
428
 
413
- `schedule` accepts the same execution fields as a normal async run (`agent`/`tasks`/`chain`, `cwd`, `model`, `output`, `reads`, `progress`, `acceptance`, `timeoutMs`) plus `schedule` (a relative delay like `+10m`/`+2h`/`+1d` or a future ISO timestamp with a timezone such as `2030-01-01T09:00:00Z`) and an optional `scheduleName`. Scheduled runs always launch async with fresh context; `context: "fork"`, `async: false`, and `clarify: true` are rejected. Once the timer fires, the run becomes a normal tracked async run: it appears in the async widget, is inspectable with `subagent({ action: "status" })`, can be awaited with `wait()`, and delivers the normal completion notification.
429
+ `schedule` accepts the same execution fields as a normal async run (`agent`/`tasks`/`chain`, `cwd`, `model`, `output`, `reads`, `progress`, `acceptance`, `timeoutMs`) plus `schedule` (a relative delay like `+10m`/`+2h`/`+1d` or a future ISO timestamp with a timezone such as `2030-01-01T09:00:00Z`) and an optional `scheduleName`. Scheduled runs always launch async with fresh context; `context: "fork"`, `async: false`, and `clarify: true` are rejected. Once the timer fires, the run becomes a normal tracked async run: it appears in the async widget, is inspectable with `subagent({ action: "status" })`, can be awaited with `subagent_wait()`, and delivers the normal completion notification.
414
430
 
415
431
  Schedules are persisted per session and restored after a Pi restart. A job whose scheduled time passed by more than `scheduledRuns.maxLatenessMs` (default 5 minutes) while Pi was unavailable is marked `missed` instead of firing late. `scheduledRuns.maxPending` (default 20) caps pending or running scheduled jobs per session.
416
432
 
@@ -452,6 +468,14 @@ subagent({
452
468
 
453
469
  If the run already has an active intercom bridge target, needs-attention notifications can also prepare a compact intercom ping for the orchestrator. When a child route is available, the ping tells the orchestrator which agent needs attention and includes the exact `intercom({ action: "send", to: "..." })` target for a nudge. Do not invent a target or ask the child to self-report when no bridge exists.
454
470
 
471
+ Steering is acknowledged delivery, not a send attempt or model-compliance signal:
472
+
473
+ ```typescript
474
+ subagent({ action: "steer", id: "abc123", message: "Focus on the failing test." })
475
+ ```
476
+
477
+ The action waits up to three seconds for the child Pi session to accept the correlated user input and returns a request id with `delivered`, `scheduled`, `pending`, `partial`, `recovered`, or `failed` plus per-child states. Indexed pending children return `scheduled` immediately. Only a top-level single-child run may automatically interrupt after a missed acknowledgment and recover after confirmed pause within a further 15 seconds. Recovery preserves the original child contract and only its remaining deadline, turn, and tool budgets. If the session is missing, a budget is exhausted, the pause cannot be confirmed, or replacement launch fails, the source remains paused when pausing succeeded and the action returns the exact failure. Chain, parallel, and nested runs never auto-interrupt; inspect their per-child outcomes and handle failures explicitly. A late acknowledgment is recorded and cannot cancel committed recovery.
478
+
455
479
  ## Clarify TUI
456
480
 
457
481
  Single and parallel runs support a clarification TUI when you want to preview or
@@ -529,6 +553,8 @@ Use `contact_supervisor` with `reason: "need_decision"` when:
529
553
  - a child needs clarification instead of guessing
530
554
  - an approval, product, API, or scope choice is required before continuing safely
531
555
 
556
+ Use `contact_supervisor` with `reason: "interview_request"` when the child needs structured supervisor input rather than a freeform answer. The request waits for a parent reply, so the child should stay alive and continue only after the reply arrives.
557
+
532
558
  Do not use `contact_supervisor` just to resolve review-only/no-project-edit versus progress-writing or output-artifact instructions. The child must not modify project/source files, but returning findings through its normal response or configured output artifact is allowed unless the parent explicitly set `output: false`.
533
559
 
534
560
  Use `contact_supervisor` with `reason: "progress_update"` when:
@@ -537,7 +563,7 @@ Use `contact_supervisor` with `reason: "progress_update"` when:
537
563
  - a long-running child needs to report a blocked/progress checkpoint without waiting for normal tool return flow
538
564
 
539
565
  Message conventions:
540
- - `reason: "need_decision"` waits for the parent reply and returns it to the child.
566
+ - `reason: "need_decision"` and `reason: "interview_request"` wait for the parent reply and return it to the child.
541
567
  - `reason: "progress_update"` is non-blocking and should stay concise.
542
568
  - Child-side routine completion handoffs are not expected. Native supervisor messages are for decisions, structured input, and meaningful progress updates while a child is still running.
543
569
 
@@ -648,6 +674,8 @@ tools: read, grep, find, ls, bash
648
674
  systemPromptMode: replace
649
675
  inheritProjectContext: true
650
676
  inheritSkills: false
677
+ skills: safe-bash, review-checklist
678
+ skillPath: ./skills, ../shared-skills
651
679
  ---
652
680
 
653
681
  Your system prompt here.
@@ -658,7 +686,21 @@ That is only a starting point. Omit `package` for the traditional unqualified ru
658
686
  - `defaultReads`
659
687
  - `output`
660
688
  - `fallbackModels`
689
+ - `subagentOnlyExtensions`
690
+ - `skills`
691
+ - `skillPath`
692
+ - `memory`
661
693
  - `maxSubagentDepth`
694
+ - `acceptance`
695
+ - `acceptanceRole`
696
+
697
+ `acceptance` is a single-agent launch default. Use a scalar level such as `checked` or an inline/block YAML map such as `{ level: "none", reason: "lightweight lookup" }`. An explicit tool-call value wins; chain and parallel acceptance remains configured on the task or step. Management create/update accepts the same policy object, and `acceptance: ""` clears the frontmatter default (`false` remains the deprecated disabled-policy shorthand).
698
+
699
+ `acceptanceRole` is `read-only` or `writer` and controls automatic acceptance inference only. Explicit task mutation or no-edit intent wins; otherwise the role replaces agent-name guessing. Omission preserves the current name heuristics. The field does not grant or revoke tools. Management accepts `false` or an empty string to clear it.
700
+
701
+ `tools` is a strict child allowlist, not an extension loader. For a named extension tool, keep its registered name in `tools` and load its provider through normal Pi discovery, `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. For example, pair `tools: read, fixture_search` with `subagentOnlyExtensions: ./tools/fixture-search.ts` when the provider should exist only in that agent's child sessions. The child now fails with the unavailable names and provider-loading guidance instead of silently continuing when a requested tool is absent; internal `structured_output` is allowed automatically when an output schema requires it.
702
+
703
+ `skillPath` adds invocation-private skill files or discovery directories relative to the agent file; it does not select them, so list the desired names under `skills`. Local matches win, unresolved or unreadable matches use normal discovery, and local candidates never enter the parent/global catalog. Use `memory: { scope: "project" | "user", path: "<name>" }` for opt-in role-specific durable memory under the dedicated `agent-memory/` namespace; it is separate from parent/session project memory.
662
704
 
663
705
  For many customizations, builtin overrides in settings are lower-friction than
664
706
  copying a full builtin file.
@@ -682,7 +724,7 @@ Additional user prompt templates can delegate into `pi-subagents` through the na
682
724
 
683
725
  Other Pi extensions can call `pi-subagents` through the in-process event bus. The stable v1 channels are `subagents:rpc:v1:ready`, `subagents:rpc:v1:request`, and per-request replies at `subagents:rpc:v1:reply:<requestId>`. Envelopes use `{ version: 1, requestId, method, params }`, and replies use `{ version: 1, requestId, success, data | error }`.
684
726
 
685
- Methods: `ping`, `status`, `spawn`, `interrupt`, and `stop`. `spawn` is async-only and rejects management actions, `async: false`, or `clarify: true`; it reuses the normal executor, so discovery, validation, session attribution, spawn limits, child-safety depth, artifacts, and async status are shared with the `subagent` tool. `status` and `interrupt` map to the normal control actions. `stop` targets running async runs through the existing timeout control channel. `pi.events` is process-local, so separate Pi processes and child subagents need lifecycle artifact files or `pi-intercom` instead.
727
+ Methods: `ping`, `status`, `spawn`, `interrupt`, and `stop`. `spawn` is async-only and rejects management actions, `async: false`, or `clarify: true`; it reuses the normal executor, so discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status are shared with the `subagent` tool. `status` and `interrupt` map to the normal control actions. `stop` targets running async runs through the existing timeout control channel. `pi.events` is process-local, so separate Pi processes and child subagents need lifecycle artifact files or `pi-intercom` instead.
686
728
 
687
729
  ## Important Constraints
688
730
 
@@ -700,22 +742,28 @@ Methods: `ping`, `status`, `spawn`, `interrupt`, and `stop`. `spawn` is async-on
700
742
  - **Keep conversational authority clear.** Advisory subagents should not silently
701
743
  become second decision-makers.
702
744
 
745
+ Runtime config can change orchestration behavior. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `subagent_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. Per-run `artifacts: false` disables artifact capture for that launch. Async status and result artifacts are versioned with fields such as `lifecycleArtifactVersion`, `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`. Child protocol failures expose a structured `protocolError`; `protocol_output_limit` means a child emitted a JSONL line above the 4 MiB live-parser cap. Prefer these artifacts and `status` views over scraping terminal output.
746
+
703
747
  ## Best Practices
704
748
 
705
749
  ### Prefer async orchestration
706
750
 
707
751
  Launch every subagent asynchronously by default. Use `async: true` for scouts, researchers, workers, reviewers, validators, oracle checks, one-off delegates, chains, and parallel groups unless you intentionally need a foreground/blocking run. The parent should keep moving: inspect code while scouts run, prepare validation while a worker implements, do a local diff pass while reviewers review, and synthesize or verify while a fix worker applies accepted feedback. Async is the default orchestration posture; foreground runs are the explicit opt-out.
708
752
 
709
- ### Use wait() to block until async runs finish
753
+ ### Use subagent_wait() to block until async runs finish
754
+
755
+ In an interactive chat, do not call `subagent_wait()` merely to wait after launching background work; return control to the user and Pi will wake the session on completion. Override that default when the current request is run-to-completion — for example, the user asked you to stay with the task and report results back this turn or a skill must finish in one turn. In a headless run, Pi auto-drains exact current-session work at `agent_end`; call `subagent_wait()` when this turn must receive results before it ends. In either case, `subagent_wait()` blocks the current turn until the next run completes or needs attention, keeps the turn alive for normal notification delivery, then returns.
756
+
757
+ - `subagent_wait()` — return when the next initially active async run or registered provider item finishes, or a subagent needs attention.
758
+ - `subagent_wait({ all: true })` — block until every async run and provider item active at call time finishes, or a subagent needs attention.
759
+ - `subagent_wait({ id: "..." })` — block on one async or remembered detached foreground run (id or prefix). Provider items are not selected through this parameter.
760
+ - `subagent_wait({ timeoutMs })` — cap the block; active work keeps running if it elapses.
710
761
 
711
- When you have launched async runs and have no independent work left but must keep going to finish the task, call `wait()`. It blocks the current turn until the next run completes or needs attention, keeps the turn alive for normal notification delivery, then returns.
762
+ Providers are discovered through the versioned `pi-subagents/background-work` registry and must return stable item IDs with exact owning session IDs. Child agents receive no provider automatically: keep `subagent_wait` in the child `tools` allowlist and load provider extensions through `extensions` or `subagentOnlyExtensions`.
712
763
 
713
- - `wait()` — return when the next active async run in this session finishes or needs attention.
714
- - `wait({ all: true })` — block until every active async run in this session finishes or one needs attention.
715
- - `wait({ id: "..." })` — block on one run (id or prefix).
716
- - `wait({ timeoutMs })` — cap the block; the runs keep going if it elapses.
764
+ For non-interactive fleet orchestration, `subagent_wait()` can keep N workers in flight: launch N, wait for the next completion, react to the result, launch a replacement if needed, then wait again. Use `subagent_wait({ all: true })` only when you intentionally want to drain the fleet to zero. If the turn ends first, headless `agent_end` auto-drain still waits for exact current-session work. In an interactive session, return to the user instead of holding the turn open just to await completion.
717
765
 
718
- `wait()` is the correct way to keep N workers in flight: launch N, call `wait()`, react to the result, launch a replacement if needed, then call `wait()` again. Use `wait({ all: true })` only when you intentionally want to drain the fleet to zero. Reserve ending-the-turn-to-wait for interactive sessions where the user will prompt you again; in a skill that must complete or a non-interactive `pi -p` run there is no next turn, so `wait()` is required to avoid abandoning live children.
766
+ If config or `PI_SUBAGENT_WAIT_TOOL_ENABLED` disables blocking behavior, direct `subagent_wait` calls return immediately. Headless `agent_end` auto-drain remains active as a lifecycle safeguard and surfaces provider, reconciliation, or timeout failures.
719
767
 
720
768
  ### Keep writes single-threaded by default
721
769
 
@@ -737,7 +785,7 @@ Give subagents specific tasks rather than vague mandates.
737
785
  ### Escalate decisions upward
738
786
 
739
787
  If a subagent encounters an unapproved product, architecture, or scope choice,
740
- it should coordinate back via `intercom` instead of deciding alone.
788
+ it should use `contact_supervisor` and wait for the reply instead of deciding alone. Generic `intercom` is a fallback only when the bridge-provided supervisor tool is unavailable.
741
789
 
742
790
  ### Intervene only on clear control signals
743
791
 
@@ -761,9 +809,23 @@ subagent({
761
809
  })
762
810
  ```
763
811
 
812
+ ### Fable mode for complex work
813
+
814
+ Fable mode is the default orchestration posture for complex work. It is not a separate runtime mode; it is how the parent session uses `subagent`, `interview`, `subagent_wait`, acceptance contracts, artifacts, and fresh-context review when the work has real complexity. Use it for complex features, broad refactors, migrations, ambiguous goals, multi-system changes, expensive validation, user-visible behavior changes, or any request to plan/orchestrate end to end. Do not force it onto tiny one-shot delegation.
815
+
816
+ Run the work through seven gated phases:
817
+
818
+ 1. **Understand** — use `scout` or `context-builder` fanout for breadth, but the parent personally reads the load-bearing files and lets direct source reading decide disagreements. Gate: the parent can quote the exact code or behavior being changed and knows the repo's verification harness.
819
+ 2. **Decide** — separate user-owned decisions from implementation judgments. Use `interview` for product, naming, cost, taste, or risk decisions; decide routine engineering details in the parent and state them. Gate: every user-owned decision needed for design is answered.
820
+ 3. **Design** — use `planner`, `context-builder`, or read-only design/review children for parallel perspectives. Before parallel workstreams, write seam contracts: ownership boundaries, composition points, assumptions, and validation handoffs. Gate: one parent-synthesized plan and written seams for parallel work.
821
+ 4. **Implement** — capture a baseline first, then launch one async `worker` as the sole writer for the active worktree unless isolated worktrees were intentionally requested. Break large work into serial milestones instead of concurrent writes. Gate: build/typecheck is green and every output or diff delta is characterized as intended or fixed.
822
+ 5. **Verify** — climb the spend ladder: static checks, free end-to-end/dry-run, cheapest live probe, targeted changed-path live test, then full realistic run when warranted. Observe the artifact itself, not only exit codes or scores, and confirm the changed code actually executed. Gate: the highest necessary rung has directly observed evidence matching intent.
823
+ 6. **Iterate** — when a gate or reviewer finds a defect, the parent names the failure class, searches for siblings, synthesizes fixes, and sends exactly one fix worker for accepted changes. For LLM judges, gates, or detectors, trigger on concrete findings rather than scores, record pass/violations/error verdicts, cache nondeterministic verdicts by input hash, budget enough output tokens, and sanitize judge text before reusing it downstream. Gate: the class is fixed or explicitly bounded, and recurrence detection exists when feasible.
824
+ 7. **Ship** — run adversarial fresh-context review/validation outside the implementation path, disposition every finding, rerun affected gates, then have the parent inspect the final diff. Commit, push, release, or open PRs only inside user-approved boundaries. Gate: findings are dispositioned, gates re-pass, and the final summary names evidence, artifacts, residual risks, and output paths.
825
+
764
826
  ### Clarify → Plan → Implement → Review (self-orchestrated workflow)
765
827
 
766
- When you are the orchestrating agent for a new feature or non-trivial change, factor in the packaged prompt workflows without literally invoking slash commands. Use the same patterns through tools and subagents.
828
+ For straightforward non-trivial work, this sequence is the lightweight version of the parent-owned loop. When the task is complex, use Fable mode above. In either case, factor in the packaged prompt workflows without literally invoking slash commands. Use the same patterns through tools and subagents.
767
829
 
768
830
  Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior. In particular, packaged `planner`, `worker`, and `oracle` default to forked context.
769
831
 
@@ -785,7 +847,7 @@ clarify → validation contract → planner → async worker → parallel async
785
847
 
786
848
  The validation contract defines acceptance before code is written: expected behavior, acceptance checks, commands or user flows to exercise, and evidence the worker should return. Keep it lightweight for small tasks, but make it explicit enough that reviewers and validators are checking the intended outcome rather than the worker’s own assumptions.
787
849
 
788
- Use the structured `acceptance` field when the run should carry an explicit acceptance contract. If omitted, subagents infer an effective acceptance policy from role, mode, and risk. Use `level: "checked"` for ordinary writer evidence gates, `level: "verified"` when the runtime should run explicit validation commands, and `level: "reviewed"` only when an independent reviewer result is expected. Do not call a run reviewed just because the worker says it is done; reviewed means a reviewer gate returned a result. Child-reported command success is evidence, not runtime verification.
850
+ Use the structured `acceptance` field when the run should carry an explicit acceptance contract. If omitted, subagents infer an effective acceptance policy from role, mode, and risk. Use `level: "checked"` for ordinary writer evidence gates and `level: "verified"` when the runtime should run explicit validation commands. Do not explicitly request `level: "reviewed"`: the current run cannot supply an independent reviewer result, so that level is reserved for inferred policy. Orchestrate a separate reviewer instead. To disable gates, use `{ level: "none", reason: "..." }`; the bare string `"none"` is rejected, and `false` is accepted only as a deprecated shorthand. Do not call a run reviewed just because the worker says it is done; reviewed means a reviewer gate returned a result. Child-reported command success is evidence, not runtime verification.
789
851
 
790
852
  The first `worker` implements the approved plan. The parent continues with independent inspection or validation prep while it runs, not parallel edits to the same worktree. When the async worker completes, treat its handoff as the transition into review, not as final completion, unless the user explicitly asked for worker-only work, review-only output, or to stop after implementation. Parallel reviewers inspect the resulting diff from fresh context. Validators check behavior with the best available evidence: commands, tests, browser/CLI interaction, screenshots, logs, or manual reproduction notes. The final `worker` applies synthesized review fixes in forked context, then the parent looks over the final diff before completing. The parent may launch these steps as an initial async chain when the workflow is already clear, or as follow-up subagent runs after each async completion. Initial chains should pass `async: true` so the main chat is unblocked; avoid `clarify: true` unless the user asked for foreground clarification. Do not stop after parallel review unless the user explicitly asked for review-only output or the review surfaced a decision that needs approval first.
791
853