pi-subagents 0.31.1 → 0.32.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 +40 -4
- package/README.md +97 -7
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +6 -1
- package/src/agents/agent-management.ts +6 -1
- package/src/agents/agents.ts +55 -11
- package/src/extension/companion-suggestions.ts +359 -0
- package/src/extension/config.ts +27 -4
- package/src/extension/doctor.ts +2 -0
- package/src/extension/fanout-child.ts +1 -0
- package/src/extension/index.ts +58 -4
- package/src/extension/schemas.ts +2 -2
- package/src/runs/background/async-execution.ts +138 -33
- package/src/runs/background/async-job-tracker.ts +77 -1
- package/src/runs/background/async-status.ts +41 -9
- package/src/runs/background/chain-root-attachment.ts +34 -4
- package/src/runs/background/control-channel.ts +50 -0
- package/src/runs/background/run-status.ts +1 -0
- package/src/runs/background/stale-run-reconciler.ts +28 -1
- package/src/runs/background/subagent-runner.ts +454 -115
- package/src/runs/foreground/chain-execution.ts +29 -7
- package/src/runs/foreground/execution.ts +24 -6
- package/src/runs/foreground/subagent-executor.ts +209 -35
- package/src/runs/shared/acceptance.ts +45 -22
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/model-fallback.ts +4 -0
- package/src/runs/shared/nested-events.ts +58 -0
- package/src/runs/shared/parallel-utils.ts +49 -1
- package/src/runs/shared/pi-args.ts +5 -3
- package/src/runs/shared/pi-spawn.ts +52 -20
- package/src/runs/shared/single-output.ts +2 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +2 -2
- package/src/runs/shared/worktree.ts +28 -5
- package/src/shared/artifacts.ts +15 -1
- package/src/shared/fork-context.ts +133 -22
- package/src/shared/types.ts +81 -3
- package/src/shared/utils.ts +99 -14
- package/src/slash/slash-commands.ts +117 -0
- package/src/tui/render.ts +16 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,15 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
## [0.32.0] - 2026-07-01
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Added `subagents.defaultModel` so subagents can have a global default model separate from the parent session model. Thanks to Artem Timofeev (@atimofeev) for #339.
|
|
13
|
+
- Added `/subagent-cost` and `totalChildUsage` run details so parent sessions can inspect aggregate subagent child usage and cost. Thanks to Aaron Ky-Riesenbach (@aaronkyriesenbach) for #343.
|
|
14
|
+
- Added configurable companion package recommendations for `pi-intercom` and `pi-prompt-template-model`, surfaced in session-start transcript messages, `subagent({ action: "list" })`, and `/subagents-doctor`, with `/subagents-companions` hide/show/status controls.
|
|
15
|
+
- Added detached async runner stdout and stderr log files. Thanks to Daniel Mateos Carballares (@danim47c) for #358.
|
|
16
|
+
- Added `totalCost` rollups to foreground single, parallel, and chain run details, including nested foreground subagent costs and compact progress display. Thanks to Clark Everson (@gr3enarr0w) for #345.
|
|
17
|
+
- Added `globalConcurrencyLimit` to cap simultaneously running subagent tasks across parallel groups in a single run. Thanks to Clark Everson (@gr3enarr0w) for #349.
|
|
18
|
+
- Added stable v1 async lifecycle artifact metadata in `status.json`, `events.jsonl`, and result JSON so observability and workflow gates can correlate subagent runs without scraping terminal output. Thanks to Clark Everson (@gr3enarr0w) for #350.
|
|
19
|
+
- Added `PI_SUBAGENT_PI_BINARY` to let wrappers launch child agents through an explicit Pi binary instead of resolving `pi` from `PATH`. Thanks to David Barroso (@dbarrosop) for #341.
|
|
20
|
+
- Added `worktreeBaseDir` and `PI_SUBAGENTS_WORKTREE_DIR` so worktree isolation can use a stable trusted base directory. Thanks to Matt Robenolt (@mattrobenolt) for #185.
|
|
21
|
+
- Added `singleRunOutputBaseDir` so single-agent relative outputs can be routed to a configured artifact directory. Thanks to Oleksii Nikiforov (@NikiforovAll) for #173.
|
|
22
|
+
- Added `maxSubagentSpawnsPerSession` and `PI_SUBAGENT_MAX_SPAWNS_PER_SESSION` to cap total subagent launches in one session. Thanks to @eightHundreds for #239.
|
|
23
|
+
- Enforce `timeoutMs` and `maxRuntimeMs` on async and background subagent runs. The per-launch deadline drives an AbortController that cancels acceptance verification, imported async roots, and fallback retries; direct children get SIGTERM with SIGKILL escalation on a bounded timer; nested descendants get timeout requests distinct from manual interrupt. `timedOut`, `deadlineAt`, and `error` propagate across status, results, and nested summaries. Thanks to @pkese for #361.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- Keep generated subagent markdown outputs, progress files, and run artifacts under the project-local `.pi-subagents/` directory by default. Thanks to Carolina (@carolitascl) for #326.
|
|
27
|
+
- Detach foreground subagent runs immediately when a child starts a blocking `contact_supervisor` or `intercom.ask` call, avoiding parent/child intercom deadlocks. Thanks to huarkiou (@huarkiou) for #335.
|
|
28
|
+
- Made child boundary prompt editing instructions tool-agnostic so Codex-style adapters are not told to call unavailable `edit`/`write` tools. Thanks to Artem Timofeev (@atimofeev) for #338.
|
|
29
|
+
- Recursively interrupt active async parallel children and nested async descendants when pausing a background run. Thanks to Vicary (@vicary) for #355.
|
|
30
|
+
- Avoid runtime peer imports from detached async runners while still forwarding the Pi package root when available. Thanks to @aurbina83 for #352 and @huangkun3251 for #342.
|
|
31
|
+
- Fall back to PATH `node` for async runners when the current Node executable path is stale or deleted. Thanks to Richard Hao (@0xRichardH) for #347.
|
|
32
|
+
- Retry fallback models when a zero-exit subagent attempt produces no output, including background async runs, preserve structured-output-only completions, and pre-warm forked session files for parallel children. Thanks to Clark Everson (@gr3enarr0w) for #344.
|
|
33
|
+
- Preserve explicit empty companion suggestion surfaces and keep global companion suggestions disabled when writing package dismissal state.
|
|
34
|
+
- Include bounded async runner stderr tails when stale-run reconciliation marks a startup crash failed. Thanks to Salem Sayed (@salemsayed) for #340.
|
|
35
|
+
- Persist forked child session files when Pi returns a branch path before writing it to disk. Thanks to @trisforrestcam for #174.
|
|
36
|
+
- Pass explicit `thinking: off` through to child model arguments as a `:off` suffix. Thanks to Thomas Dietert (@tdietert) for #147.
|
|
37
|
+
- Sanitize Anthropic signed `thinking` / `redacted_thinking` blocks out of forked child sessions and force child thinking off so fork-context subagents survive signed-thinking transcripts after branching or compaction. Thanks to Thomas Dietert (@tdietert) for #147.
|
|
38
|
+
- Restore queued and running detached async jobs into the widget after restarting Pi. Thanks to Vicary (@vicary) for #362.
|
|
39
|
+
- Fix session-start freeze where restoring active async jobs did O(runs × nested-route-dirs) directory scans over stale terminal runs; `listAsyncRuns` now builds a single nested-route index and filters by state before lookup.
|
|
40
|
+
|
|
5
41
|
## [0.31.1] - 2026-06-25
|
|
6
42
|
|
|
7
43
|
### Added
|
|
8
|
-
- Added `/chain` inline parallel groups with per-step metadata, group options, and tab completion.
|
|
9
|
-
- Added subagent profile commands and provider model catalog generation for quota and quality model profiles.
|
|
44
|
+
- Added `/chain` inline parallel groups with per-step metadata, group options, and tab completion. Thanks to loss-and-quick (@loss-and-quick) for #312.
|
|
45
|
+
- Added subagent profile commands and provider model catalog generation for quota and quality model profiles. Thanks to tencnivel (@tencnivel) for #333.
|
|
10
46
|
|
|
11
47
|
### Fixed
|
|
12
|
-
- Discover `pi-intercom` installations created by `--extension npm:pi-intercom` under Pi's temporary npm extension cache.
|
|
13
|
-
- Made async subagent interrupt, steer, and stop requests portable across platforms that do not support Unix signals.
|
|
48
|
+
- Discover `pi-intercom` installations created by `--extension npm:pi-intercom` under Pi's temporary npm extension cache. Thanks to loss-and-quick (@loss-and-quick) for #336.
|
|
49
|
+
- Made async subagent interrupt, steer, and stop requests portable across platforms that do not support Unix signals. Thanks to AeonDave (@AeonDave) for #332.
|
|
14
50
|
- Hardened profile commands by probing models without tools, rejecting unsafe profile/provider path tokens, and resolving short model IDs and thinking suffixes against the current registry.
|
|
15
51
|
- Limited inline `/chain` acceptance values to levels expressible in slash syntax and kept completion disabled inside shared `--` tasks with literal parentheses.
|
|
16
52
|
|
package/README.md
CHANGED
|
@@ -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.
|
|
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
|
|
|
@@ -168,6 +182,10 @@ You can also ask naturally:
|
|
|
168
182
|
Show me the current async runs.
|
|
169
183
|
```
|
|
170
184
|
|
|
185
|
+
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.
|
|
186
|
+
|
|
187
|
+
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.
|
|
188
|
+
|
|
171
189
|
If something feels misconfigured, run:
|
|
172
190
|
|
|
173
191
|
```text
|
|
@@ -218,6 +236,8 @@ Add `autofix` to `/parallel-review` or `/parallel-cleanup` to apply only the syn
|
|
|
218
236
|
pi install npm:pi-intercom
|
|
219
237
|
```
|
|
220
238
|
|
|
239
|
+
When `pi-intercom` is not active, `pi-subagents` may recommend it at session start, in `subagent({ action: "list" })`, and in `/subagents-doctor`. The recommendation is visible to the assistant so it can offer to run the install command or hide the recommendation after you approve that action.
|
|
240
|
+
|
|
221
241
|
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.
|
|
222
242
|
|
|
223
243
|
Use it for work where the child might need a decision instead of guessing:
|
|
@@ -332,6 +352,7 @@ Skip this section until you want exact syntax.
|
|
|
332
352
|
| `/chain scout "scan" -> (reviewer "A" \| reviewer "B") -> writer "fix"` | Run a chain with a static parallel group inline |
|
|
333
353
|
| `/parallel agent1 "task1" -> agent2 "task2"` | Run agents in parallel |
|
|
334
354
|
| `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` or `.chain.json` workflow |
|
|
355
|
+
| `/subagent-cost` | Show parent plus child subagent token usage and cost for this session |
|
|
335
356
|
| `/subagents-doctor` | Show read-only setup diagnostics |
|
|
336
357
|
| `/subagents-models [agent]` | Show the runtime-loaded builtin model mapping, optionally filtered to one builtin |
|
|
337
358
|
| `/subagents-profiles` | List saved subagent profiles from `~/.pi/agent/profiles/pi-subagents/` |
|
|
@@ -440,7 +461,7 @@ Append `[key=value,...]` to an agent name to override defaults. `/chain` applies
|
|
|
440
461
|
|
|
441
462
|
| Key | Example | Description |
|
|
442
463
|
|-----|---------|-------------|
|
|
443
|
-
| `output` | `output=context.md` | Write results to a file.
|
|
464
|
+
| `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
465
|
| `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
466
|
| `reads` | `reads=a.md+b.md` | Read files before executing. `+` separates multiple paths. |
|
|
446
467
|
| `model` | `model=anthropic/claude-sonnet-4` | Override model for this step. |
|
|
@@ -521,7 +542,7 @@ Agent locations, lowest to highest priority:
|
|
|
521
542
|
|
|
522
543
|
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
544
|
|
|
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.
|
|
545
|
+
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
546
|
|
|
526
547
|
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
548
|
|
|
@@ -552,6 +573,8 @@ Example:
|
|
|
552
573
|
|
|
553
574
|
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
575
|
|
|
576
|
+
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.
|
|
577
|
+
|
|
555
578
|
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.
|
|
556
579
|
|
|
557
580
|
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.
|
|
@@ -977,6 +1000,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
977
1000
|
| `clarify` | boolean | true for chains | Show TUI preview/edit flow. |
|
|
978
1001
|
| `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
|
|
979
1002
|
| `async` | boolean | false | Background execution. For chains, `clarify: true` explicitly keeps the run foreground for the clarify UI. |
|
|
1003
|
+
| `timeoutMs` / `maxRuntimeMs` | number | none | Optional run-level max runtime in milliseconds for foreground and async/background runs. |
|
|
980
1004
|
| `cwd` | string | runtime cwd | Override working directory. |
|
|
981
1005
|
| `maxOutput` | object | 200KB, 5000 lines | Final output truncation limits. |
|
|
982
1006
|
| `artifacts` | boolean | true | Write debug artifacts. |
|
|
@@ -985,7 +1009,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
985
1009
|
| `sessionDir` | string | derived | Override session log directory. |
|
|
986
1010
|
| `acceptance` | string/object/false | inferred | Override the run's inferred acceptance gates. Use `"auto"`, `"attested"`, `"checked"`, `"verified"`, `"reviewed"`, or `{ level: "none", reason: "..." }`. |
|
|
987
1011
|
|
|
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.
|
|
1012
|
+
`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
1013
|
|
|
990
1014
|
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
1015
|
|
|
@@ -1040,6 +1064,8 @@ Requirements:
|
|
|
1040
1064
|
- task-level `cwd` overrides must be omitted or match the shared cwd
|
|
1041
1065
|
- configured `worktreeSetupHook` must return valid JSON before timeout
|
|
1042
1066
|
|
|
1067
|
+
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.
|
|
1068
|
+
|
|
1043
1069
|
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
1070
|
|
|
1045
1071
|
## Configuration
|
|
@@ -1062,6 +1088,22 @@ Makes top-level calls use background execution when the request does not explici
|
|
|
1062
1088
|
|
|
1063
1089
|
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
1090
|
|
|
1091
|
+
### `globalConcurrencyLimit`
|
|
1092
|
+
|
|
1093
|
+
```json
|
|
1094
|
+
{ "globalConcurrencyLimit": 20 }
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
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.
|
|
1098
|
+
|
|
1099
|
+
### `maxSubagentSpawnsPerSession`
|
|
1100
|
+
|
|
1101
|
+
```json
|
|
1102
|
+
{ "maxSubagentSpawnsPerSession": 40 }
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
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.
|
|
1106
|
+
|
|
1065
1107
|
### `parallel`
|
|
1066
1108
|
|
|
1067
1109
|
```json
|
|
@@ -1083,6 +1125,14 @@ Forces depth-0 single, parallel, and chain runs into background mode and bypasse
|
|
|
1083
1125
|
|
|
1084
1126
|
Session directory precedence is: `params.sessionDir`, then `config.defaultSessionDir`, then a directory derived from the parent session. Sessions are always enabled.
|
|
1085
1127
|
|
|
1128
|
+
### `singleRunOutputBaseDir`
|
|
1129
|
+
|
|
1130
|
+
```json
|
|
1131
|
+
{ "singleRunOutputBaseDir": "~/.pi/subagent-outputs" }
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
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.
|
|
1135
|
+
|
|
1086
1136
|
### `maxSubagentDepth`
|
|
1087
1137
|
|
|
1088
1138
|
```json
|
|
@@ -1091,6 +1141,14 @@ Session directory precedence is: `params.sessionDir`, then `config.defaultSessio
|
|
|
1091
1141
|
|
|
1092
1142
|
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
1143
|
|
|
1144
|
+
### `PI_SUBAGENT_PI_BINARY`
|
|
1145
|
+
|
|
1146
|
+
```bash
|
|
1147
|
+
export PI_SUBAGENT_PI_BINARY=/path/to/pi-or-wrapper
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
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.
|
|
1151
|
+
|
|
1094
1152
|
### `intercomBridge`
|
|
1095
1153
|
|
|
1096
1154
|
```json
|
|
@@ -1113,6 +1171,36 @@ Bridge activation also requires `pi-intercom` to be installed and enabled throug
|
|
|
1113
1171
|
|
|
1114
1172
|
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
1173
|
|
|
1174
|
+
### `companionSuggestions`
|
|
1175
|
+
|
|
1176
|
+
```json
|
|
1177
|
+
{
|
|
1178
|
+
"companionSuggestions": {
|
|
1179
|
+
"enabled": true,
|
|
1180
|
+
"packages": {
|
|
1181
|
+
"pi-intercom": {
|
|
1182
|
+
"surfaces": ["session_start", "list", "doctor"]
|
|
1183
|
+
},
|
|
1184
|
+
"pi-prompt-template-model": {
|
|
1185
|
+
"surfaces": ["session_start", "list", "doctor"]
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
Controls recommendations for optional companion packages. `pi-intercom` enables live supervisor decisions, progress updates, and grouped result delivery. `pi-prompt-template-model` makes subagent workflows reusable as prompt templates with model/thinking/skill/subagent frontmatter.
|
|
1193
|
+
|
|
1194
|
+
Use `/subagents-companions status` to inspect recommendation status. Use `/subagents-companions hide pi-intercom workspace` or `/subagents-companions hide pi-prompt-template-model user` to hide a recommendation. Use `/subagents-companions show <package>` to show a workspace recommendation again. Set `companionSuggestions` to `false` to disable all companion recommendations.
|
|
1195
|
+
|
|
1196
|
+
### `worktreeBaseDir`
|
|
1197
|
+
|
|
1198
|
+
```json
|
|
1199
|
+
{ "worktreeBaseDir": "/Users/matt/code/.worktrees/pi-subagents" }
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
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.
|
|
1203
|
+
|
|
1116
1204
|
### `worktreeSetupHook`
|
|
1117
1205
|
|
|
1118
1206
|
```json
|
|
@@ -1142,7 +1230,7 @@ Each chain run creates a user-scoped temp directory like:
|
|
|
1142
1230
|
|
|
1143
1231
|
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
1232
|
|
|
1145
|
-
Debug artifacts live under `{sessionDir}/subagent-artifacts/` or a user-scoped temp artifact directory. Per task you may see:
|
|
1233
|
+
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
1234
|
|
|
1147
1235
|
- `{runId}_{agent}_input.md`
|
|
1148
1236
|
- `{runId}_{agent}_output.md`
|
|
@@ -1199,7 +1287,7 @@ For `attested` or stricter levels, the child prompt includes a standardized acce
|
|
|
1199
1287
|
|
|
1200
1288
|
## Live progress
|
|
1201
1289
|
|
|
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.
|
|
1290
|
+
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
1291
|
|
|
1204
1292
|
Press `Ctrl+O` to expand the full streaming view with complete output per step.
|
|
1205
1293
|
|
|
@@ -1269,6 +1357,8 @@ Then `/take-screenshot https://example.com` switches to Sonnet, delegates to `br
|
|
|
1269
1357
|
|
|
1270
1358
|
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/`.
|
|
1271
1359
|
|
|
1360
|
+
When `pi-prompt-template-model` is not active, `pi-subagents` may recommend it at session start, in `subagent({ action: "list" })`, and in `/subagents-doctor`. The recommendation is only a prompt; package installation still requires an explicit user-approved command.
|
|
1361
|
+
|
|
1272
1362
|
## Runtime files
|
|
1273
1363
|
|
|
1274
1364
|
The main runtime files are:
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ Use this skill when the parent orchestrator needs to launch a specialized subage
|
|
|
21
21
|
- **Recon and planning**: use `scout` or `context-builder`, then `planner`
|
|
22
22
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
23
23
|
- **Regular skill specialists**: when discovery shows proactive skill subagent suggestions and the current work is broad enough, launch a small fresh-context fanout that asks one subagent per relevant regularly used skill to apply that skill's perspective to the task
|
|
24
|
-
- **Long-running work**: launch async/background runs and inspect them later
|
|
24
|
+
- **Long-running work**: launch async/background runs and inspect them later; use `timeoutMs` or `maxRuntimeMs` when a foreground or async run needs a hard max runtime
|
|
25
25
|
- **Subagent control**: watch needs-attention signals and soft-interrupt only when a delegated run is genuinely blocked
|
|
26
26
|
- **Agent authoring**: create, update, or override agents and chains for a project
|
|
27
27
|
|
|
@@ -632,6 +632,11 @@ If `pi-prompt-template-model` is installed, additional user prompt templates can
|
|
|
632
632
|
`pi-subagents`. This is useful when a slash command should always run through a
|
|
633
633
|
particular agent or with forked context.
|
|
634
634
|
|
|
635
|
+
If `subagent({ action: "list" })`, `/subagents-doctor`, or a startup message recommends
|
|
636
|
+
`pi-intercom` or `pi-prompt-template-model`, offer to run the shown `pi install npm:<package>`
|
|
637
|
+
command only after user approval. To hide future recommendations, use
|
|
638
|
+
`/subagents-companions hide <package> workspace` or `... user`.
|
|
639
|
+
|
|
635
640
|
## Important Constraints
|
|
636
641
|
|
|
637
642
|
- **Forking requires a persisted parent session.** If the current session does not
|
|
@@ -31,7 +31,7 @@ import { getProjectConfigDir } from "../shared/utils.ts";
|
|
|
31
31
|
|
|
32
32
|
type ManagementAction = "list" | "get" | "models" | "create" | "update" | "delete";
|
|
33
33
|
type ManagementScope = "user" | "project";
|
|
34
|
-
type ManagementContext = Pick<ExtensionContext, "cwd" | "modelRegistry"> & { model?: ExtensionContext["model"]; config?: ExtensionConfig };
|
|
34
|
+
type ManagementContext = Pick<ExtensionContext, "cwd" | "modelRegistry"> & { model?: ExtensionContext["model"]; config?: ExtensionConfig; companionSuggestionLines?: () => string[] };
|
|
35
35
|
|
|
36
36
|
interface ManagementParams {
|
|
37
37
|
action?: string;
|
|
@@ -549,6 +549,7 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
549
549
|
config: ctx.config?.proactiveSkillSubagents,
|
|
550
550
|
discoverAvailableSkills: () => discoverAvailableSkills(ctx.cwd),
|
|
551
551
|
});
|
|
552
|
+
const companionSuggestions = ctx.companionSuggestionLines?.() ?? [];
|
|
552
553
|
const lines = [
|
|
553
554
|
"Executable agents:",
|
|
554
555
|
...(agents.length
|
|
@@ -558,6 +559,7 @@ export function handleList(params: ManagementParams, ctx: ManagementContext): Ag
|
|
|
558
559
|
"Chains:",
|
|
559
560
|
...(chains.length ? chains.map((c) => `- ${c.name} (${c.source}): ${c.description}`) : ["- (none)"]),
|
|
560
561
|
...(proactiveSuggestions.length ? ["", ...proactiveSuggestions] : []),
|
|
562
|
+
...(companionSuggestions.length ? ["", ...companionSuggestions] : []),
|
|
561
563
|
...(diagnostics.length ? ["", "Chain diagnostics:", ...diagnostics.map((entry) => `- ${entry.filePath}: ${entry.error}`)] : []),
|
|
562
564
|
];
|
|
563
565
|
return result(lines.join("\n"));
|
|
@@ -567,6 +569,9 @@ function formatModelSource(agent: AgentConfig, currentModel: ParentModel | undef
|
|
|
567
569
|
if (agent.override && agent.model !== agent.override.base.model) {
|
|
568
570
|
return `${agent.override.scope} override`;
|
|
569
571
|
}
|
|
572
|
+
if (agent.modelSource?.type === "subagents.defaultModel" && agent.model === agent.modelSource.model) {
|
|
573
|
+
return `${agent.modelSource.scope} defaultModel`;
|
|
574
|
+
}
|
|
570
575
|
if (agent.model) return "builtin agent config";
|
|
571
576
|
if (currentModel) return "inherits current session model";
|
|
572
577
|
return "inherit requested, but no current session model is available";
|
package/src/agents/agents.ts
CHANGED
|
@@ -84,6 +84,13 @@ interface BuiltinAgentOverrideInfo {
|
|
|
84
84
|
base: BuiltinAgentOverrideBase;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
export interface AgentModelSourceInfo {
|
|
88
|
+
type: "subagents.defaultModel";
|
|
89
|
+
scope: "user" | "project";
|
|
90
|
+
path: string;
|
|
91
|
+
model: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
87
94
|
export interface AgentConfig {
|
|
88
95
|
name: string;
|
|
89
96
|
localName?: string;
|
|
@@ -113,10 +120,12 @@ export interface AgentConfig {
|
|
|
113
120
|
disabled?: boolean;
|
|
114
121
|
extraFields?: Record<string, string>;
|
|
115
122
|
override?: BuiltinAgentOverrideInfo;
|
|
123
|
+
modelSource?: AgentModelSourceInfo;
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
interface SubagentSettings {
|
|
119
127
|
overrides: Record<string, BuiltinAgentOverrideConfig>;
|
|
128
|
+
defaultModel?: string;
|
|
120
129
|
disableBuiltins?: boolean;
|
|
121
130
|
disableThinking?: boolean;
|
|
122
131
|
}
|
|
@@ -683,17 +692,50 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
683
692
|
throw new Error(`Subagent settings in '${filePath}' have invalid 'disableThinking'; expected a boolean.`);
|
|
684
693
|
}
|
|
685
694
|
}
|
|
695
|
+
let defaultModel: string | undefined;
|
|
696
|
+
if ("defaultModel" in subagentsObject) {
|
|
697
|
+
if (typeof subagentsObject.defaultModel === "string" && subagentsObject.defaultModel.trim()) {
|
|
698
|
+
defaultModel = subagentsObject.defaultModel.trim();
|
|
699
|
+
} else {
|
|
700
|
+
throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
686
703
|
|
|
687
704
|
const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
688
705
|
const agentOverrides = subagentsObject.agentOverrides;
|
|
689
706
|
if (!agentOverrides || typeof agentOverrides !== "object" || Array.isArray(agentOverrides)) {
|
|
690
|
-
return { overrides: parsed, disableBuiltins, disableThinking };
|
|
707
|
+
return { overrides: parsed, defaultModel, disableBuiltins, disableThinking };
|
|
691
708
|
}
|
|
692
709
|
for (const [name, value] of Object.entries(agentOverrides)) {
|
|
693
710
|
const override = parseBuiltinOverrideEntry(name, value, filePath);
|
|
694
711
|
if (override) parsed[name] = override;
|
|
695
712
|
}
|
|
696
|
-
return { overrides: parsed, disableBuiltins, disableThinking };
|
|
713
|
+
return { overrides: parsed, defaultModel, disableBuiltins, disableThinking };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function resolveSubagentDefaultModel(
|
|
717
|
+
userSettings: SubagentSettings,
|
|
718
|
+
projectSettings: SubagentSettings,
|
|
719
|
+
userSettingsPath: string,
|
|
720
|
+
projectSettingsPath: string | null,
|
|
721
|
+
): AgentModelSourceInfo | undefined {
|
|
722
|
+
if (projectSettingsPath && projectSettings.defaultModel !== undefined) {
|
|
723
|
+
return { type: "subagents.defaultModel", scope: "project", path: projectSettingsPath, model: projectSettings.defaultModel };
|
|
724
|
+
}
|
|
725
|
+
return userSettings.defaultModel !== undefined
|
|
726
|
+
? { type: "subagents.defaultModel", scope: "user", path: userSettingsPath, model: userSettings.defaultModel }
|
|
727
|
+
: undefined;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function applySubagentDefaultModel(agents: AgentConfig[], defaultModel: AgentModelSourceInfo | undefined): AgentConfig[] {
|
|
731
|
+
if (!defaultModel) return agents;
|
|
732
|
+
return agents.map((agent) => {
|
|
733
|
+
if (agent.model !== undefined) return agent;
|
|
734
|
+
const next = { ...agent, model: defaultModel.model, modelSource: defaultModel };
|
|
735
|
+
const frontmatterFields = agentFrontmatterFields.get(agent);
|
|
736
|
+
if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
|
|
737
|
+
return next;
|
|
738
|
+
});
|
|
697
739
|
}
|
|
698
740
|
|
|
699
741
|
function applyBuiltinOverride(
|
|
@@ -1241,13 +1283,14 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1241
1283
|
const projectSettingsPath = getProjectAgentSettingsPath(cwd);
|
|
1242
1284
|
const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
|
|
1243
1285
|
const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
|
|
1286
|
+
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
|
|
1244
1287
|
const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
|
|
1245
1288
|
includeUser: scope !== "project",
|
|
1246
1289
|
includeProject: scope !== "user",
|
|
1247
1290
|
});
|
|
1248
1291
|
|
|
1249
1292
|
const builtinAgents = applyBuiltinOverrides(
|
|
1250
|
-
loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"),
|
|
1293
|
+
applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
|
|
1251
1294
|
userSettings,
|
|
1252
1295
|
projectSettings,
|
|
1253
1296
|
userSettingsPath,
|
|
@@ -1258,7 +1301,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1258
1301
|
const userAgentsOld = scope === "project" ? [] : loadAgentsFromDir(userDirOld, "user");
|
|
1259
1302
|
const userAgentsNew = scope === "project" ? [] : loadAgentsFromDir(userDirNew, "user");
|
|
1260
1303
|
const userAgents = applyCustomAgentOverrides(
|
|
1261
|
-
[...userAgentsExtra, ...userAgentsOld, ...userAgentsNew],
|
|
1304
|
+
applySubagentDefaultModel([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel),
|
|
1262
1305
|
userSettings,
|
|
1263
1306
|
projectSettings,
|
|
1264
1307
|
userSettingsPath,
|
|
@@ -1266,13 +1309,13 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
1266
1309
|
);
|
|
1267
1310
|
|
|
1268
1311
|
const projectAgents = applyCustomAgentOverrides(
|
|
1269
|
-
scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")),
|
|
1312
|
+
applySubagentDefaultModel(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel),
|
|
1270
1313
|
userSettings,
|
|
1271
1314
|
projectSettings,
|
|
1272
1315
|
userSettingsPath,
|
|
1273
1316
|
projectSettingsPath,
|
|
1274
1317
|
);
|
|
1275
|
-
const packageAgents = packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package"));
|
|
1318
|
+
const packageAgents = applySubagentDefaultModel(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel);
|
|
1276
1319
|
const agents = mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents)
|
|
1277
1320
|
.filter((agent) => agent.disabled !== true);
|
|
1278
1321
|
|
|
@@ -1302,21 +1345,22 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
1302
1345
|
const projectSettingsPath = getProjectAgentSettingsPath(cwd);
|
|
1303
1346
|
const userSettings = readSubagentSettings(userSettingsPath);
|
|
1304
1347
|
const projectSettings = readSubagentSettings(projectSettingsPath);
|
|
1348
|
+
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
|
|
1305
1349
|
const packageSubagentPaths = collectPackageSubagentPaths(cwd);
|
|
1306
1350
|
|
|
1307
1351
|
const builtin = applyBuiltinOverrides(
|
|
1308
|
-
loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"),
|
|
1352
|
+
applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
|
|
1309
1353
|
userSettings,
|
|
1310
1354
|
projectSettings,
|
|
1311
1355
|
userSettingsPath,
|
|
1312
1356
|
projectSettingsPath,
|
|
1313
1357
|
);
|
|
1314
1358
|
const user = applyCustomAgentOverrides(
|
|
1315
|
-
[
|
|
1359
|
+
applySubagentDefaultModel([
|
|
1316
1360
|
...extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, "user")),
|
|
1317
1361
|
...loadAgentsFromDir(userDirOld, "user"),
|
|
1318
1362
|
...loadAgentsFromDir(userDirNew, "user"),
|
|
1319
|
-
],
|
|
1363
|
+
], defaultModel),
|
|
1320
1364
|
userSettings,
|
|
1321
1365
|
projectSettings,
|
|
1322
1366
|
userSettingsPath,
|
|
@@ -1328,7 +1372,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
1328
1372
|
if (!packageMap.has(agent.name)) packageMap.set(agent.name, agent);
|
|
1329
1373
|
}
|
|
1330
1374
|
}
|
|
1331
|
-
const packageAgents = Array.from(packageMap.values());
|
|
1375
|
+
const packageAgents = applySubagentDefaultModel(Array.from(packageMap.values()), defaultModel);
|
|
1332
1376
|
const projectMap = new Map<string, AgentConfig>();
|
|
1333
1377
|
for (const dir of projectDirs) {
|
|
1334
1378
|
for (const agent of loadAgentsFromDir(dir, "project")) {
|
|
@@ -1336,7 +1380,7 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
1336
1380
|
}
|
|
1337
1381
|
}
|
|
1338
1382
|
const project = applyCustomAgentOverrides(
|
|
1339
|
-
Array.from(projectMap.values()),
|
|
1383
|
+
applySubagentDefaultModel(Array.from(projectMap.values()), defaultModel),
|
|
1340
1384
|
userSettings,
|
|
1341
1385
|
projectSettings,
|
|
1342
1386
|
userSettingsPath,
|