pi-subagents 0.31.1 → 0.33.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 (60) hide show
  1. package/CHANGELOG.md +67 -4
  2. package/README.md +219 -40
  3. package/install.mjs +2 -1
  4. package/package.json +3 -2
  5. package/skills/pi-subagents/SKILL.md +71 -10
  6. package/src/agents/agent-management.ts +179 -2
  7. package/src/agents/agent-memory.ts +254 -0
  8. package/src/agents/agent-serializer.ts +11 -0
  9. package/src/agents/agents.ts +193 -19
  10. package/src/agents/chain-serializer.ts +27 -2
  11. package/src/extension/config.ts +27 -4
  12. package/src/extension/doctor.ts +1 -7
  13. package/src/extension/fanout-child.ts +3 -2
  14. package/src/extension/index.ts +70 -41
  15. package/src/extension/rpc.ts +369 -0
  16. package/src/extension/schemas.ts +54 -10
  17. package/src/extension/tool-description.ts +200 -0
  18. package/src/intercom/intercom-bridge.ts +21 -253
  19. package/src/intercom/native-supervisor-channel.ts +510 -0
  20. package/src/runs/background/async-execution.ts +187 -38
  21. package/src/runs/background/async-job-tracker.ts +88 -2
  22. package/src/runs/background/async-status.ts +67 -10
  23. package/src/runs/background/chain-root-attachment.ts +34 -4
  24. package/src/runs/background/completion-batcher.ts +166 -0
  25. package/src/runs/background/control-channel.ts +156 -1
  26. package/src/runs/background/fleet-view.ts +515 -0
  27. package/src/runs/background/notify.ts +161 -44
  28. package/src/runs/background/result-watcher.ts +1 -2
  29. package/src/runs/background/run-id-resolver.ts +3 -2
  30. package/src/runs/background/run-status.ts +167 -6
  31. package/src/runs/background/scheduled-runs.ts +514 -0
  32. package/src/runs/background/stale-run-reconciler.ts +28 -1
  33. package/src/runs/background/subagent-runner.ts +840 -127
  34. package/src/runs/background/wait.ts +353 -0
  35. package/src/runs/foreground/chain-execution.ts +123 -27
  36. package/src/runs/foreground/execution.ts +174 -27
  37. package/src/runs/foreground/subagent-executor.ts +569 -81
  38. package/src/runs/shared/acceptance.ts +45 -22
  39. package/src/runs/shared/dynamic-fanout.ts +2 -2
  40. package/src/runs/shared/model-fallback.ts +171 -20
  41. package/src/runs/shared/model-scope.ts +128 -0
  42. package/src/runs/shared/nested-events.ts +89 -0
  43. package/src/runs/shared/parallel-utils.ts +50 -1
  44. package/src/runs/shared/pi-args.ts +35 -4
  45. package/src/runs/shared/pi-spawn.ts +52 -20
  46. package/src/runs/shared/single-output.ts +2 -0
  47. package/src/runs/shared/subagent-prompt-runtime.ts +110 -4
  48. package/src/runs/shared/tool-budget.ts +74 -0
  49. package/src/runs/shared/turn-budget.ts +52 -0
  50. package/src/runs/shared/worktree.ts +28 -5
  51. package/src/shared/artifacts.ts +16 -1
  52. package/src/shared/atomic-json.ts +15 -2
  53. package/src/shared/child-transcript.ts +212 -0
  54. package/src/shared/fork-context.ts +133 -22
  55. package/src/shared/settings.ts +3 -1
  56. package/src/shared/types.ts +197 -4
  57. package/src/shared/utils.ts +99 -14
  58. package/src/slash/prompt-workflows.ts +330 -0
  59. package/src/slash/slash-commands.ts +133 -2
  60. package/src/tui/render.ts +32 -12
package/README.md CHANGED
@@ -95,7 +95,7 @@ Those are ordinary Pi requests. Pi decides whether to call `subagent`, which age
95
95
  | Run in the background | “Run this in the background.” |
96
96
  | Browse agents | “Show me the available subagents.” |
97
97
  | Use a saved workflow | “Run the review chain on this branch.” |
98
- | See running work | “Show active async runs.” |
98
+ | See running work | “Show active async runs.” or “Show the subagent fleet.” |
99
99
  | Check setup | “Check whether subagents are configured correctly.” |
100
100
 
101
101
  The extension ships with builtin agents you can use immediately.
@@ -117,7 +117,21 @@ A simple rule of thumb: use `scout` before you understand the code, `researcher`
117
117
 
118
118
  ## Changing an agent's model
119
119
 
120
- Builtin agents inherit your current Pi default model by default. This keeps new installs from depending on a provider you may not have configured. If you want a role to use a specific model, set an override instead of copying the bundled agent file.
120
+ Builtin agents inherit your current Pi default model by default. This keeps new installs from depending on a provider you may not have configured. If you want every subagent without its own model to use a different default, set `subagents.defaultModel`. If you want a role to use a specific model, set an override instead of copying the bundled agent file.
121
+
122
+ ```json
123
+ {
124
+ "defaultModel": "deepseek-v4-pro",
125
+ "subagents": {
126
+ "defaultModel": "deepseek-v4-flash",
127
+ "agentOverrides": {
128
+ "oracle": {
129
+ "model": "deepseek-v4-pro"
130
+ }
131
+ }
132
+ }
133
+ }
134
+ ```
121
135
 
122
136
  For one run, put the override in the command:
123
137
 
@@ -141,7 +155,7 @@ For a persistent override, edit settings. This example pins the reviewer everywh
141
155
  }
142
156
  ```
143
157
 
144
- Use `~/.pi/agent/settings.json` for a user override or the project config settings file (`.pi/settings.json` in standard Pi) for a project override. The same `agentOverrides` block can change `tools`, `skills`, inherited context, prompt text, or disable a builtin. Matching user and project agents also receive override fields that their frontmatter leaves unset, so a shared project config agent can keep the persona while local settings choose the model. Explicit frontmatter still wins.
158
+ Use `~/.pi/agent/settings.json` for a user override or the project config settings file (`.pi/settings.json` in standard Pi) for a project override. `subagents.defaultModel` applies to builtin, package, user, and project agents that do not set `model` in frontmatter. Per-run model overrides and `agentOverrides.<name>.model` still win, and explicit agent frontmatter still wins over the global default. The same `agentOverrides` block can change `tools`, `skills`, inherited context, prompt text, or disable a builtin. Matching user and project agents also receive override fields that their frontmatter leaves unset, so a shared project config agent can keep the persona while local settings choose the model.
145
159
 
146
160
  If your provider rejects model IDs with thinking suffixes, set `subagents.disableThinking: true` in user or project settings. That clears bundled builtin thinking defaults in one place; an explicit higher-precedence `agentOverrides.<name>.thinking` value can opt a role back in.
147
161
 
@@ -154,11 +168,28 @@ To inspect what `pi-subagents` has actually loaded right now, use:
154
168
 
155
169
  That reports the live runtime mapping, which can differ from settings on disk until you reload Pi.
156
170
 
171
+ You do not have to spell a model exactly. Model ids are matched fuzzily against the registry, so provider separator variations (`anthropic/claude-sonnet-4`, `anthropic:claude-sonnet-4`, or `anthropic.claude-sonnet-4`), id separator variations (`claude-haiku-4.5` vs `claude-haiku-4-5`), case differences (`Claude-Sonnet-4` vs `claude-sonnet-4`), and optional trailing date stamps (`claude-haiku-4-5-20251001` or `claude-haiku-4-5-2025-10-01` vs `claude-haiku-4-5`) all resolve to the same model. Exact `provider/id` matches still win, and a qualified provider query never silently switches providers — it only matches within the named provider. Ambiguous bare ids that exist under multiple providers still require a provider prefix or the current session's provider to disambiguate.
172
+
173
+ To keep subagents inside a budget or compliance profile, enforce a model scope. Put `subagents.modelScope` in user or project settings (project overrides user):
174
+
175
+ ```json
176
+ {
177
+ "subagents": {
178
+ "modelScope": {
179
+ "enforce": true,
180
+ "allow": ["anthropic/*", "openai/gpt-5-*"]
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ `allow` is a list of glob patterns matched against the resolved `provider/id` (only `*` is special, case-insensitive). A resolved model that matches none of the patterns is rejected. Models you pass explicitly — the tool-call `model`, `--model`, or a clarify pick — error and abort the run. Models that come from agent frontmatter, `subagents.defaultModel`, or the inherited parent session model only warn, so existing configurations keep working while you tighten the scope. `enforce: true` requires a non-empty `allow` list; otherwise the config is rejected at load time.
187
+
157
188
  ## Where running subagents show up
158
189
 
159
190
  Foreground runs stream progress in the conversation while they run.
160
191
 
161
- 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: "..." })`.
192
+ 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: "..." })`. For a read-only fleet view across active foreground and background work, use `/subagents-fleet` or `subagent({ action: "status", view: "fleet" })`. To inspect what a background child is saying without hunting through artifact directories, tail its live transcript with `subagent({ action: "status", id: "...", view: "transcript" })`; add `index` for a specific child in a parallel or chain run.
162
193
 
163
194
  They also show a compact async widget and send completion notifications. Parallel background runs show per-agent progress instead of fake chain steps. 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.
164
195
 
@@ -168,6 +199,30 @@ You can also ask naturally:
168
199
  Show me the current async runs.
169
200
  ```
170
201
 
202
+ 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.
203
+
204
+ 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`, and nested `children` when a child is allowed to launch subagents. `events.jsonl` records lifecycle transitions such as `subagent.run.started`, `subagent.step.started`, `subagent.step.completed`/`failed`/`paused`, control attention events, nested interrupt failures, and `subagent.run.completed`; 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.
205
+
206
+ 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>`.
207
+
208
+ ```typescript
209
+ const requestId = crypto.randomUUID();
210
+ pi.events.on(`subagents:rpc:v1:reply:${requestId}`, (reply) => {
211
+ // { version: 1, requestId, success: true, data } or
212
+ // { version: 1, requestId, success: false, error: { code, message } }
213
+ });
214
+ pi.events.emit("subagents:rpc:v1:request", {
215
+ version: 1,
216
+ requestId,
217
+ method: "spawn",
218
+ params: { agent: "reviewer", task: "Review the current diff", context: "fresh" }
219
+ });
220
+ ```
221
+
222
+ The v1 methods are `ping`, `status`, `spawn`, `interrupt`, and `stop`. `status` and `interrupt` reuse the normal control actions. `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, spawn limits, child-safety depth, artifacts, and async status all behave the same. `stop` targets running async runs through the existing timeout control channel.
223
+
224
+ `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.
225
+
171
226
  If something feels misconfigured, run:
172
227
 
173
228
  ```text
@@ -210,15 +265,9 @@ The package includes reusable prompt templates for common workflows. You do not
210
265
 
211
266
  Add `autofix` to `/parallel-review` or `/parallel-cleanup` to apply only the synthesized fixes worth doing now after reviewers return.
212
267
 
213
- ## Optional pi-intercom companion
214
-
215
- `pi-subagents` works without `pi-intercom`. Install `pi-intercom` only if you want child agents to talk back to the parent Pi session while they are running.
216
-
217
- ```bash
218
- pi install npm:pi-intercom
219
- ```
268
+ ## Native supervisor coordination
220
269
 
221
- Most users do not call `intercom` directly. After `pi-intercom` is installed, `pi-subagents` can automatically give child agents a private coordination channel back to the parent session. The bridge recognizes the normal `pi install npm:pi-intercom` package install as well as legacy local extension checkouts.
270
+ Child agents can talk back to the parent Pi session without installing `pi-intercom`. `pi-subagents` now provides the child-facing `contact_supervisor` tool and the parent-facing `intercom({ action: "reply" })` path natively.
222
271
 
223
272
  Use it for work where the child might need a decision instead of guessing:
224
273
 
@@ -232,11 +281,11 @@ Ask oracle to review this plan. If it sees a decision I need to make, have it as
232
281
 
233
282
  The child can use one dedicated coordination tool:
234
283
 
235
- - `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
284
+ - `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, `reason: "interview_request"` for structured input, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
236
285
 
237
- Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets, full child summaries, and compact nested child summaries under the parent child that launched them.
286
+ Supervisor messages are scoped to the exact Pi session id that spawned the child. A second Pi session in the same repository does not receive those requests.
238
287
 
239
- If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
288
+ Child-side routine completion handoffs are still not expected. If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
240
289
 
241
290
  If messages do not show up, run:
242
291
 
@@ -332,6 +381,7 @@ Skip this section until you want exact syntax.
332
381
  | `/chain scout "scan" -> (reviewer "A" \| reviewer "B") -> writer "fix"` | Run a chain with a static parallel group inline |
333
382
  | `/parallel agent1 "task1" -> agent2 "task2"` | Run agents in parallel |
334
383
  | `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` or `.chain.json` workflow |
384
+ | `/subagent-cost` | Show parent plus child subagent token usage and cost for this session |
335
385
  | `/subagents-doctor` | Show read-only setup diagnostics |
336
386
  | `/subagents-models [agent]` | Show the runtime-loaded builtin model mapping, optionally filtered to one builtin |
337
387
  | `/subagents-profiles` | List saved subagent profiles from `~/.pi/agent/profiles/pi-subagents/` |
@@ -440,7 +490,7 @@ Append `[key=value,...]` to an agent name to override defaults. `/chain` applies
440
490
 
441
491
  | Key | Example | Description |
442
492
  |-----|---------|-------------|
443
- | `output` | `output=context.md` | Write results to a file. For `/chain` and `/parallel`, relative paths live under the chain directory; for `/run`, relative paths resolve against cwd. |
493
+ | `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. |
444
494
  | `outputMode` | `outputMode=file-only` | Return only a concise file reference for saved output instead of the full saved content. Requires `output`; default is `inline`. |
445
495
  | `reads` | `reads=a.md+b.md` | Read files before executing. `+` separates multiple paths. |
446
496
  | `model` | `model=anthropic/claude-sonnet-4` | Override model for this step. |
@@ -483,13 +533,15 @@ You can combine them in either order:
483
533
  /run reviewer "review this diff" --bg --fork
484
534
  ```
485
535
 
486
- Background runs are detached. If the parent agent has other independent work, it should keep working. If it has nothing useful to do until the background result arrives, it should end the turn instead of running sleep or status-polling loops. Pi will deliver the completion when the run finishes.
536
+ Background runs are detached. If the parent agent has other independent work, it should keep working. When it has nothing useful to do until a background result arrives, it should call the `wait` tool instead of running sleep or 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 })` for one run, and `wait({ timeoutMs })` to cap the block.
537
+
538
+ `wait` is what lets a background-launching skill keep moving in a single turn, including non-interactive `pi -p` invocations where there is no subsequent turn to receive a completion notification. Ending the turn to wait for a completion only works in an interactive session where the user will prompt the agent again; in a run-to-completion skill or a non-interactive run, use `wait` so the still-running children are not abandoned.
487
539
 
488
540
  The `oracle` and `worker` builtins are designed for an explicit decision loop. A typical pattern is to ask `oracle` for diagnosis and a recommended execution prompt, then only run `worker` after the main agent approves that direction.
489
541
 
490
542
  ## Clarify and launch UI
491
543
 
492
- Chains open a clarify UI by default so you can preview and edit the workflow before it runs. Single and parallel tool calls can opt into the same flow with `clarify: true`; slash commands launch directly.
544
+ 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.
493
545
 
494
546
  Common clarify keys:
495
547
 
@@ -521,7 +573,7 @@ Agent locations, lowest to highest priority:
521
573
 
522
574
  Project discovery also reads legacy `.agents/**/*.md` files. Nested subdirectories are discovered recursively. `.chain.md` files do not define agents. Installed Pi packages can expose agent directories from either `{"pi-subagents":{"agents":["./agents"]}}` or `{"pi":{"subagents":{"agents":["./agents"]}}}` in their package manifest. Package agents load above builtins and below user/project agents. If both `.agents/` and the project config agents directory define the same parsed runtime agent name, the project config directory wins. Use `agentScope: "user" | "project" | "both"` to control discovery; `both` is the default and project definitions win runtime-name collisions.
523
575
 
524
- Builtin agents load at the lowest priority, so a user or project agent with the same name overrides them. They do not pin a provider model; they inherit your current Pi default model unless you set `subagents.agentOverrides.<name>.model`. `oracle` is an advisory reviewer that critiques direction and proposes an execution prompt without editing files. `worker` is the implementation agent for normal tasks and approved oracle handoffs.
576
+ Builtin agents load at the lowest priority, so a user or project agent with the same name overrides them. They do not pin a provider model; they inherit your current Pi default model unless you set `subagents.defaultModel` or `subagents.agentOverrides.<name>.model`. `oracle` is an advisory reviewer that critiques direction and proposes an execution prompt without editing files. `worker` is the implementation agent for normal tasks and approved oracle handoffs.
525
577
 
526
578
  The `researcher` builtin uses `web_search`, `fetch_content`, and `get_search_content`; those require [pi-web-access](https://github.com/nicobailon/pi-web-access):
527
579
 
@@ -552,7 +604,9 @@ Example:
552
604
 
553
605
  Supported override fields are `model`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`, `disabled`, `skills`, `tools`, and `systemPrompt`. Use `defaultContext: false` in builtin overrides to clear an inherited context default. Project overrides beat user overrides.
554
606
 
555
- Set `disabled: true` to hide a builtin from runtime discovery and agent-facing `subagent({ action: "list" })` output. For bulk control, set `subagents.disableBuiltins: true` in settings.
607
+ Set `subagents.defaultModel` to give all subagents without an explicit model their own default model, separate from the parent session model. Per-agent model overrides and agent frontmatter still win.
608
+
609
+ Set `disabled: true` to hide a builtin from runtime discovery and agent-facing `subagent({ action: "list" })` output. For bulk control, set `subagents.disableBuiltins: true` in settings. You can also toggle a single agent without editing settings by hand: `subagent({ action: "disable", agent: "reviewer" })` writes that override, and `subagent({ action: "enable", agent: "reviewer" })` removes it.
556
610
 
557
611
  Set `subagents.disableThinking: true` to clear bundled builtin thinking defaults globally for providers that do not support `:low`, `:medium`, `:high`, or similar model suffixes. A higher-precedence per-agent `thinking` override can opt one builtin back in.
558
612
 
@@ -623,7 +677,22 @@ Important fields:
623
677
  | `defaultProgress` | Maintain `progress.md`. |
624
678
  | `completionGuard` | Set `false` only for non-implementation agents that may mention implementation words while using mutation-capable tools such as `bash`. |
625
679
  | `interactive` | Parsed for compatibility but not enforced in v1. |
626
- | `maxSubagentDepth` | Tightens nested delegation for this agents children. |
680
+ | `maxSubagentDepth` | Tightens nested delegation for this agent's children. |
681
+ | `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. |
682
+
683
+ ### Per-agent persistent memory
684
+
685
+ A recurring custom agent can opt into a durable, role-specific memory scope with the `memory` frontmatter field. This is independent of Pi's own parent/session/project memory system and writes nothing to it; memory lives under a dedicated `agent-memory/` namespace so the two never collide.
686
+
687
+ ```yaml
688
+ memory:
689
+ scope: project
690
+ path: security-reviewer
691
+ ```
692
+
693
+ On each run, the first 200 lines of `MEMORY.md` in the resolved memory directory are injected into the child system prompt so the agent can recall accumulated role notes such as threat-model entries, release gotchas, or verified commands. Agents that have write tools (`edit`, `write`, or `bash`, or no `tools` allowlist at all) are told they may append concise dated entries to the file. Agents without write tools receive a read-only memory block and are not instructed to edit it, so a read-only reviewer can still recall prior notes without being granted write capability. The memory directory is never created eagerly; the agent's own `write` tool creates it (and `MEMORY.md`) on the first persist. Memory paths are validated against `.`/`..` traversal and symlink escape, and an unsafe or unresolvable scope is silently skipped rather than breaking the run.
694
+
695
+ Project-scoped memory resolves under `<project>/.pi/agent-memory/<path>` and travels with the repo. User-scoped memory resolves under `~/.pi/agent/agent-memory/<path>` and is shared across projects for that agent.
627
696
 
628
697
  ### Tool and extension selection
629
698
 
@@ -815,7 +884,7 @@ What the bundled skill covers:
815
884
  - **Prompt workflow recipes**: how to apply the packaged techniques directly with `subagent(...)` when the user describes the workflow in natural language instead of invoking a slash command. This includes parallel review, review-loop, parallel research, parallel context-build, parallel handoff-plan, gather-context-and-clarify, and parallel cleanup
816
885
  - **Role-agent prompting guidance**: compact contract prompts instead of long scripts, what to include in role-specific meta prompts, and retrieval budgets for researchers
817
886
  - **Safety boundaries**: child agents must not run subagents unless their resolved builtin tools explicitly include `subagent`, must not invent intercom targets, and must escalate unapproved decisions
818
- - **Intercom conventions**: when to ask vs send, and how parent-side result delivery works with `pi-intercom`
887
+ - **Intercom conventions**: when to ask vs send, and how parent-side supervisor/result delivery works through the native channel
819
888
  - **Control and diagnostics**: attention signals, soft interrupts, status, and the `doctor` action
820
889
 
821
890
  If you are writing an agent that orchestrates subagents, the bundled skill helps it behave correctly without guessing the patterns. If you are a human user, you do not need to read it directly; the README and prompt shortcuts encode the same workflows in user-facing form.
@@ -951,32 +1020,45 @@ Agent definitions are not loaded into context by default. Management actions let
951
1020
  { action: "update", chainName: "review-pipeline", config: { steps: [...] } }
952
1021
  { action: "delete", agent: "scout" }
953
1022
  { action: "delete", chainName: "review-pipeline" }
1023
+
1024
+ { action: "eject", agent: "reviewer" }
1025
+ { action: "eject", agent: "reviewer", agentScope: "project" }
1026
+ { action: "disable", agent: "reviewer" }
1027
+ { action: "enable", agent: "reviewer", agentScope: "project" }
1028
+ { action: "reset", agent: "reviewer" }
954
1029
  ```
955
1030
 
956
1031
  `create` uses `config.scope`, not `agentScope`. `config.name` is the local frontmatter name; optional `config.package` registers the runtime name as `{package}.{name}` and is saved as separate `name` and `package` frontmatter. `update` and `delete` use the runtime name and `agentScope` only when the same runtime name exists in multiple scopes. To clear optional string fields, including `package`, set them to `false` or `""`.
957
1032
 
1033
+ `eject` copies a bundled builtin or package agent verbatim into the user or project agent dir (default `user`) as an editable custom file that shadows the original, so you can customize a builtin without hunting package files. `disable` writes a reversible `agentOverrides.<name>.disabled: true` entry to the user or project settings file (default `user`); the agent stays on disk but is hidden from runtime discovery and `list`. `enable` removes that `disabled` field while preserving any other override fields on the same entry. `reset` deletes the scope's custom agent file and/or settings override entry, restoring the bundled default; it refuses if no bundled default exists (use `delete` for purely custom agents). All four accept `agentScope: "user" | "project"` and operate in one scope at a time; project overrides still win over user ones, so a project-scope disable survives a user-scope `enable` until you target the project scope.
1034
+
958
1035
  ### Parameter reference
959
1036
 
960
1037
  | Param | Type | Default | Description |
961
1038
  |-------|------|---------|-------------|
962
1039
  | `agent` | string | - | Agent name for single mode, or target for management actions. |
963
1040
  | `task` | string | - | Task string for single mode. |
964
- | `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `interrupt`, `resume`, `append-step`, or `doctor`. |
1041
+ | `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `interrupt`, `resume`, `steer`, `append-step`, or `doctor`. |
965
1042
  | `chainName` | string | - | Chain name for management actions. |
966
1043
  | `config` | object/string | - | Agent or chain config for create/update. |
967
1044
  | `output` | `string \| false` | agent default | Override single-agent output file. |
968
1045
  | `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
969
1046
  | `skill` | `string \| string[] \| false` | agent default | Override skills or disable all. |
970
1047
  | `model` | string | agent default | Override model. |
971
- | `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, `model`, and `acceptance`. |
1048
+ | `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, `model`, `toolBudget`, and `acceptance`. |
972
1049
  | `concurrency` | number | config or `4` | Top-level parallel concurrency. |
973
1050
  | `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
974
1051
  | `chain` | array | - | Sequential, static parallel, and dynamic fanout chain steps. Steps and chain parallel tasks support `phase`, `label`, `as`, `outputSchema`, and `acceptance` 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. |
975
1052
  | `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`, and `oracle` default to `fork`. |
976
1053
  | `chainDir` | string | temp chain dir | Persistent directory for chain artifacts. |
977
- | `clarify` | boolean | true for chains | Show TUI preview/edit flow. |
1054
+ | `view` | `fleet \| transcript` | - | Optional `status` view for the active fleet surface or transcript tail inspection. |
1055
+ | `lines` | number | `80` | Maximum transcript lines for `action: "status", view: "transcript"`; capped at 500. |
1056
+ | `clarify` | boolean | false | Show TUI preview/edit flow. Explicit `clarify: true` keeps the run foreground for the clarify UI. |
978
1057
  | `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
979
1058
  | `async` | boolean | false | Background execution. For chains, `clarify: true` explicitly keeps the run foreground for the clarify UI. |
1059
+ | `timeoutMs` / `maxRuntimeMs` | number | none | Optional run-level max runtime in milliseconds for foreground and async/background runs. |
1060
+ | `turnBudget` | object | none | Optional assistant-turn budget `{ maxTurns, graceTurns }`. At `maxTurns` the child is warned to wrap up; after `graceTurns` (default 1) more assistant turns the run is aborted and partial output is returned. |
1061
+ | `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`, or use `"*"` to block every tool call. Final assistant text is never blocked. |
980
1062
  | `cwd` | string | runtime cwd | Override working directory. |
981
1063
  | `maxOutput` | object | 200KB, 5000 lines | Final output truncation limits. |
982
1064
  | `artifacts` | boolean | true | Write debug artifacts. |
@@ -985,31 +1067,37 @@ Agent definitions are not loaded into context by default. Management actions let
985
1067
  | `sessionDir` | string | derived | Override session log directory. |
986
1068
  | `acceptance` | string/object/false | inferred | Override the run's inferred acceptance gates. Use `"auto"`, `"attested"`, `"checked"`, `"verified"`, `"reviewed"`, or `{ level: "none", reason: "..." }`. |
987
1069
 
988
- `context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. It 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.
1070
+ `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 and forces the child run's thinking level to `off` so Anthropic does not reject modified signatures after branching or compaction. 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.
989
1071
 
990
1072
  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, later `{previous}` steps receive the same compact reference when the prior step used file-only mode.
991
1073
 
992
- Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. 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}`.
1074
+ Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, `model`, and `toolBudget`. 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}`.
993
1075
 
994
1076
  Status and control actions:
995
1077
 
996
1078
  ```ts
997
1079
  subagent({ action: "status" })
1080
+ subagent({ action: "status", view: "fleet" })
998
1081
  subagent({ action: "status", id: "<run-id>" })
1082
+ subagent({ action: "status", id: "<run-id>", view: "transcript", index: 0, lines: 80 })
999
1083
  subagent({ action: "status", id: "<nested-run-id>" })
1000
1084
  subagent({ action: "interrupt", id: "<run-id>" })
1001
1085
  subagent({ action: "interrupt", id: "<nested-run-id>" })
1002
1086
  subagent({ action: "resume", id: "<run-id>", message: "follow-up question" })
1003
1087
  subagent({ action: "resume", id: "<run-id>", index: 1, message: "follow-up for child 2" })
1004
1088
  subagent({ action: "resume", id: "<nested-run-id>", message: "follow-up for a nested child" })
1089
+ subagent({ action: "steer", id: "<run-id>", message: "guidance for the running child" })
1090
+ subagent({ action: "steer", id: "<run-id>", index: 1, message: "guidance for child 2" })
1005
1091
  subagent({ action: "append-step", id: "<run-id>", chain: [{ agent: "worker", task: "Continue from {previous}" }] })
1006
1092
  subagent({ action: "doctor" })
1007
1093
  ```
1008
1094
 
1009
- `status` resolves exact foreground ids, top-level async ids, and nested run ids before falling back to prefix matching. Nested status shows the root/parent path, nested children, session/artifact paths when known, and nested control commands. Inside child-safe fanout mode, bare `status` requires an id when no local foreground run is active, so children cannot enumerate unrelated top-level async runs. Bare `interrupt` still targets only the visible top-level run; interrupting a nested run requires its explicit nested id.
1095
+ `status` resolves exact foreground ids, top-level async ids, and nested run ids before falling back to prefix matching. `view: "fleet"` is an optional read-only active-run surface with transcript commands; it does not add steering or stop controls. `view: "transcript"` tails the selected run's live `output-<index>.log` or persisted session transcript, with `lines` capped at 500. Nested status shows the root/parent path, nested children, session/artifact paths when known, and nested control commands. Inside child-safe fanout mode, bare `status` requires an id when no local foreground run is active, so children cannot enumerate unrelated top-level async runs. Bare `interrupt` still targets only the visible top-level run; interrupting a nested run requires its explicit nested id.
1010
1096
 
1011
1097
  `resume` sends the follow-up directly when an async child is still reachable over intercom. After completion, it revives the child by starting a new async child from the stored child session file. 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 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.
1012
1098
 
1099
+ `steer` queues non-terminal guidance for a running async Pi child, or for a pending indexed child that will start later in the same async run. It does not interrupt, pause, or revive a child. Delivery requires the spawned Pi session to support mid-run `sendUserMessage(..., { deliverAs: "steer" })`; unsupported runtimes keep the request visible in control artifacts but cannot receive it live. Use `index` for multi-child runs when you want to steer one child; without `index`, steering targets the currently running child or children.
1100
+
1013
1101
  `append-step` accepts exactly one sequential, 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, paused, foreground, single, and top-level parallel runs reject appends.
1014
1102
 
1015
1103
  ## Worktree isolation
@@ -1040,12 +1128,24 @@ Requirements:
1040
1128
  - task-level `cwd` overrides must be omitted or match the shared cwd
1041
1129
  - configured `worktreeSetupHook` must return valid JSON before timeout
1042
1130
 
1131
+ 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.
1132
+
1043
1133
  After a worktree parallel step completes, per-agent diff stats are appended to the output and full patch files are written to artifacts. Worktrees and temp branches are cleaned up in `finally` blocks.
1044
1134
 
1045
1135
  ## Configuration
1046
1136
 
1047
1137
  `pi-subagents` reads optional JSON config from `~/.pi/agent/extensions/subagent/config.json`.
1048
1138
 
1139
+ ### `toolDescriptionMode`
1140
+
1141
+ ```json
1142
+ { "toolDescriptionMode": "compact" }
1143
+ ```
1144
+
1145
+ Controls the parent-facing `subagent` tool description registered at startup. `full` is the default. `compact` keeps the execution modes, async/wait guidance, child-safety boundary, management/action split, one-writer review guidance, and artifact/status essentials with less prompt bloat.
1146
+
1147
+ `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.
1148
+
1049
1149
  ### `asyncByDefault`
1050
1150
 
1051
1151
  ```json
@@ -1062,6 +1162,30 @@ Makes top-level calls use background execution when the request does not explici
1062
1162
 
1063
1163
  Forces depth-0 single, parallel, and chain runs into background mode and bypasses clarify UI by forcing `clarify: false`. Nested calls keep their own inherited settings.
1064
1164
 
1165
+ ### `globalConcurrencyLimit`
1166
+
1167
+ ```json
1168
+ { "globalConcurrencyLimit": 20 }
1169
+ ```
1170
+
1171
+ 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.
1172
+
1173
+ ### `maxSubagentSpawnsPerSession`
1174
+
1175
+ ```json
1176
+ { "maxSubagentSpawnsPerSession": 40 }
1177
+ ```
1178
+
1179
+ Caps the total number of child subagent launches allowed during one parent session, including single runs, parallel task counts, static chain steps, and bounded dynamic fanout children. Set `PI_SUBAGENT_MAX_SPAWNS_PER_SESSION` to override the config for a process. The default is `40`; `0` blocks new subagent launches for that session.
1180
+
1181
+ ### `scheduledRuns`
1182
+
1183
+ ```json
1184
+ { "scheduledRuns": { "enabled": true, "maxPending": 20, "maxLatenessMs": 300000 } }
1185
+ ```
1186
+
1187
+ 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, `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.
1188
+
1065
1189
  ### `parallel`
1066
1190
 
1067
1191
  ```json
@@ -1083,6 +1207,14 @@ Forces depth-0 single, parallel, and chain runs into background mode and bypasse
1083
1207
 
1084
1208
  Session directory precedence is: `params.sessionDir`, then `config.defaultSessionDir`, then a directory derived from the parent session. Sessions are always enabled.
1085
1209
 
1210
+ ### `singleRunOutputBaseDir`
1211
+
1212
+ ```json
1213
+ { "singleRunOutputBaseDir": "~/.pi/subagent-outputs" }
1214
+ ```
1215
+
1216
+ Routes relative `output` paths for single-agent `/run` calls under this directory. Absolute per-call or agent output paths are still used as-is. When unset, relative single-run outputs go under the run's output artifact directory instead of the project root.
1217
+
1086
1218
  ### `maxSubagentDepth`
1087
1219
 
1088
1220
  ```json
@@ -1091,6 +1223,14 @@ Session directory precedence is: `params.sessionDir`, then `config.defaultSessio
1091
1223
 
1092
1224
  Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent’s child runs, but cannot relax an inherited stricter limit. This applies even to children that explicitly declare `tools: subagent`; at the cap, execution fanout is blocked instead of silently hiding nested work.
1093
1225
 
1226
+ ### `PI_SUBAGENT_PI_BINARY`
1227
+
1228
+ ```bash
1229
+ export PI_SUBAGENT_PI_BINARY=/path/to/pi-or-wrapper
1230
+ ```
1231
+
1232
+ Overrides the command used to launch child Pi processes. Package wrappers can set this to their own `pi`/agent binary so subagents inherit wrapper flags, environment setup, and bundled resources without relying on `PATH` ordering. Empty or whitespace-only values are ignored.
1233
+
1094
1234
  ### `intercomBridge`
1095
1235
 
1096
1236
  ```json
@@ -1109,10 +1249,18 @@ Fields:
1109
1249
  - `mode`: default `always`; use `fork-only` to inject only for forked runs, or `off` to disable the bridge.
1110
1250
  - `instructionFile`: optional Markdown template replacing the default bridge instructions. `{orchestratorTarget}` is interpolated. Relative paths resolve from `~/.pi/agent/extensions/subagent/`.
1111
1251
 
1112
- Bridge activation also requires `pi-intercom` to be installed and enabled through `pi install npm:pi-intercom` or a legacy local extension checkout, a targetable current session name or fallback alias, and `pi-intercom` in any explicit agent `extensions` allowlist.
1252
+ 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.
1113
1253
 
1114
1254
  The default injected guidance tells children to use `contact_supervisor` with `reason: "need_decision"` when blocked or needing a decision, `reason: "progress_update"` only for meaningful blocked/progress updates, generic `intercom` as fallback plumbing, and avoid routine completion handoffs.
1115
1255
 
1256
+ ### `worktreeBaseDir`
1257
+
1258
+ ```json
1259
+ { "worktreeBaseDir": "/Users/matt/code/.worktrees/pi-subagents" }
1260
+ ```
1261
+
1262
+ Sets the base directory for `worktree: true` runs. Relative paths resolve from the repository root, `~/...` expands to your home directory, and `PI_SUBAGENTS_WORKTREE_DIR` is used when config is unset. The default remains the system temp directory.
1263
+
1116
1264
  ### `worktreeSetupHook`
1117
1265
 
1118
1266
  ```json
@@ -1132,6 +1280,25 @@ stdin is a JSON object with `repoRoot`, `worktreePath`, `agentCwd`, `branch`, `i
1132
1280
 
1133
1281
  `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.
1134
1282
 
1283
+ ### `completionBatch`
1284
+
1285
+ ```json
1286
+ {
1287
+ "completionBatch": {
1288
+ "enabled": true,
1289
+ "debounceMs": 150,
1290
+ "maxWaitMs": 1000,
1291
+ "stragglerDebounceMs": 75,
1292
+ "stragglerMaxWaitMs": 400,
1293
+ "stragglerWindowMs": 2000
1294
+ }
1295
+ }
1296
+ ```
1297
+
1298
+ 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`.
1299
+
1300
+ 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.
1301
+
1135
1302
  ## Files, logs, and observability
1136
1303
 
1137
1304
  Each chain run creates a user-scoped temp directory like:
@@ -1142,7 +1309,7 @@ Each chain run creates a user-scoped temp directory like:
1142
1309
 
1143
1310
  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.
1144
1311
 
1145
- Debug artifacts live under `{sessionDir}/subagent-artifacts/` or a user-scoped temp artifact directory. Per task you may see:
1312
+ 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:
1146
1313
 
1147
1314
  - `{runId}_{agent}_input.md`
1148
1315
  - `{runId}_{agent}_output.md`
@@ -1153,7 +1320,7 @@ Metadata records timing, usage, exit code, final model, attempted models, and fa
1153
1320
 
1154
1321
  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.
1155
1322
 
1156
- Async completions notify only the originating session. The result watcher emits `subagent:async-complete`, and the extension consumes that event to render completion notifications.
1323
+ 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.
1157
1324
 
1158
1325
  Async runs write:
1159
1326
 
@@ -1165,7 +1332,7 @@ Async runs write:
1165
1332
  subagent-log-<id>.md
1166
1333
  ```
1167
1334
 
1168
- `status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. Nested fanout status is stored as compact sidecar event/registry metadata and merged into parent status views and result/intercom payloads; full recursive status snapshots are not embedded in parent result files. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
1335
+ `status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata, including `subagent.steer.requested` when live async steering is queued. Nested fanout status is stored as compact sidecar event/registry metadata and merged into parent status views and result/intercom payloads; full recursive status snapshots are not embedded in parent result files. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
1169
1336
 
1170
1337
  ## Acceptance Gates
1171
1338
 
@@ -1199,9 +1366,9 @@ For `attested` or stricter levels, the child prompt includes a standardized acce
1199
1366
 
1200
1367
  ## Live progress
1201
1368
 
1202
- Foreground runs show compact live progress for single, chain, and parallel modes: current tool, recent output, token counts, duration, activity freshness, current-tool duration, and chain graph metadata when available.
1369
+ Foreground runs show compact live progress for single, chain, and parallel modes: current tool, recent output, token counts, aggregate cost, duration, activity freshness, current-tool duration, and chain graph metadata when available.
1203
1370
 
1204
- Press `Ctrl+O` to expand the full streaming view with complete output per step.
1371
+ Press Pi's configured expand key (`Ctrl+O` by default) to expand the full streaming view with complete output per step.
1205
1372
 
1206
1373
  Sequential chains show a flow line like `done scout → running planner`. Chains with parallel steps show per-step cards instead. Chain status uses `label` and `phase` metadata when present, while falling back to agent names for older chains.
1207
1374
 
@@ -1247,13 +1414,13 @@ Intercom delivery events:
1247
1414
  - `subagent:control-intercom`
1248
1415
  - `subagent:result-intercom`
1249
1416
 
1250
- The result watcher emits `subagent:async-complete`; `src/extension/index.ts` registers the notification handler that consumes it. Control/attention events are surfaced as visible parent notices and persisted for async runs. With `pi-intercom`, needs-attention notices and grouped parent-side subagent result deliveries can reach the orchestrator over intercom.
1417
+ The result watcher emits `subagent:async-complete`; `src/extension/index.ts` registers the notification handler that consumes it. Control/attention events are surfaced as visible parent notices and persisted for async runs. Native supervisor requests are delivered only to the exact parent session that spawned the child.
1251
1418
 
1252
1419
  ## Prompt-template integration
1253
1420
 
1254
- `pi-subagents` works standalone through natural language, the `subagent` tool, slash commands, and the packaged prompt shortcuts listed near the top of this README. If you use [pi-prompt-template-model](https://github.com/nicobailon/pi-prompt-template-model), you can also wrap subagent delegation in your own reusable prompt templates.
1421
+ `pi-subagents` works standalone through natural language, the `subagent` tool, slash commands, and the packaged prompt shortcuts listed near the top of this README. It also includes a native prompt-workflow adapter for reusable subagent prompt templates, so you do not need `pi-prompt-template-model` for the common subagent workflow path.
1255
1422
 
1256
- Example:
1423
+ Create a prompt in `.pi/prompts/` or `~/.pi/agent/prompts/`:
1257
1424
 
1258
1425
  ```md
1259
1426
  ---
@@ -1265,9 +1432,21 @@ cwd: /tmp/screenshots
1265
1432
  Use url in the prompt to take screenshot: $@
1266
1433
  ```
1267
1434
 
1268
- Then `/take-screenshot https://example.com` switches to Sonnet, delegates to `browser-screenshoter` with `/tmp/screenshots` as cwd, and restores your model when done. Runtime overrides like `--cwd=<path>` and `--subagent=<name>` work too.
1435
+ Then run it through the native adapter:
1436
+
1437
+ ```text
1438
+ /prompt-workflow take-screenshot https://example.com
1439
+ ```
1440
+
1441
+ 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`.
1442
+
1443
+ For prompt-template chains, use:
1444
+
1445
+ ```text
1446
+ /chain-prompts analyze -> fix -- user arguments here
1447
+ ```
1269
1448
 
1270
- For more reusable workflows on top of subagents, including `/chain-prompts` and compare-style prompts such as `/best-of-n`, install `pi-prompt-template-model` separately and copy the examples you want into `~/.pi/agent/prompts/`.
1449
+ 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.
1271
1450
 
1272
1451
  ## Runtime files
1273
1452
 
@@ -1287,4 +1466,4 @@ The main runtime files are:
1287
1466
  | `src/runs/shared/worktree.ts` | Git worktree isolation. |
1288
1467
  | `src/intercom/intercom-bridge.ts` | Runtime intercom bridge instructions and diagnostics. |
1289
1468
  | `src/extension/schemas.ts` / `src/shared/types.ts` | Tool schemas, shared types, and event constants. |
1290
- | `test/unit/` / `test/integration/` | Unit and loader-based integration tests. |
1469
+ | `test/unit/` / `test/integration/` / `test/e2e/` | Unit, loader-based integration, and real-session E2E tests. |
package/install.mjs CHANGED
@@ -85,8 +85,9 @@ if (fs.existsSync(EXTENSION_DIR)) {
85
85
  }
86
86
 
87
87
  console.log(`
88
- The extension is now available in pi. Tool added:
88
+ The extension is now available in pi. Tools added:
89
89
  • subagent - Delegate tasks to agents and inspect run status
90
+ • wait - Block until background subagent runs finish (delivers their results)
90
91
 
91
92
  Documentation: ${EXTENSION_DIR}/README.md
92
93
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.31.1",
3
+ "version": "0.33.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",
@@ -38,7 +38,8 @@
38
38
  "test": "npm run test:unit",
39
39
  "test:unit": "node --experimental-strip-types --test test/unit/*.test.ts",
40
40
  "test:integration": "node --experimental-transform-types --import ./test/support/register-loader.mjs --test test/integration/*.test.ts",
41
- "test:all": "npm run test:unit && npm run test:integration"
41
+ "test:e2e": "node --experimental-transform-types --import ./test/support/register-loader.mjs --test test/e2e/*.test.ts",
42
+ "test:all": "npm run test:unit && npm run test:integration && npm run test:e2e"
42
43
  },
43
44
  "pi": {
44
45
  "extensions": [