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.
- package/CHANGELOG.md +78 -9
- package/README.md +213 -32
- package/index.ts +1 -0
- package/install.mjs +1 -1
- package/package.json +23 -8
- package/prompts/review-loop.md +3 -1
- package/skills/pi-subagents/SKILL.md +87 -25
- package/src/agents/agent-management.ts +82 -15
- package/src/agents/agent-serializer.ts +19 -0
- package/src/agents/agents.ts +91 -49
- package/src/agents/frontmatter.ts +67 -13
- package/src/agents/skills.ts +25 -12
- package/src/api/background-work.ts +197 -0
- package/src/api/delegation.ts +158 -0
- package/src/extension/chain-validation.ts +165 -0
- package/src/extension/doctor.ts +15 -0
- package/src/extension/fanout-child.ts +3 -1
- package/src/extension/index.ts +65 -124
- package/src/extension/rpc.ts +10 -2
- package/src/extension/schemas.ts +18 -14
- package/src/extension/steering-notices.ts +35 -0
- package/src/extension/tool-description.ts +20 -9
- package/src/intercom/intercom-bridge.ts +3 -2
- package/src/intercom/native-supervisor-channel.ts +9 -1
- package/src/intercom/result-intercom.ts +4 -0
- package/src/runs/background/async-execution.ts +293 -44
- package/src/runs/background/async-job-tracker.ts +56 -9
- package/src/runs/background/async-resume.ts +159 -52
- package/src/runs/background/async-status.ts +25 -18
- package/src/runs/background/auto-drain.ts +67 -0
- package/src/runs/background/chain-root-attachment.ts +16 -8
- package/src/runs/background/control-channel.ts +260 -13
- package/src/runs/background/fleet-view.ts +23 -2
- package/src/runs/background/notify.ts +79 -10
- package/src/runs/background/result-watcher.ts +12 -9
- package/src/runs/background/run-id-resolver.ts +14 -2
- package/src/runs/background/run-status.ts +23 -15
- package/src/runs/background/scheduled-runs.ts +3 -0
- package/src/runs/background/stale-run-reconciler.ts +32 -10
- package/src/runs/background/steering.ts +237 -0
- package/src/runs/background/subagent-runner.ts +898 -236
- package/src/runs/background/subagent-wait.ts +484 -0
- package/src/runs/background/top-level-async.ts +2 -1
- package/src/runs/background/wait-config.ts +36 -0
- package/src/runs/background/wait-tool.ts +26 -0
- package/src/runs/foreground/async-steering-action.ts +230 -0
- package/src/runs/foreground/chain-clarify.ts +22 -6
- package/src/runs/foreground/chain-execution.ts +50 -32
- package/src/runs/foreground/execution.ts +308 -94
- package/src/runs/foreground/subagent-executor.ts +592 -268
- package/src/runs/shared/acceptance.ts +355 -97
- package/src/runs/shared/child-protocol.ts +121 -0
- package/src/runs/shared/completion-guard.ts +8 -127
- package/src/runs/shared/dynamic-fanout.ts +6 -4
- package/src/runs/shared/model-fallback.ts +36 -0
- package/src/runs/shared/nested-events.ts +9 -4
- package/src/runs/shared/nested-render.ts +4 -1
- package/src/runs/shared/parallel-utils.ts +7 -0
- package/src/runs/shared/pi-args.ts +34 -7
- package/src/runs/shared/pi-spawn.ts +18 -12
- package/src/runs/shared/session-lease.ts +279 -0
- package/src/runs/shared/single-output.ts +61 -6
- package/src/runs/shared/spawn-budget.ts +128 -0
- package/src/runs/shared/subagent-control.ts +10 -6
- package/src/runs/shared/subagent-prompt-runtime.ts +127 -26
- package/src/runs/shared/task-intent.ts +176 -0
- package/src/runs/shared/tool-availability.ts +65 -0
- package/src/runs/shared/turn-budget.ts +49 -4
- package/src/shared/atomic-json.ts +4 -1
- package/src/shared/fork-context.ts +28 -3
- package/src/shared/model-info.ts +7 -4
- package/src/shared/status-format.ts +7 -1
- package/src/shared/types.ts +203 -25
- package/src/shared/utils.ts +35 -7
- package/src/slash/delegation-adapters.ts +457 -0
- package/src/slash/delegation-request.ts +103 -0
- package/src/slash/prompt-template-bridge.ts +167 -344
- package/src/slash/slash-commands.ts +239 -6
- package/src/slash/subagents-admin.ts +428 -0
- package/src/slash/subagents-editor.ts +86 -0
- package/src/tui/fleet.ts +405 -0
- package/src/tui/render.ts +90 -16
- package/src/watchdog/change-signature.ts +127 -0
- package/src/watchdog/child-status.ts +205 -0
- package/src/watchdog/emission-guard.ts +123 -0
- package/src/watchdog/lsp-diagnostics.ts +532 -0
- package/src/watchdog/model-selection.ts +167 -0
- package/src/watchdog/register-child.ts +117 -0
- package/src/watchdog/register-main.ts +433 -0
- package/src/watchdog/render.ts +54 -0
- package/src/watchdog/review.ts +293 -0
- package/src/watchdog/runtime.ts +712 -0
- package/src/watchdog/settings.ts +528 -0
- package/src/watchdog/tool-actions.ts +155 -0
- package/src/watchdog/turn-delta.ts +161 -0
- package/src/watchdog/types.ts +188 -0
- package/src/watchdog/warning-format.ts +73 -0
- package/src/runs/background/wait.ts +0 -394
package/README.md
CHANGED
|
@@ -170,6 +170,61 @@ That reports the live runtime mapping, which can differ from settings on disk un
|
|
|
170
170
|
|
|
171
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
172
|
|
|
173
|
+
### Choosing a watchdog model
|
|
174
|
+
|
|
175
|
+
The subagent watchdog is not the `reviewer` subagent. `subagents.defaultModel` and `subagents.agentOverrides.reviewer` do not configure it. The watchdog is an opt-in adversarial change reviewer, so it should usually use a strong complementary model rather than a cheap/light model.
|
|
176
|
+
|
|
177
|
+
The watchdog reviews repo edits, not ordinary conversation. It runs at the safe `agent_end` boundary only when the current agent or child writer changed the final repo state since the start of that turn. Multiple edits in one turn are coalesced into one review of the final changed state, unchanged/reverted diffs are skipped, and generated `.pi-subagents/` or `tmp/` artifacts do not trigger review. In orchestrated runs, each writing child can review its own edited worktree, and the parent can still review the aggregate repo diff after child changes are applied.
|
|
178
|
+
|
|
179
|
+
When the watchdog is enabled, it also checks changed TypeScript and JavaScript files for fresh language-server diagnostics before the model review. It auto-detects `typescript-language-server` from the project `node_modules/.bin` or `PATH`; it never installs tools or scans the whole workspace. LSP errors surface as watchdog blockers, warnings as concerns, and info/hints stay in status details. Slow or missing servers are reported in `/subagents-watchdog status` without blocking the turn or emitting late mid-turn warnings. Configure the bounds with `subagents.watchdog.lsp.enabled`, `timeoutMs`, `maxFiles`, and `maxDiagnostics`.
|
|
180
|
+
|
|
181
|
+
Use `/subagents-watchdog recommend-model` to ask pi-subagents for the current strong pairing. The current recommendation policy is Opus 4.8 with thinking high or GPT 5.5 with thinking high. If your main session is using one, the watchdog should use the other when that model is authenticated.
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
/subagents-watchdog recommend-model
|
|
185
|
+
/subagents-watchdog session model recommended
|
|
186
|
+
/subagents-watchdog model recommended
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`session model recommended` changes only the current Pi session. `model recommended` saves the recommendation to `~/.pi/agent/settings.json`; it does not turn the watchdog on. Enable it separately with `/subagents-watchdog on` when you want the extra review pass.
|
|
190
|
+
|
|
191
|
+
You can also set the model explicitly:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
/subagents-watchdog model anthropic/claude-opus-4-8:high
|
|
195
|
+
/subagents-watchdog model openai-codex/gpt-5.5:high
|
|
196
|
+
/subagents-watchdog model inherit
|
|
197
|
+
/subagents-watchdog check
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
For settings files, use `subagents.watchdog.main.model` and `subagents.watchdog.main.thinking` for the main watchdog. If `main.model` is omitted, the main watchdog uses the current session model and thinking level. If `main.model` is set without a thinking suffix or `main.thinking`, it runs with thinking off, so prefer `:high` or `"thinking": "high"` for the strong-watchdog pairing.
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"subagents": {
|
|
205
|
+
"watchdog": {
|
|
206
|
+
"enabled": true,
|
|
207
|
+
"main": {
|
|
208
|
+
"model": "anthropic/claude-opus-4-8",
|
|
209
|
+
"thinking": "high"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For child subagent watchdogs, use `subagents.watchdog.children.model` as the default child watchdog model, or `subagents.watchdog.children.overrides.<agent>.model` for a specific child role. Child watchdogs are still opt-in and follow the same edit-gated rule: read-only children do not trigger watchdog reviews, while writer children are reviewed at their own `agent_end` if their worktree changed.
|
|
217
|
+
|
|
218
|
+
Agents can configure the same values through the tool when you ask them to set up the watchdog:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
subagent({ action: "watchdog.recommend-model" })
|
|
222
|
+
subagent({ action: "watchdog.configure", model: "recommended", scope: "session" })
|
|
223
|
+
subagent({ action: "watchdog.configure", model: "recommended", scope: "project" })
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Persistent scopes (`user` or `project`) should only be used when you ask for a lasting default. Otherwise the agent should use `scope: "session"`.
|
|
227
|
+
|
|
173
228
|
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
229
|
|
|
175
230
|
```json
|
|
@@ -189,7 +244,7 @@ To keep subagents inside a budget or compliance profile, enforce a model scope.
|
|
|
189
244
|
|
|
190
245
|
Foreground runs stream progress in the conversation while they run.
|
|
191
246
|
|
|
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: "..." })`.
|
|
247
|
+
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: "..." })`. `/subagents-fleet` opens a live, inspection-only fleet with current-session foreground work, recent async children, transcript tails, and completed output/session paths. Use `↑`/`↓` or `j`/`k` to select a child, `PgUp`/`PgDn` to scroll its transcript, `r` to refresh immediately, and `Esc` to close. `Ctrl+Alt+F` opens the same inspector even while a foreground turn is active and slash input is queued. Without a TUI, `/subagents-fleet` retains the textual `subagent({ action: "status", view: "fleet" })` fallback. Mutations stay in explicit commands: run `/subagents-stop` and pick from the selector, or use `/subagents-stop <run-id>` / `subagent({ action: "stop", id: "..." })` when you already know the id. To inspect one background child in text, use `subagent({ action: "status", id: "...", view: "transcript" })`; add `index` for a specific child in a parallel or chain run.
|
|
193
248
|
|
|
194
249
|
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.
|
|
195
250
|
|
|
@@ -201,7 +256,9 @@ Show me the current async runs.
|
|
|
201
256
|
|
|
202
257
|
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
258
|
|
|
204
|
-
|
|
259
|
+
Foreground and async runners share bounded child-protocol handling. A child JSONL line above 4 MiB fails with structured `protocolError` code `protocol_output_limit`, stderr retains only its latest 128 KiB, split UTF-8 and final unterminated JSON events remain valid, and `agent_end.willRetry` defers completion until the child settles. Current Pi builds use `agent_settled` as the terminal watermark; older builds retain the bounded terminal-message fallback.
|
|
260
|
+
|
|
261
|
+
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`/`stopped`, control attention events, nested interrupt failures, and `subagent.run.completed`/`stopped`; run boundary events include the lifecycle artifact version. Consumers should read these JSON files instead of scraping terminal output; unknown fields and event types should be ignored for forward compatibility.
|
|
205
262
|
|
|
206
263
|
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
264
|
|
|
@@ -219,7 +276,7 @@ pi.events.emit("subagents:rpc:v1:request", {
|
|
|
219
276
|
});
|
|
220
277
|
```
|
|
221
278
|
|
|
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
|
|
279
|
+
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, configured spawn caps, child-safety depth, artifacts, and async status all behave the same. `stop` targets current-session top-level async runs through the stop control channel and records a `stopped` lifecycle instead of reporting a timeout.
|
|
223
280
|
|
|
224
281
|
`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
282
|
|
|
@@ -382,8 +439,10 @@ Skip this section until you want exact syntax.
|
|
|
382
439
|
| `/parallel agent1 "task1" -> agent2 "task2"` | Run agents in parallel |
|
|
383
440
|
| `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` or `.chain.json` workflow |
|
|
384
441
|
| `/subagent-cost` | Show parent plus child subagent token usage and cost for this session |
|
|
442
|
+
| `/subagents [agent] [model\|thinking\|prompt\|details]` | Interactively inspect or edit an agent's model, thinking level, or system prompt |
|
|
385
443
|
| `/subagents-doctor` | Show read-only setup diagnostics |
|
|
386
444
|
| `/subagents-models [agent]` | Show the runtime-loaded builtin model mapping, optionally filtered to one builtin |
|
|
445
|
+
| `/subagents-watchdog [status|on|off|recommend-model|model ...|session model ...|check]` | Show or configure the opt-in watchdog; use a strong complementary model such as Opus 4.8 high or GPT 5.5 high |
|
|
387
446
|
| `/subagents-profiles` | List saved subagent profiles from `~/.pi/agent/profiles/pi-subagents/` |
|
|
388
447
|
| `/subagents-load-profile <name>` | Replace only `settings.subagents` with a saved profile and optionally switch this session to the profile worker model |
|
|
389
448
|
| `/subagents-refresh-provider-models <provider> [--force]` | Create or refresh the cached provider model catalog |
|
|
@@ -392,6 +451,8 @@ Skip this section until you want exact syntax.
|
|
|
392
451
|
|
|
393
452
|
Commands validate agent names locally, support tab completion, and send results back into the conversation.
|
|
394
453
|
|
|
454
|
+
`/subagents` opens a compact administration flow for builtin, package, user, and project agents. Model choices refresh Pi's model registry first, thinking choices are filtered to levels declared by the selected model, and prompt editing uses a blocking `$VISUAL`/`$EDITOR` command (with MarkEdit as the macOS fallback). Full metadata is opt-in through `details`. Edits are persisted to the field-owning layer: explicit custom-agent frontmatter remains in the agent file, while settings/profile-managed fields remain in `settings.subagents.agentOverrides`. Package-owned fields and definitions loaded through `PI_SUBAGENT_EXTRA_AGENT_DIRS` stay read-only; settings can still supply model or thinking fields omitted by a package definition.
|
|
455
|
+
|
|
395
456
|
### Profiles and provider model catalogs
|
|
396
457
|
|
|
397
458
|
Profiles are stored under:
|
|
@@ -502,7 +563,7 @@ Append `[key=value,...]` to an agent name to override defaults. `/chain` applies
|
|
|
502
563
|
| `cwd` | `cwd=packages/api` | Run the step in a subdirectory. |
|
|
503
564
|
| `count` | `count=3` | Fan a group task into N copies (only inside a `( ... )` group). |
|
|
504
565
|
| `outputSchema` | `outputSchema=schema.json` | Validate structured output against a JSON Schema file (path resolved against the session cwd, not an inline step `cwd`). |
|
|
505
|
-
| `acceptance` | `acceptance=checked` | Inline acceptance level: `auto`, `attested`, or `checked`. Use the tool API or saved `.chain.json` for object contracts such as `none
|
|
566
|
+
| `acceptance` | `acceptance=checked` | Inline acceptance level: `auto`, `attested`, or `checked`. Use the tool API or saved `.chain.json` for object contracts such as `none` or `verified`; `reviewed` is inferred-only. |
|
|
506
567
|
|
|
507
568
|
Set `output=false`, `reads=false`, or `skills=false` to disable that behavior explicitly. Do not use `output=false` for file-only returns; use `outputMode=file-only` with an `output` path.
|
|
508
569
|
|
|
@@ -533,9 +594,11 @@ You can combine them in either order:
|
|
|
533
594
|
/run reviewer "review this diff" --bg --fork
|
|
534
595
|
```
|
|
535
596
|
|
|
536
|
-
Background runs are detached. If the parent agent has other independent work, it should keep working.
|
|
597
|
+
Background runs are detached. If the parent agent has other independent work, it should keep working. In an interactive chat, it should normally return control when ready to yield and let Pi deliver the completion notification instead of blocking merely to wait. Override that default and use `subagent_wait` when the current request is run-to-completion — for example, the user asked you to report results back before continuing or a skill cannot return before its work finishes. In a non-interactive run, Pi auto-drains current-session work at `agent_end`; use `subagent_wait` when this turn must receive results before it ends. It returns when the next initially active run or registered provider item finishes or a subagent needs attention; use `subagent_wait({ all: true })` for all work active at call time, `subagent_wait({ id })` for one async or remembered detached foreground run, and `subagent_wait({ timeoutMs })` to cap the block.
|
|
537
598
|
|
|
538
|
-
|
|
599
|
+
A foreground child can detach while it waits for a supervisor reply. Reply first, then call `subagent_wait({ id: runId })`. The remembered run stays pending until the child exits, then emits a session-scoped completion notification with recovered output and remains inspectable through `subagent({ action: "status", id: runId })`. Do not call `resume` or launch a replacement while the child remains detached.
|
|
600
|
+
|
|
601
|
+
Headless sessions also auto-drain current-session subagent and registered provider work at `agent_end`, using one absolute timeout and continuing through attention states. This is a final lifecycle safeguard rather than a replacement for explicit orchestration: `subagent_wait` still lets a model react to each result during the turn. Provider, reconciliation, timeout, and malformed-state failures remain visible errors instead of being treated as successful drains.
|
|
539
602
|
|
|
540
603
|
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.
|
|
541
604
|
|
|
@@ -602,7 +665,7 @@ Example:
|
|
|
602
665
|
}
|
|
603
666
|
```
|
|
604
667
|
|
|
605
|
-
Supported override fields are `model`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`, `disabled`, `skills`, `tools`, and `systemPrompt`. Use `defaultContext: false`
|
|
668
|
+
Supported override fields are `model`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`, `acceptanceRole`, `disabled`, `skills`, `tools`, and `systemPrompt`. Use `defaultContext: false` or `acceptanceRole: false` to clear an inherited override. Project overrides beat user overrides.
|
|
606
669
|
|
|
607
670
|
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
671
|
|
|
@@ -644,10 +707,16 @@ thinking: high
|
|
|
644
707
|
systemPromptMode: replace
|
|
645
708
|
inheritProjectContext: false
|
|
646
709
|
inheritSkills: false
|
|
647
|
-
skills: safe-bash,
|
|
710
|
+
skills: safe-bash, review-checklist
|
|
711
|
+
skillPath: ./skills, ../shared-skills
|
|
648
712
|
output: context.md
|
|
649
713
|
defaultReads: context.md
|
|
650
714
|
defaultProgress: true
|
|
715
|
+
async: true
|
|
716
|
+
timeoutMs: 900000
|
|
717
|
+
turnBudget: {"maxTurns":20,"graceTurns":2}
|
|
718
|
+
acceptance: {"level":"none","reason":"lightweight lookup"}
|
|
719
|
+
acceptanceRole: read-only
|
|
651
720
|
completionGuard: false
|
|
652
721
|
interactive: true
|
|
653
722
|
maxSubagentDepth: 1
|
|
@@ -656,14 +725,25 @@ maxSubagentDepth: 1
|
|
|
656
725
|
Your system prompt goes here.
|
|
657
726
|
```
|
|
658
727
|
|
|
728
|
+
Simple-scalar list fields accept either the existing comma-separated form or a newline block list with one `- item` per line. This applies to `tools`, `defaultReads`, `skill`/`skills`, `skillPath`, `fallbackModels`, `extensions`, and `subagentOnlyExtensions`; for example:
|
|
729
|
+
|
|
730
|
+
```yaml
|
|
731
|
+
tools:
|
|
732
|
+
- read
|
|
733
|
+
- mcp:github/search_repositories
|
|
734
|
+
fallbackModels:
|
|
735
|
+
- openai/gpt-5-mini
|
|
736
|
+
- anthropic/claude-sonnet-4
|
|
737
|
+
```
|
|
738
|
+
|
|
659
739
|
Important fields:
|
|
660
740
|
|
|
661
741
|
| Field | Notes |
|
|
662
742
|
|-------|-------|
|
|
663
743
|
| `package` | Optional package identifier. A file with `name: scout` and `package: code-analysis` registers as `code-analysis.scout`; serialization keeps `name` and `package` separate. |
|
|
664
|
-
| `tools` |
|
|
665
|
-
| `extensions` | Omitted means normal extensions; empty means no extensions;
|
|
666
|
-
| `subagentOnlyExtensions` |
|
|
744
|
+
| `tools` | Strict child tool allowlist. Named extension tools must also have their provider loaded. `mcp:` entries select direct MCP tools when `pi-mcp-adapter` is installed. |
|
|
745
|
+
| `extensions` | Omitted means normal extensions; empty means no extensions; list values allowlist specific extensions. |
|
|
746
|
+
| `subagentOnlyExtensions` | Extension paths loaded only in spawned child sessions for this agent. Tools registered there are unavailable to the main agent unless also installed through normal Pi extension configuration. |
|
|
667
747
|
| `model` | Default model. Bare ids prefer the current provider when possible, then unique registry matches. |
|
|
668
748
|
| `fallbackModels` | Ordered backup models for provider/model failures such as quota, auth, timeout, or unavailable model. Ordinary task failures do not trigger fallback. |
|
|
669
749
|
| `thinking` | Appended as a `:level` suffix at runtime unless a suffix is already present. |
|
|
@@ -671,15 +751,23 @@ Important fields:
|
|
|
671
751
|
| `inheritProjectContext` | Keeps or strips inherited project instruction blocks. |
|
|
672
752
|
| `inheritSkills` | Keeps or strips Pi’s discovered skills catalog. |
|
|
673
753
|
| `defaultContext` | Optional `fresh` or `fork` launch context default for this agent. |
|
|
674
|
-
| `skills` |
|
|
754
|
+
| `skills` | Selects specific skills for the child, regardless of `inheritSkills`. |
|
|
755
|
+
| `skillPath` | Invocation-private skill files or discovery directories. Relative paths resolve from the agent definition file. Local matches take precedence, while unresolved or unreadable matches fall back to normal skill discovery. This field discovers candidates only; `skills` still selects what the child receives. |
|
|
675
756
|
| `output` | Default single-agent output file. |
|
|
676
757
|
| `defaultReads` | Files to read before running in chain/parallel behavior. |
|
|
677
758
|
| `defaultProgress` | Maintain `progress.md`. |
|
|
759
|
+
| `async` | Default a single-agent launch to background (`true`) or foreground (`false`) when the call omits `async`. Explicit call values and `forceTopLevelAsync` win. |
|
|
760
|
+
| `timeoutMs` | Positive integer default runtime deadline in milliseconds for single-agent launches. An explicit `timeoutMs` or `maxRuntimeMs` wins. |
|
|
761
|
+
| `turnBudget` | JSON object default such as `{"maxTurns":20,"graceTurns":2}` for single-agent launches. An explicit call value wins, followed by this agent default, then global `turnBudget` config. |
|
|
762
|
+
| `acceptance` | Acceptance default for single-agent launches. Use a scalar level such as `checked` or an inline/block YAML map such as `{ level: "none", reason: "lightweight lookup" }`. Explicit call values win; chain and parallel acceptance remains task/step configuration. |
|
|
763
|
+
| `acceptanceRole` | Optional `read-only` or `writer` role for automatic acceptance inference. Explicit task mutation or no-edit intent wins; otherwise the declared role replaces agent-name guessing. This does not grant or revoke tools. |
|
|
678
764
|
| `completionGuard` | Set `false` only for non-implementation agents that may mention implementation words while using mutation-capable tools such as `bash`. |
|
|
679
765
|
| `interactive` | Parsed for compatibility but not enforced in v1. |
|
|
680
766
|
| `maxSubagentDepth` | Tightens nested delegation for this agent's children. |
|
|
681
767
|
| `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
768
|
|
|
769
|
+
Agent-local `skillPath` candidates never enter Pi's parent/global skills catalog. Pair `inheritSkills: false` with explicit `skills` and `skillPath` when a child should receive only its selected private skills.
|
|
770
|
+
|
|
683
771
|
### Per-agent persistent memory
|
|
684
772
|
|
|
685
773
|
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.
|
|
@@ -696,7 +784,7 @@ Project-scoped memory resolves under `<project>/.pi/agent-memory/<path>` and tra
|
|
|
696
784
|
|
|
697
785
|
### Tool and extension selection
|
|
698
786
|
|
|
699
|
-
If `tools` is omitted, `pi-subagents` does not pass `--tools`, so the child gets Pi’s normal builtin tools. If `tools` is present, regular tool names become an explicit allowlist. `mcp:` entries are split out and forwarded as direct MCP selections. Path-like `tools` entries, such as extension paths or `.ts`/`.js` files, are treated as tool-extension paths rather than
|
|
787
|
+
If `tools` is omitted, `pi-subagents` does not pass `--tools`, so the child gets Pi’s normal builtin tools. If `tools` is present, regular tool names become an explicit allowlist. An allowlisted name does not load the extension that registers it: load that provider through normal Pi extension discovery, `extensions`, `subagentOnlyExtensions`, or a path-like `tools` entry. `mcp:` entries are split out and forwarded as direct MCP selections. Path-like `tools` entries, such as extension paths or `.ts`/`.js` files, are treated as tool-extension paths rather than tool names. Internal runtime tools such as `structured_output` are added to an explicit allowlist only when their contract is active. Agents that declare only known read-only builtin tools skip the implementation completion guard, but `bash`, unknown tools, and MCP tools stay mutation-capable. Use `completionGuard: false` for bash-enabled validators or advisors that should never be judged as implementation agents.
|
|
700
788
|
|
|
701
789
|
Examples:
|
|
702
790
|
|
|
@@ -704,6 +792,7 @@ Examples:
|
|
|
704
792
|
- `tools: mcp:chrome-devtools`: normal builtins plus direct Chrome DevTools MCP tools.
|
|
705
793
|
- `tools: read, bash, mcp:chrome-devtools`: only `read` and `bash` as builtins, plus direct Chrome DevTools MCP tools.
|
|
706
794
|
- `tools: subagent, read`: a child-safe `subagent` tool is available inside that child so it can run explicitly assigned nested fanout.
|
|
795
|
+
- `tools: read, fixture_search` plus `subagentOnlyExtensions: ./tools/fixture-search.ts`: the provider loads only in this agent's child process, and the registered `fixture_search` name survives the strict allowlist.
|
|
707
796
|
|
|
708
797
|
Direct MCP tools require [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter). Subagents only receive direct MCP tools when `mcp:` entries are listed in their frontmatter; global `directTools: true` in `mcp.json` is not enough by itself. The generic `mcp` proxy tool can still be used for discovery when available. The adapter caches tool metadata at startup, so after connecting a new MCP server for the first time, restart Pi before relying on direct tools. An `mcp:` entry named `subagent` does not authorize nested fanout; only the builtin `subagent` tool name does.
|
|
709
798
|
|
|
@@ -719,10 +808,12 @@ extensions:
|
|
|
719
808
|
extensions: /abs/path/to/ext-a.ts, /abs/path/to/ext-b.ts
|
|
720
809
|
```
|
|
721
810
|
|
|
722
|
-
When `extensions` is present,
|
|
811
|
+
When `extensions` is present, normal discovered extensions are disabled; the listed extensions, path-like `tools` entries, required pi-subagents runtime extensions, and `subagentOnlyExtensions` still load.
|
|
723
812
|
|
|
724
813
|
Use `subagentOnlyExtensions` when a custom extension tool should exist only inside child sessions. It is scoped by agent config: every run of that agent receives those extension paths, while other agents do not unless they declare the same field. The current model does not have a separate named-subagent audience inside one agent definition.
|
|
725
814
|
|
|
815
|
+
Before the first model turn, the child runtime compares every explicit tool name with Pi's final filtered registry. A missing provider now fails the run with the unavailable names and concrete `subagentOnlyExtensions`/`extensions` guidance instead of letting a direct or chained child silently continue without its requested tools.
|
|
816
|
+
|
|
726
817
|
## Chain files
|
|
727
818
|
|
|
728
819
|
Chains are reusable workflows stored separately from agent files. Use `.chain.md` for simple sequential saved chains. Use `.chain.json` when a chain needs dynamic fanout.
|
|
@@ -889,6 +980,69 @@ What the bundled skill covers:
|
|
|
889
980
|
|
|
890
981
|
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.
|
|
891
982
|
|
|
983
|
+
## Extension delegation API
|
|
984
|
+
|
|
985
|
+
Pi extensions can request one configured foreground agent through the typed v1 event contract:
|
|
986
|
+
|
|
987
|
+
```ts
|
|
988
|
+
import {
|
|
989
|
+
SUBAGENT_DELEGATION_REQUEST_EVENT,
|
|
990
|
+
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
991
|
+
type SubagentDelegationRequest,
|
|
992
|
+
type SubagentDelegationResponse,
|
|
993
|
+
} from "pi-subagents/delegation";
|
|
994
|
+
|
|
995
|
+
const request: SubagentDelegationRequest = {
|
|
996
|
+
version: 1,
|
|
997
|
+
requestId: crypto.randomUUID(),
|
|
998
|
+
agent: "reviewer",
|
|
999
|
+
task: "Review the supplied evidence.",
|
|
1000
|
+
context: "fresh",
|
|
1001
|
+
cwd: ctx.cwd,
|
|
1002
|
+
timeoutMs: 120_000,
|
|
1003
|
+
toolBudget: { soft: 10, hard: 16, block: "*" },
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
const unsubscribe = pi.events.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => {
|
|
1007
|
+
const response = payload as SubagentDelegationResponse;
|
|
1008
|
+
if (response.requestId !== request.requestId) return;
|
|
1009
|
+
unsubscribe();
|
|
1010
|
+
// Inspect response.status and the metadata present for this run.
|
|
1011
|
+
});
|
|
1012
|
+
pi.events.emit(SUBAGENT_DELEGATION_REQUEST_EVENT, request);
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
The contract uses the established `prompt-template:subagent:*` event transport and the same executor as the `subagent` tool; it does not add another launcher. New integrations must send `version: 1`. Requests are strict and single-agent only. They can set fresh or fork context, model, cwd, timeout, turn and tool-call budgets, skills, output behavior, acceptance, and artifact capture. Unknown or malformed fields return `invalid_request` before execution.
|
|
1016
|
+
|
|
1017
|
+
Responses distinguish completion, failure, timeout, cancellation, interruption, turn or tool-budget exhaustion, explicit acceptance failure, invalid requests, and unavailable active context. Optional run, model, output, session, acceptance, usage, progress, and warning fields are omitted when unavailable. Request IDs must be unique while active; duplicate active IDs are ignored so the original request keeps ownership of its terminal response. Emit `SUBAGENT_DELEGATION_CANCEL_EVENT` with the same version and request ID to cancel queued or active work.
|
|
1018
|
+
|
|
1019
|
+
Delegation requires an active extension context. Emit requests from a supported event callback or queued application step, not by recursively invoking the `subagent` tool inside another tool's `tool_call` hook. The caller selects a configured agent, but agent discovery and effective tools remain package-owned. A request cannot grant arbitrary tools, and tool restrictions are not an operating-system sandbox. The detached RPC remains async-only; this API is foreground-only.
|
|
1020
|
+
|
|
1021
|
+
Existing prompt-template payloads continue over the same event family, including their parallel-only adapter. `pi-subagents/delegation` is the canonical contract for new extension integrations.
|
|
1022
|
+
|
|
1023
|
+
## Background-work provider API
|
|
1024
|
+
|
|
1025
|
+
Other Pi extensions can make their current-session jobs visible to `subagent_wait` through the versioned process-local provider contract:
|
|
1026
|
+
|
|
1027
|
+
```ts
|
|
1028
|
+
import { registerBackgroundWorkProvider } from "pi-subagents/background-work";
|
|
1029
|
+
|
|
1030
|
+
const dispose = registerBackgroundWorkProvider({
|
|
1031
|
+
name: "my-background-extension",
|
|
1032
|
+
wakeChannels: ["my-extension:job-finished"],
|
|
1033
|
+
listActiveWork: () => jobs
|
|
1034
|
+
.filter((job) => job.status === "running")
|
|
1035
|
+
.map((job) => ({ id: job.id, sessionId: job.ownerSessionId })),
|
|
1036
|
+
reconcile: ({ sessionId, nowMs }) => reconcileJobs(sessionId, nowMs),
|
|
1037
|
+
});
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
Each item needs a stable provider-local ID and the exact Pi session ID that owns it. `subagent_wait` captures those identities rather than a count, so one job finishing while another starts still satisfies first-completion waits without losing the replacement. It filters snapshots to the active session, fails closed if a provider disappears while its work is tracked, and surfaces malformed snapshots or provider errors with provider context. Wake channels only shorten polling; validated snapshots remain authoritative.
|
|
1041
|
+
|
|
1042
|
+
Providers share a registry through `Symbol.for("pi-subagents.background-work.v1")`, allowing independently loaded extension modules to meet in one Pi process. Registration is reload-safe: a new provider with the same name replaces the old callback, and the old disposer cannot remove the replacement. Call the disposer during extension shutdown when possible.
|
|
1043
|
+
|
|
1044
|
+
Child processes do not gain provider tools or extensions automatically. Add `subagent_wait` to the child agent's `tools` allowlist and load each provider through `extensions` or `subagentOnlyExtensions`. The parent's effective `waitTool` setting is serialized through foreground, async, resume, chain, parallel, and fanout launch paths; `PI_SUBAGENT_WAIT_TOOL_ENABLED` keeps precedence.
|
|
1045
|
+
|
|
892
1046
|
## Programmatic tool usage
|
|
893
1047
|
|
|
894
1048
|
These are the parameters the LLM passes when it calls the `subagent` tool. Most users ask naturally or use slash commands instead.
|
|
@@ -1001,6 +1155,8 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
1001
1155
|
extensions: "",
|
|
1002
1156
|
skills: "parallel-scout",
|
|
1003
1157
|
thinking: "high",
|
|
1158
|
+
acceptance: { level: "none", reason: "lightweight lookup" },
|
|
1159
|
+
acceptanceRole: "read-only",
|
|
1004
1160
|
output: "context.md",
|
|
1005
1161
|
reads: "shared-context.md",
|
|
1006
1162
|
progress: true
|
|
@@ -1017,6 +1173,8 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
1017
1173
|
}}
|
|
1018
1174
|
|
|
1019
1175
|
{ action: "update", agent: "code-analysis.scout", config: { model: "openai/gpt-4o" } }
|
|
1176
|
+
{ action: "update", agent: "code-analysis.scout", config: { acceptance: "" } } // clear the frontmatter default
|
|
1177
|
+
{ action: "update", agent: "code-analysis.scout", config: { acceptanceRole: false } } // restore inferred name fallback
|
|
1020
1178
|
{ action: "update", chainName: "review-pipeline", config: { steps: [...] } }
|
|
1021
1179
|
{ action: "delete", agent: "scout" }
|
|
1022
1180
|
{ action: "delete", chainName: "review-pipeline" }
|
|
@@ -1038,7 +1196,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
1038
1196
|
|-------|------|---------|-------------|
|
|
1039
1197
|
| `agent` | string | - | Agent name for single mode, or target for management actions. |
|
|
1040
1198
|
| `task` | string | - | Task string for single mode. |
|
|
1041
|
-
| `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `interrupt`, `resume`, `steer`, `append-step`, or `doctor`. |
|
|
1199
|
+
| `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `interrupt`, `stop`, `resume`, `steer`, `append-step`, or `doctor`. |
|
|
1042
1200
|
| `chainName` | string | - | Chain name for management actions. |
|
|
1043
1201
|
| `config` | object/string | - | Agent or chain config for create/update. |
|
|
1044
1202
|
| `output` | `string \| false` | agent default | Override single-agent output file. |
|
|
@@ -1057,19 +1215,23 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
1057
1215
|
| `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
|
|
1058
1216
|
| `async` | boolean | false | Background execution. For chains, `clarify: true` explicitly keeps the run foreground for the clarify UI. |
|
|
1059
1217
|
| `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
|
|
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`,
|
|
1218
|
+
| `turnBudget` | object | none | Optional assistant-turn budget `{ maxTurns, graceTurns }`. At `maxTurns` the child is warned to wrap up. After the grace window (default 1), termination occurs at the next assistant boundary; a response that starts tool work records `termination-deferred` until a later boundary. Partial output is returned on abort. |
|
|
1219
|
+
| `toolBudget` | object | none | Optional child tool-call budget `{ soft?, hard, block? }`. At `soft` the child is nudged to finalize. After `hard`, configured tools are blocked; `block` defaults to `read`, `grep`, `find`, and `ls`, while `"*"` blocks every tool call. Final assistant text is never blocked. |
|
|
1062
1220
|
| `cwd` | string | runtime cwd | Override working directory. |
|
|
1063
1221
|
| `maxOutput` | object | 200KB, 5000 lines | Final output truncation limits. |
|
|
1064
1222
|
| `artifacts` | boolean | true | Write debug artifacts. |
|
|
1065
1223
|
| `includeProgress` | boolean | false | Include full progress in result. |
|
|
1066
1224
|
| `share` | boolean | false | Upload session export to GitHub Gist. |
|
|
1067
1225
|
| `sessionDir` | string | derived | Override session log directory. |
|
|
1068
|
-
| `acceptance` | string/object/false | inferred | Override
|
|
1226
|
+
| `acceptance` | string/object/false | inferred | Override inferred gates with `"auto"`, `"attested"`, `"checked"`, `"verified"`, or `{ level: "none", reason: "..." }`. `reviewed` is inferred-only; explicit requests fail preflight. `false` is a deprecated shorthand for disabling gates. |
|
|
1069
1227
|
|
|
1070
|
-
|
|
1228
|
+
As a conservative orchestration policy, do not set `turnBudget` or a hard `toolBudget` on implementation workers, fix workers, reviewers with edit authority, or other mutation-capable children. A default tool budget blocks read/search tools rather than mutation tools, but neither assistant turns nor tool-call counts measure whether a delivery slice is buildable or safe to hand off. Hard count caps remain appropriate for explicitly read-only scouts, reviewers, and validators.
|
|
1071
1229
|
|
|
1072
|
-
|
|
1230
|
+
Bound writer work with a narrow task and an outer `timeoutMs` or `maxRuntimeMs` that leaves enough margin for the slice. An elapsed timeout is not a mutation-safe boundary and may still signal a child during tool work. Before the deadline, use `steer` or an attention notice to request a checkpoint after the current tool returns, including changed files, build/test state, remaining work, and commit or PR state.
|
|
1231
|
+
|
|
1232
|
+
`context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. When the inherited transcript contains signed Anthropic `thinking` / `redacted_thinking` blocks, `pi-subagents` strips those provider-private blocks from the forked child session. It forces thinking `off` only when the child’s effective primary or fallback model resolves through the model registry to the Anthropic provider or `anthropic-messages` API; unresolved models are treated conservatively. The result reports every affected child, including on failed runs. Use `context: "fresh"` when an Anthropic child needs thinking. Forking never silently downgrades to `fresh`. In multi-agent runs that omit `context`, each agent/task/step follows its own `defaultContext`, so a fresh-default scout can run fresh beside a fork-default worker. Pass explicit `context: "fork"` or `context: "fresh"` when you intentionally want one context for every child.
|
|
1233
|
+
|
|
1234
|
+
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. A child with only read-only tools does not need direct filesystem access for `output`: it returns the complete artifact in its final response and the runtime persists it. Children with mutation-capable tools retain the direct-write instruction.
|
|
1073
1235
|
|
|
1074
1236
|
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}`.
|
|
1075
1237
|
|
|
@@ -1083,7 +1245,8 @@ subagent({ action: "status", id: "<run-id>", view: "transcript", index: 0, lines
|
|
|
1083
1245
|
subagent({ action: "status", id: "<nested-run-id>" })
|
|
1084
1246
|
subagent({ action: "interrupt", id: "<run-id>" })
|
|
1085
1247
|
subagent({ action: "interrupt", id: "<nested-run-id>" })
|
|
1086
|
-
subagent({ action: "
|
|
1248
|
+
subagent({ action: "stop", id: "<run-id>" })
|
|
1249
|
+
subagent({ action: "resume", id: "<run-id>", message: "follow-up question after it pauses or finishes" })
|
|
1087
1250
|
subagent({ action: "resume", id: "<run-id>", index: 1, message: "follow-up for child 2" })
|
|
1088
1251
|
subagent({ action: "resume", id: "<nested-run-id>", message: "follow-up for a nested child" })
|
|
1089
1252
|
subagent({ action: "steer", id: "<run-id>", message: "guidance for the running child" })
|
|
@@ -1094,9 +1257,11 @@ subagent({ action: "doctor" })
|
|
|
1094
1257
|
|
|
1095
1258
|
`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.
|
|
1096
1259
|
|
|
1097
|
-
`resume`
|
|
1260
|
+
`resume` revives a paused, completed, or failed async/foreground child by starting a new child from its stored session file; stopped runs remain non-resumable, and it does not interrupt a live top-level async child. Use `steer` for acknowledged live async guidance. Multi-child async runs and remembered foreground single, parallel, or chain runs can be revived by passing `index` to choose the child. Nested runs can be resumed by nested id when their live route or persisted nested session metadata is available. Revive starts a new child process from the old session context; it does not restart the same OS process, and it requires the chosen child to have a persisted `.jsonl` session file. Direct revival takes an exclusive cross-process lease on the canonical session file until the new child finishes. A concurrent attempt fails before Pi is spawned and identifies the owning revived run; dead-owner leases are reclaimed only when staleness can be proved.
|
|
1098
1261
|
|
|
1099
|
-
`
|
|
1262
|
+
`stop` ends a current-session top-level async run. It is deliberately stronger than `interrupt`: it is not a resumable pause, stopped runs should be restarted as new runs, foreground and nested targets are rejected, direct id calls execute immediately, and `/subagents-stop` without an id opens a selector with confirmation when a TUI is available. In non-TUI contexts the slash command prints exact `subagent({ action: "stop", id })` and `/subagents-stop <id>` commands. Scheduled jobs can appear in the selector, but they are labeled as scheduled cancellations and route through `schedule-cancel`, not `stop`.
|
|
1263
|
+
|
|
1264
|
+
`steer` waits up to three seconds for a correlated child-Pi input acceptance and returns a request id with `delivered`, `scheduled`, `pending`, `partial`, `recovered`, or `failed` plus per-child states. Delivery means Pi accepted the user message, not model compliance. A pending indexed child returns `scheduled`. Only a top-level single run may interrupt after the acknowledgment deadline and recover after a further 15-second pause/revival bound; chain, parallel, and nested runs never auto-interrupt. Recovery launches a replacement only after the source is confirmed paused, a valid persisted session exists, and deadline, turn, and tool budgets remain. It preserves the original child contract and remaining limits; otherwise the source stays paused with an explicit failure. Late acceptance is recorded but cannot cancel committed recovery. The persisted `steering` ledger retains 20 requests and replaces the old `steerCount`/`lastSteerAt` fields.
|
|
1100
1265
|
|
|
1101
1266
|
`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.
|
|
1102
1267
|
|
|
@@ -1142,7 +1307,7 @@ After a worktree parallel step completes, per-agent diff stats are appended to t
|
|
|
1142
1307
|
{ "toolDescriptionMode": "compact" }
|
|
1143
1308
|
```
|
|
1144
1309
|
|
|
1145
|
-
Controls the parent-facing `subagent` tool description registered at startup. `full` is the default. `compact` keeps the execution modes, async
|
|
1310
|
+
Controls the parent-facing `subagent` tool description registered at startup. `full` is the default. `compact` keeps the execution modes, async/`subagent_wait` guidance, child-safety boundary, management/action split, one-writer review guidance, and artifact/status essentials with less prompt bloat.
|
|
1146
1311
|
|
|
1147
1312
|
`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
1313
|
|
|
@@ -1154,13 +1319,21 @@ Controls the parent-facing `subagent` tool description registered at startup. `f
|
|
|
1154
1319
|
|
|
1155
1320
|
Makes top-level calls use background execution when the request does not explicitly set `async`. Callers can still force foreground with `async: false` unless `forceTopLevelAsync` is enabled.
|
|
1156
1321
|
|
|
1322
|
+
### `asyncWidget`
|
|
1323
|
+
|
|
1324
|
+
```json
|
|
1325
|
+
{ "asyncWidget": false }
|
|
1326
|
+
```
|
|
1327
|
+
|
|
1328
|
+
Controls the above-editor widget for background runs. The default is `true`. Set it to `false` when another extension renders async lifecycle data in a custom footer, status line, or dashboard; status tracking, completion notifications, `/subagents-fleet`, and lifecycle events continue to work.
|
|
1329
|
+
|
|
1157
1330
|
### `waitTool`
|
|
1158
1331
|
|
|
1159
1332
|
```json
|
|
1160
1333
|
{ "waitTool": { "enabled": false } }
|
|
1161
1334
|
```
|
|
1162
1335
|
|
|
1163
|
-
Keeps the `
|
|
1336
|
+
Keeps the `subagent_wait` tool registered but makes direct calls return immediately instead of blocking on active subagent or provider work. The default is enabled. You can also set `"waitTool": false`; set `PI_SUBAGENT_WAIT_TOOL_ENABLED=false` (or `0`, `off`, `disabled`) to override config for one process. The effective value is passed explicitly to child runtimes. Headless `agent_end` auto-drain remains a lifecycle safeguard even when direct wait calls are disabled. Invalid config or environment values fail instead of being coerced.
|
|
1164
1337
|
|
|
1165
1338
|
### `forceTopLevelAsync`
|
|
1166
1339
|
|
|
@@ -1181,10 +1354,14 @@ Caps simultaneously running subagent tasks within a single run across top-level
|
|
|
1181
1354
|
### `maxSubagentSpawnsPerSession`
|
|
1182
1355
|
|
|
1183
1356
|
```json
|
|
1184
|
-
{ "maxSubagentSpawnsPerSession":
|
|
1357
|
+
{ "maxSubagentSpawnsPerSession": 100 }
|
|
1185
1358
|
```
|
|
1186
1359
|
|
|
1187
|
-
|
|
1360
|
+
Optionally caps the total number of child subagent launches during one parent session, including completed and failed children, parallel task counts, static chain steps, and bounded dynamic fanout children. Sessions are unlimited by default. Set this value to `0` to disable a configured cap. `PI_SUBAGENT_MAX_SPAWNS_PER_SESSION` overrides the config for a process and follows the same positive-cap/zero-unlimited semantics.
|
|
1361
|
+
|
|
1362
|
+
`subagent({ action: "status" })`, fleet status, and `subagent({ action: "doctor" })` expose used, effective limit, remaining capacity, grants, and the remaining grant allowance. Static chains and parallel calls fail before creating run artifacts or starting partial work when their declared capacity cannot fit. Later retries or unbounded dynamic work are not guaranteed by that preflight.
|
|
1363
|
+
|
|
1364
|
+
A user may explicitly call `subagent({ action: "grant-spawn-budget", additional: 10 })` from the root interactive parent after all children settle and confirm the native prompt. Grants are additive: they never erase cumulative usage, are rejected for unlimited sessions and child/headless callers, and total granted capacity cannot exceed the original configured cap. Compaction remains part of the same logical parent session and does not reset usage or grants; starting a new parent session does.
|
|
1188
1365
|
|
|
1189
1366
|
### `scheduledRuns`
|
|
1190
1367
|
|
|
@@ -1192,7 +1369,7 @@ Caps the total number of child subagent launches allowed during one parent sessi
|
|
|
1192
1369
|
{ "scheduledRuns": { "enabled": true, "maxPending": 20, "maxLatenessMs": 300000 } }
|
|
1193
1370
|
```
|
|
1194
1371
|
|
|
1195
|
-
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, `
|
|
1372
|
+
Enables optional one-shot scheduled subagent runs. When enabled, `subagent({ action: "schedule", agent, task?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? })` defers a subagent launch until a future time. Absolute ISO timestamps must include a timezone (`Z` or an offset such as `+05:30`). The scheduled run launches as a normal tracked async run with fresh context once it fires, and joins the existing async widget, status, `subagent_wait`, and completion-notification paths. `schedule-list`, `schedule-status`, and `schedule-cancel` manage pending jobs. Schedules are persisted per session and restored after a Pi restart; a job missed by more than `maxLatenessMs` while Pi is unavailable is marked `missed` instead of firing late. `maxPending` caps the number of pending or running scheduled jobs per session (default `20`). The feature is opt-in: leave `enabled` unset to keep scheduling out of the tool surface and prompt. Only schedule explicit delayed runs the user asked for.
|
|
1196
1373
|
|
|
1197
1374
|
### `parallel`
|
|
1198
1375
|
|
|
@@ -1324,7 +1501,7 @@ Debug artifacts live under `{sessionDir}/subagent-artifacts/`, `.pi-subagents/ar
|
|
|
1324
1501
|
- `{runId}_{agent}.jsonl`
|
|
1325
1502
|
- `{runId}_{agent}_meta.json`
|
|
1326
1503
|
|
|
1327
|
-
Metadata records timing, usage, exit code, final model, attempted models,
|
|
1504
|
+
Metadata records timing, usage, exit code, final model, attempted models, fallback attempt outcomes, and the resolved acceptance ledger with its parsed child report.
|
|
1328
1505
|
|
|
1329
1506
|
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.
|
|
1330
1507
|
|
|
@@ -1340,7 +1517,7 @@ Async runs write:
|
|
|
1340
1517
|
subagent-log-<id>.md
|
|
1341
1518
|
```
|
|
1342
1519
|
|
|
1343
|
-
`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`
|
|
1520
|
+
`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 correlated `subagent.steer.requested`, `scheduled`, `routed`, `delivered`, `failed`, and `recovered` events plus failure/partial/recovery notices. 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.
|
|
1344
1521
|
|
|
1345
1522
|
## Acceptance Gates
|
|
1346
1523
|
|
|
@@ -1359,7 +1536,7 @@ Every run resolves an effective acceptance policy. Callers may omit `acceptance`
|
|
|
1359
1536
|
}
|
|
1360
1537
|
```
|
|
1361
1538
|
|
|
1362
|
-
|
|
1539
|
+
Acceptance policies use the levels `auto`, `none`, `attested`, `checked`, `verified`, and `reviewed`. `acceptance: "auto"` is the default. Callers may explicitly request levels through `verified`; `reviewed` is reserved for inferred policy because the current execution path cannot supply an independent reviewer result. Explicit `reviewed` fails preflight instead of spawning a child that is guaranteed to be rejected. Read-only tasks infer lightweight attestation, normal writer tasks infer checked evidence, and async/risky/dynamic writer contexts infer a reviewed gate. Agent frontmatter or `subagents.agentOverrides` may set `acceptanceRole: "read-only" | "writer"` for ambiguous tasks; explicit task mutation or no-edit intent wins over that role, while omitted metadata preserves the existing reviewer/scout/worker name heuristics. The role affects acceptance inference only and does not change tool access. The bare string `"none"` is rejected; use `{ level: "none", reason: "..." }` instead. `acceptance: false` is accepted only as a deprecated shorthand for disabling gates.
|
|
1363
1540
|
|
|
1364
1541
|
Acceptance provenance is stored separately from child prose:
|
|
1365
1542
|
|
|
@@ -1370,7 +1547,9 @@ Acceptance provenance is stored separately from child prose:
|
|
|
1370
1547
|
- `reviewed`: an independent reviewer result is present.
|
|
1371
1548
|
- `rejected`: attestation, structural checks, verification, or review failed.
|
|
1372
1549
|
|
|
1373
|
-
For `attested` or stricter levels, the child prompt includes a standardized acceptance section and asks for a fenced `acceptance-report` JSON block.
|
|
1550
|
+
For `attested` or stricter levels, the child prompt includes a standardized acceptance section and asks for a fenced `acceptance-report` JSON block. The parser canonicalizes known enum synonyms, snake_case report keys and wrappers, underscore fence tags, unambiguous scalar arrays, string booleans, and criterion-id separators. Unknown or ambiguous keys and enum values fail with field-level diagnostics. Explicit empty `changedFiles` and `testsAddedOrUpdated` arrays are recorded as not applicable; missing fields and empty required command or validation evidence still fail.
|
|
1551
|
+
|
|
1552
|
+
Acceptance fences are removed from normal output artifacts, while the raw child transcript remains intact and per-child metadata stores the complete acceptance ledger and parsed report. Explicit failed gates fail the run. Inferred gates remain observable without failing the run.
|
|
1374
1553
|
|
|
1375
1554
|
## Live progress
|
|
1376
1555
|
|
|
@@ -1417,6 +1596,8 @@ Async events:
|
|
|
1417
1596
|
- `subagent:async-started`
|
|
1418
1597
|
- `subagent:async-complete`
|
|
1419
1598
|
|
|
1599
|
+
The `subagent:async-started` payload includes `task`, the backwards-compatible first child task truncated to 50 characters, and `goal`, the workflow-level caller task truncated to 120 characters (falling back to the first child task). Companion UI extensions can combine `goal`, `workflowGraph`, and the live lifecycle artifacts under `asyncDir` without scraping terminal output.
|
|
1600
|
+
|
|
1420
1601
|
Intercom delivery events:
|
|
1421
1602
|
|
|
1422
1603
|
- `subagent:control-intercom`
|
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./src/extension/index.ts";
|
package/install.mjs
CHANGED
|
@@ -87,7 +87,7 @@ if (fs.existsSync(EXTENSION_DIR)) {
|
|
|
87
87
|
console.log(`
|
|
88
88
|
The extension is now available in pi. Tools added:
|
|
89
89
|
• subagent - Delegate tasks to agents and inspect run status
|
|
90
|
-
•
|
|
90
|
+
• subagent_wait - Block until background subagent runs finish (delivers their results)
|
|
91
91
|
|
|
92
92
|
Documentation: ${EXTENSION_DIR}/README.md
|
|
93
93
|
`);
|