pi-subagents 0.60.0 → 0.62.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 +55 -0
- package/docs/agents.md +7 -3
- package/docs/configuration.md +9 -5
- package/docs/extension-api.md +14 -7
- package/docs/models.md +1 -1
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +13 -4
- package/docs/workflows.md +14 -13
- package/install.mjs +1 -1
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +6 -4
- package/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/skills/pi-subagents/references/execution-controls.md +41 -11
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +4 -4
- package/skills/pi-subagents/references/review-and-validation.md +1 -1
- package/src/agents/agent-management.ts +121 -63
- package/src/agents/agent-serializer.ts +3 -0
- package/src/agents/agents.ts +543 -223
- package/src/agents/runtime-agent-registry.ts +5 -1
- package/src/api/background-work.ts +7 -2
- package/src/api/external-runs.ts +67 -4
- package/src/api/preflight.ts +17 -8
- package/src/api/shared-types.ts +1 -0
- package/src/extension/index.ts +7 -4
- package/src/extension/public-execution.ts +48 -4
- package/src/extension/rpc.ts +62 -4
- package/src/extension/schemas.ts +17 -9
- package/src/extension/tool-description.ts +15 -19
- package/src/runs/background/active-async-capacity.ts +26 -7
- package/src/runs/background/async-execution.ts +98 -51
- package/src/runs/background/async-job-tracker.ts +62 -3
- package/src/runs/background/async-resume.ts +6 -3
- package/src/runs/background/async-status.ts +59 -9
- package/src/runs/background/auto-drain.ts +1 -1
- package/src/runs/background/fleet-view.ts +1 -1
- package/src/runs/background/process-terminal.ts +16 -0
- package/src/runs/background/result-watcher.ts +1 -1
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/run-status.ts +2 -2
- package/src/runs/background/scheduled-runs.ts +63 -6
- package/src/runs/background/steering.ts +4 -1
- package/src/runs/background/subagent-runner.ts +15 -9
- package/src/runs/background/subagent-wait.ts +20 -21
- package/src/runs/background/wait-completions.ts +1 -1
- package/src/runs/background/wait-tool.ts +18 -18
- package/src/runs/foreground/execution.ts +75 -9
- package/src/runs/foreground/subagent-executor.ts +181 -60
- package/src/runs/shared/acceptance.ts +113 -27
- package/src/runs/shared/capability-ceiling.ts +1 -0
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/host-step-status.ts +1 -0
- package/src/runs/shared/model-fallback.ts +61 -17
- package/src/runs/shared/parallel-utils.ts +2 -6
- package/src/runs/shared/permissions.ts +1 -1
- package/src/runs/shared/pi-args.ts +24 -12
- package/src/runs/shared/pi-spawn.ts +69 -35
- package/src/runs/shared/structured-output.ts +33 -6
- package/src/runs/shared/subagent-prompt-runtime.ts +20 -3
- package/src/runs/shared/task-intent.ts +17 -6
- package/src/runs/shared/tool-timeout.ts +1 -1
- package/src/runs/shared/workflow-graph.ts +3 -2
- package/src/shared/atomic-json.ts +3 -1
- package/src/shared/fork-context.ts +0 -12
- package/src/shared/fork-session-cwd.ts +27 -0
- package/src/shared/launch-contract.ts +3 -0
- package/src/shared/types.ts +43 -4
- package/src/shared/workflow-child-permit.ts +91 -0
- package/src/slash/prompt-template-bridge.ts +37 -1
- package/src/slash/slash-commands.ts +18 -26
- package/src/slash/subagents-admin.ts +2 -0
- package/src/tui/render.ts +95 -52
- package/src/workflows/scripted-workflow.ts +153 -4
- package/src/workflows/workflow-child-summary.ts +1 -1
- package/src/workflows/workflow-receipt.ts +41 -4
- package/src/workflows/workflow-resources.ts +150 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,61 @@
|
|
|
3
3
|
|
|
4
4
|
## [Unreleased]
|
|
5
5
|
|
|
6
|
+
## [0.62.0] - 2026-08-31
|
|
7
|
+
|
|
8
|
+
### Highlights
|
|
9
|
+
- Child agents can report completion evidence more cleanly and stay away from tools they should not use.
|
|
10
|
+
- Session-only schedules keep personal scheduled work tied to the session that created it.
|
|
11
|
+
- Async forked runs now start and resume in the working directory you requested.
|
|
12
|
+
- Windows child launches are more reliable, with clearer errors when Pi cannot find a valid CLI.
|
|
13
|
+
- External CLI and read-only recovery paths are sturdier when workers disappear or prompts include unusual line separators.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Let native children with `outputSchema` include required acceptance evidence in the same `structured_output` call with `acceptance.report: "on"`; `acceptance.report: "off"` keeps fenced acceptance reports. Thanks [@mapleluvr](https://github.com/mapleluvr) for #1770.
|
|
17
|
+
- Add per-agent `excludeTools` deny-lists that compose with Pi's ambient or explicit child tool selection. Thanks [@expoli](https://github.com/expoli) for #1776.
|
|
18
|
+
- Add session-only durable schedules that only run in the session that created them. Thanks [@yangfeng20](https://github.com/yangfeng20) for #1777.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- Keep async forked runs in the requested child `cwd` when they start or resume. Thanks [@stekman08](https://github.com/stekman08) for #1785.
|
|
22
|
+
- Accept JSON-encoded acceptance objects from model tool calls, while still failing clearly for malformed strings. Thanks [@mapleluvr](https://github.com/mapleluvr) for #1781.
|
|
23
|
+
- Keep steer and follow-up receipt statuses separate from their redacted message previews (#1773).
|
|
24
|
+
- Create async lifecycle sidecars before external CLI workers begin worktree changes, so disappeared runners are reported as failed runs. Thanks [@fkhawajagh](https://github.com/fkhawajagh) for #1764.
|
|
25
|
+
- Preserve explicit read-only intent when escaped line separators surround no-edit wording. Thanks [@fkhawajagh](https://github.com/fkhawajagh) for #1765.
|
|
26
|
+
- Launch child Pi processes through the resolved CLI JavaScript on Windows, and run JavaScript `PI_SUBAGENT_PI_BINARY` overrides with Node. Thanks [@caohuipeng](https://github.com/caohuipeng) for #1768.
|
|
27
|
+
- Resolve the installed Pi CLI on Windows wrapper hosts from the forwarded package root, and report a clear error when no verified CLI can be found. Thanks [@lux032](https://github.com/lux032) for #1780.
|
|
28
|
+
|
|
29
|
+
## [0.61.0] - 2026-08-31
|
|
30
|
+
|
|
31
|
+
### Highlights
|
|
32
|
+
- Subagent runs use less context and repeat less status text, so everyday delegation is cheaper and easier to scan.
|
|
33
|
+
- Status, Fleet, widgets, RPC, and background-work views refresh with less duplicated work.
|
|
34
|
+
- Async recovery is more reliable when active status files, child reports, or provider fallback attempts go wrong.
|
|
35
|
+
- Workflow permissions are clearer with named workflow resources and `bg_wait` as the primary background wait tool.
|
|
36
|
+
- Model listings now show effective models for discovered and runtime-registered agents.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Add extension-owned named workflow resources so permission and policy extensions can distinguish trusted workflow resources from raw scripts. Thanks [@mathiasloh](https://github.com/mathiasloh) for #1751.
|
|
40
|
+
- Add workflow-only `globalConcurrencyLimit` and `maxSubagentSpawnsPerRun` overrides for top-level `workflowScript` calls. Thanks [@RapierCraft](https://github.com/RapierCraft) for #1760.
|
|
41
|
+
- Remove the deprecated compatibility wait alias; use `bg_wait` instead (#1729).
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- Show effective model mappings for discovered and runtime-registered subagents through management and `/subagents-models`. Thanks [@RapierCraft](https://github.com/RapierCraft) for #1732.
|
|
45
|
+
- Trim default subagent prompt guidelines to five parent-facing entries while keeping advanced workflow details in the packaged guide. Thanks [@Ran-Xing](https://github.com/Ran-Xing) for #1746.
|
|
46
|
+
- Reduce repeated heartbeat status updates during delegated runs while keeping foreground progress and complete terminal responses (#1739).
|
|
47
|
+
- Clarify that `fallbackModels` handles provider/model timeouts but not run-level `timeoutMs` / `maxRuntimeMs` expiry. Thanks [@kaplan-shaked](https://github.com/kaplan-shaked) for #1745.
|
|
48
|
+
- Pass requested session and timestamp context to background-work providers so they can avoid listing unrelated sessions while preserving strict validation (#1737).
|
|
49
|
+
- Avoid repeated external-run display normalization during Fleet refresh while still validating externally replaced or mutated records (#1736).
|
|
50
|
+
- Clarify that `oracle` and top-reasoning models are escalation tools, not routine defaults.
|
|
51
|
+
- Serve broad RPC status requests from restored in-memory state when safe, while preserving targeted status and transcript behavior (#1735).
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- Isolate corrupt active async status files during restoration so valid runs remain available and corrupt run artifacts are preserved. Thanks [@zhexulong](https://github.com/zhexulong) for #1756.
|
|
55
|
+
- Reduce async widget update churn during running workflows by repainting animation ticks without reinstalling the widget and coalescing close status refreshes (#1726).
|
|
56
|
+
- Avoid repeated staged workflow projection during widget rendering. Thanks [@kkkhs](https://github.com/kkkhs) for #1730.
|
|
57
|
+
- Preserve durable file-only child reports and continue read-only workflow review after malformed acceptance metadata (#1724).
|
|
58
|
+
- Preserve model origins across fallback and fork preparation, so eligible fallbacks work for unavailable configured primaries while invalid explicit models still fail closed. Thanks [@xz-dev](https://github.com/xz-dev) for #1747.
|
|
59
|
+
- Stop hidden 125ms spinner redraws while keeping progress refreshes and one-second animation frames (#1747).
|
|
60
|
+
|
|
6
61
|
## [0.60.0] - 2026-08-30
|
|
7
62
|
|
|
8
63
|
### Highlights
|
package/docs/agents.md
CHANGED
|
@@ -255,6 +255,7 @@ package: code-analysis
|
|
|
255
255
|
description: Fast codebase recon
|
|
256
256
|
aliases: explorer, code-scout
|
|
257
257
|
tools: read, grep, find, ls, bash, mcp:chrome-devtools
|
|
258
|
+
excludeTools: bash
|
|
258
259
|
extensions:
|
|
259
260
|
subagentOnlyExtensions: ./tools/child-only-search.ts
|
|
260
261
|
model: claude-haiku-4-5
|
|
@@ -283,7 +284,7 @@ allowNestedSubagents: true
|
|
|
283
284
|
Your system prompt goes here.
|
|
284
285
|
```
|
|
285
286
|
|
|
286
|
-
Simple-scalar list fields accept either a 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`:
|
|
287
|
+
Simple-scalar list fields accept either a comma-separated form or a newline block list with one `- item` per line. This applies to `tools`, `excludeTools`, `defaultReads`, `skill`/`skills`, `skillPath`, `fallbackModels`, `extensions`, and `subagentOnlyExtensions`:
|
|
287
288
|
|
|
288
289
|
```yaml
|
|
289
290
|
tools:
|
|
@@ -301,11 +302,12 @@ Field notes:
|
|
|
301
302
|
| `package` | Optional package identifier. A file with `name: scout` and `package: code-analysis` registers as `code-analysis.scout`; serialization keeps `name` and `package` separate. |
|
|
302
303
|
| `aliases` | Optional comma-separated or block-list names that resolve to this agent for selection and explicit `agent` and task inputs. Runtime status, persistence, and config still use the canonical `name`. Exact canonical names take precedence over aliases, and alias collisions between distinct canonical agents fail as ambiguous. |
|
|
303
304
|
| `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. |
|
|
305
|
+
| `excludeTools` | Optional child tool deny-list applied after normal tool resolution. With an explicit `tools` allowlist, matching names are removed; when `tools` is omitted, the names are forwarded to Pi as `--exclude-tools` so the ambient tool set is inherited minus those names. Unknown names are ignored by Pi without making the agent definition invalid. |
|
|
304
306
|
| `allowNestedSubagents` | Set `true` to authorize the child-safe nested `subagent` runtime without making omitted `tools` an allowlist. Inherited depth and capability ceilings remain authoritative. |
|
|
305
307
|
| `extensions` | Omitted means normal extensions; empty means no extensions; list values allowlist specific extensions. |
|
|
306
308
|
| `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. |
|
|
307
309
|
| `model` | Default model. Bare ids prefer the current provider when possible, then unique registry matches. |
|
|
308
|
-
| `fallbackModels` | Ordered backup models for provider/model failures such as quota, auth, timeout, or unavailable model. Ordinary task failures do not trigger fallback. |
|
|
310
|
+
| `fallbackModels` | Ordered backup models for provider/model failures such as quota, auth, provider-reported timeout, or unavailable model. Expiration of the run-level `timeoutMs` / `maxRuntimeMs` deadline is terminal and does not trigger fallback. Ordinary task failures do not trigger fallback. |
|
|
309
311
|
| `thinking` | Appended as a `:level` suffix at runtime unless a suffix is already present. |
|
|
310
312
|
| `systemPromptMode` | `replace` by default; `append` keeps Pi's base prompt. |
|
|
311
313
|
| `inheritProjectContext` | Keeps or strips inherited repository instruction blocks. |
|
|
@@ -319,7 +321,7 @@ Field notes:
|
|
|
319
321
|
| `defaultProgress` | Maintain `progress.md`. |
|
|
320
322
|
| `async` | Default a single-agent launch to background (`true`) or foreground (`false`) when the call omits `async`. Explicit call values and `forceTopLevelAsync` win. |
|
|
321
323
|
| `timeoutMs` | Positive integer default runtime deadline in milliseconds for single-agent launches. Foreground launches use 30 minutes when neither the call nor agent provides a timeout; explicit `timeoutMs`/`maxRuntimeMs` and agent defaults win. |
|
|
322
|
-
| `toolTimeoutMs` | Optional positive integer hard per-tool-call deadline in milliseconds. An explicit call value wins, then this agent default, global `toolTimeoutMs`, and `PI_SUBAGENT_TOOL_TIMEOUT_MS`. When omitted, known-fast built-in tools get a five-minute default; long-running tools get attention notices but no hard default. It does not extend the run-level deadline; `contact_supervisor`, `intercom`, and `
|
|
324
|
+
| `toolTimeoutMs` | Optional positive integer hard per-tool-call deadline in milliseconds. An explicit call value wins, then this agent default, global `toolTimeoutMs`, and `PI_SUBAGENT_TOOL_TIMEOUT_MS`. When omitted, known-fast built-in tools get a five-minute default; long-running tools get attention notices but no hard default. It does not extend the run-level deadline; `contact_supervisor`, `intercom`, and `bg_wait` are exempt. |
|
|
323
325
|
| `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. |
|
|
324
326
|
| `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. |
|
|
325
327
|
| `mutationTools` | Comma-separated extension tool names whose calls count as mutation attempts for the completion guard. This declares evidence only; list and load each tool through `tools` and its extension provider as usual. |
|
|
@@ -385,6 +387,8 @@ How `tools` behaves:
|
|
|
385
387
|
- `tools:` empty: emits `--no-tools`.
|
|
386
388
|
- `allowNestedSubagents: true`: explicitly enables child-safe nested fanout without turning omitted `tools` into an allowlist. Depth and inherited capability ceilings still apply.
|
|
387
389
|
|
|
390
|
+
`excludeTools` is applied after this resolution. It can narrow an explicit `tools` allowlist or, when `tools` is omitted, compose with Pi's ambient builtin tools through `--exclude-tools`. Runtime-injected tools are excluded only when their exact names are listed. An empty `excludeTools` list has no effect.
|
|
391
|
+
|
|
388
392
|
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.
|
|
389
393
|
|
|
390
394
|
More rules:
|
package/docs/configuration.md
CHANGED
|
@@ -36,7 +36,7 @@ Controls the duration, in milliseconds, for model exclusions. The default is `86
|
|
|
36
36
|
{ "toolDescriptionMode": "compact" }
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Controls the parent-facing `subagent` tool description registered at startup. The default registers split prompt metadata: a short tool description plus `promptSnippet` and `promptGuidelines`. Set `"full"` to register the complete description as one tool description, or `"compact"` to keep the execution modes, async/`
|
|
39
|
+
Controls the parent-facing `subagent` tool description registered at startup. The default registers split prompt metadata: a short tool description plus `promptSnippet` and `promptGuidelines`. Set `"full"` to register the complete description as one tool description, or `"compact"` to keep the execution modes, async/`bg_wait` guidance, child-safety boundary, management/action split, one-writer review guidance, and artifact/status essentials with less prompt bloat.
|
|
40
40
|
|
|
41
41
|
`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.
|
|
42
42
|
|
|
@@ -187,9 +187,9 @@ Controls the under-editor widget for active background runs. It defaults to `tru
|
|
|
187
187
|
{ "waitTool": { "enabled": true, "defaultTimeoutMs": 120000 } }
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
`defaultTimeoutMs` sets the blocking window used when a `
|
|
190
|
+
`defaultTimeoutMs` sets the blocking window used when a `bg_wait` call omits `timeoutMs`; explicit call values win, followed by this setting, then the 30-minute fallback. `bg_wait` is the only registered wait tool. When the window elapses, the tool returns a non-error `window_elapsed` result with the still-active work identities, and that work keeps running. Set `enabled` to `false` to make direct calls return immediately instead of blocking. 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 enabled and default-timeout values are passed explicitly to child runtimes. Headless `agent_end` auto-drain retains its own strict deadline and fails if required work remains unresolved. Invalid config or environment values fail instead of being coerced.
|
|
191
191
|
|
|
192
|
-
Blocking `
|
|
192
|
+
Blocking `bg_wait({ id: "..." })` keeps the current tool call open until that run changes. By default it returns when a run needs attention. Use `bg_wait({ stopOnAttention: false })` only for run-to-completion flows that should wait through idle or long-thinking attention; supervisor/contact requests still stop the wait. In a long-lived interactive parent session, `bg_wait({ id: "...", nonBlocking: true })` instead resolves the prefix once, persists the exact run identity, returns a subscription token immediately, and wakes that session on completion, failure, attention, reconciliation failure, or timeout. Use it for provider, detached, or other background work without a native completion notification; ordinary async subagent runs notify the parent natively and do not need a wait subscription. Armed subscriptions appear in ordinary `subagent({ action: "status" })` output and are not counted as active child work.
|
|
193
193
|
|
|
194
194
|
This is different from `waitTool.enabled=false`, which returns immediately without registering any future wake. Provider items remain available only to blocking fleet-wide waits; non-blocking subscriptions require one async or remembered detached foreground run id.
|
|
195
195
|
|
|
@@ -217,7 +217,7 @@ Forces depth-0 internal single, parallel, and chain runs into background mode an
|
|
|
217
217
|
{ "timeoutMs": 3600000 }
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
-
Global default runtime deadline, in milliseconds, for subagent runs. It replaces the built-in 30-minute backstop for foreground launches (single, parallel, chain, and workflowScript) and plain single-agent async runs whenever no call-level `timeoutMs`/`maxRuntimeMs` applies. For single-agent launches, selected agent frontmatter `timeoutMs` still wins. This only moves the *default*.
|
|
220
|
+
Global default runtime deadline, in milliseconds, for subagent runs. It replaces the built-in 30-minute backstop for foreground launches (single, parallel, chain, and workflowScript) and plain single-agent async runs whenever no call-level `timeoutMs`/`maxRuntimeMs` applies. For single-agent launches, selected agent frontmatter `timeoutMs` still wins. This only moves the *default*. Expiring this run-level deadline is terminal and does not trigger `fallbackModels`; only provider/model failures reported before the deadline can fall back.
|
|
221
221
|
|
|
222
222
|
Use it when foreground orchestration or plain async single-agent runs need a longer default than 30 minutes. It does not set async composite top-level deadlines, and it does not replace async fan-out child deadlines.
|
|
223
223
|
|
|
@@ -233,7 +233,7 @@ Optional hard per-tool-call deadline in milliseconds. When configured, a child t
|
|
|
233
233
|
|
|
234
234
|
Without a configured value, Pi still applies a five-minute hard timeout to known-fast built-in tools: `read`, `grep`, `find`, `ls`, `edit`, `write`, and `structured_output`. Long-running tools such as `bash`, custom tools, and MCP tools do not get a hard default. They get the normal open-tool attention notice after `activeNoticeAfterMs` and remain bounded by the run-level deadline.
|
|
235
235
|
|
|
236
|
-
The tool timer tracks each active `toolCallId` separately and never extends the run-level deadline: when the remaining run budget is shorter, the ordinary run-level timeout wins. `contact_supervisor`, `intercom`, and `
|
|
236
|
+
The tool timer tracks each active `toolCallId` separately and never extends the run-level deadline: when the remaining run budget is shorter, the ordinary run-level timeout wins. `contact_supervisor`, `intercom`, and `bg_wait` are exempt because their legitimate purpose can be to wait for a human, supervisor, or background run. Use hard tool timeouts only for wedge protection; an elapsed timeout is not a mutation-safe boundary. Configured values must be positive integers no greater than `2147483647`; invalid or out-of-range values are rejected with a visible error rather than silently ignored.
|
|
237
237
|
|
|
238
238
|
## `globalConcurrencyLimit`
|
|
239
239
|
|
|
@@ -243,6 +243,8 @@ The tool timer tracks each active `toolCallId` separately and never extends the
|
|
|
243
243
|
|
|
244
244
|
Caps simultaneously running children inside one run, including durable legacy multi-child runs and `workflowScript` launches through `runs.run`/`runs.all`. Queued workflow children retain their stable keys and begin when a running sibling releases capacity. The default is `20`.
|
|
245
245
|
|
|
246
|
+
Inline or file-backed top-level workflow calls may set a positive safe-integer `globalConcurrencyLimit` to override this value for that workflow. The override is workflow-only and is not forwarded to child calls.
|
|
247
|
+
|
|
246
248
|
## `maxSubagentSpawnsPerSession`
|
|
247
249
|
|
|
248
250
|
```json
|
|
@@ -261,6 +263,8 @@ Optionally caps the total number of child subagent launches during one parent se
|
|
|
261
263
|
|
|
262
264
|
Caps cumulative logical child admissions in one top-level run tree. The default is `64`. `PI_SUBAGENT_MAX_SPAWNS_PER_RUN` overrides the config when it is a positive integer. Invalid, zero, or missing values fall back to the configured positive value or `64`.
|
|
263
265
|
|
|
266
|
+
Inline or file-backed top-level workflow calls may set a positive safe-integer `maxSubagentSpawnsPerRun`; it overrides the environment and config for that workflow. Inherited nested budgets remain authoritative, and the override is not forwarded to child calls.
|
|
267
|
+
|
|
264
268
|
The budget counts single launches, expanded `tasks`/`count`, static chain steps and parallel groups, actual dynamic `expand` items, appended chain steps, workflow children, and nested child calls. Static and materialized dynamic groups are admitted atomically. Startup retries, model fallback, and retained-child resume reuse the original logical child claim. Claims are never released or refunded. This cap is independent from the session-wide cumulative spawn budget and `globalConcurrencyLimit`.
|
|
265
269
|
|
|
266
270
|
## `maxActiveAsyncRunsPerSession`
|
package/docs/extension-api.md
CHANGED
|
@@ -32,6 +32,7 @@ Method notes:
|
|
|
32
32
|
- `steer` requires an async run `id` (plus optional child `index`) and a non-empty `message`; its reply preserves the normal acknowledged-delivery result. Optional `mode` values are `steer` (default), `follow_up`, and `auto`, and receipts include `deliveryStatus: "delivered" | "queued"`. RPC steering disables the direct tool's pause-and-revive recovery in every mode so an extension keeps authority over the exact child it spawned; `ping.capabilities.nonRecoveringSteer` advertises this guarantee.
|
|
33
33
|
- `resume` requires a run target and non-empty `message`. It delegates to the existing revival path, which validates current-session ownership, persisted session/recovery metadata, stopped/live state, capability ceilings, and the exclusive session lease before returning the new async run details. Callers may request a `file-only` output path for the revived result without overriding its model, tools, or budgets. `ping.capabilities.resume` advertises this seam.
|
|
34
34
|
- `stop` targets current-session top-level async runs through the stop control channel and records a `stopped` lifecycle instead of reporting a timeout.
|
|
35
|
+
- `status` keeps targeted and rich requests on the executor-backed path. A request with no `id`, `runId`, `dir`, `index`, `view`, or `lines` may use the restored in-memory projections and a short summary; when the live state is missing, stale, session-mismatched, or not restored, it falls back to normal executor status. Status `view`, `lines`, and `index` are forwarded for targeted transcript/fleet requests. Successful replies retain `text`, `details`, `fleet`, and `asyncSnapshot`; the short summary intentionally omits canonical filesystem details, wait subscriptions, and budget annotations.
|
|
35
36
|
|
|
36
37
|
Capability advertisements on `ping`:
|
|
37
38
|
|
|
@@ -42,6 +43,7 @@ Capability advertisements on `ping`:
|
|
|
42
43
|
- `processTerminalProof` — the process-terminal proof status (see [observability.md](observability.md#process-terminal-proof)).
|
|
43
44
|
- `nonRecoveringSteer` — RPC steering never pauses-and-revives.
|
|
44
45
|
- `resume` — the revival seam described above.
|
|
46
|
+
- `statusProjection: { version: 1, untargeted: "in-memory-when-ready", targeted: "executor" }` — untargeted status may use restored bounded projections; targeted or rich status remains executor-backed.
|
|
45
47
|
- `fleetStatus: { version: 1 }` — successful `status` replies additionally include `data.fleet`.
|
|
46
48
|
|
|
47
49
|
Structured delegation progress updates carry `runId` as soon as foreground execution allocates it, so a caller can retain the package-owned revival target even if its own tool turn is interrupted before the terminal response. Foreground `details.results[]` rows also include a numeric `index` that is unique within the run and stable across partial progress snapshots and the final result; use `(runId, index)` instead of row position to correlate single, counted parallel, and chain children.
|
|
@@ -54,6 +56,8 @@ Entries are bounded, current-session public display records with an opaque recon
|
|
|
54
56
|
|
|
55
57
|
The DTO intentionally never exposes run, async, or tool IDs. Clients must ignore unknown fields and fall back to status text when the capability is absent.
|
|
56
58
|
|
|
59
|
+
`data.asyncSnapshot` is a separate bounded projection included on successful status replies when available. Its `runs[].id` contains the async run id; unlike the fleet DTO, it is not an opaque display key. Fleet keys remain opaque and must not be interpreted as run or async identifiers.
|
|
60
|
+
|
|
57
61
|
### Scope
|
|
58
62
|
|
|
59
63
|
`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.
|
|
@@ -129,7 +133,7 @@ updateExternalRun(ctx.sessionManager.getSessionId(), "dependency-review", {
|
|
|
129
133
|
unregisterExternalRun(ctx.sessionManager.getSessionId(), "dependency-review");
|
|
130
134
|
```
|
|
131
135
|
|
|
132
|
-
The API validates and caches bounded display fields when the caller registers or updates a job. FleetView reads that cache only. It does not poll caller code. `snapshotExternalRuns(sessionId)` and `listExternalRuns(sessionId)` return bounded current-session snapshots. By default, malformed
|
|
136
|
+
The API validates and caches bounded display fields when the caller registers or updates a job. FleetView reads that cache only. It does not poll caller code. `snapshotExternalRuns(sessionId)` and `listExternalRuns(sessionId)` return bounded current-session snapshots. Snapshots filter the session-qualified cache key before inspecting record fields; API-written records avoid repeated normalization through module-private provenance, while records replaced or mutated through the process-local registry are validated on demand. By default, malformed records for the requested session throw with the validation error. Display-only Fleet callers can pass `{ ignoreMalformed: true, onMalformedRecord }` to remove bad records and keep rendering with a programmatic diagnostic.
|
|
133
137
|
|
|
134
138
|
External jobs are observational. The caller owns execution, persistence, cancellation, and result delivery. FleetView does not expose stop, steer, resume, cancel, or Herdr controls for them. Supplied report and transcript paths are shown as bounded text only; FleetView does not read arbitrary external paths.
|
|
135
139
|
|
|
@@ -229,6 +233,8 @@ Results:
|
|
|
229
233
|
- Result mode is explicit. Text remains literal even when it looks like JSON. Structured mode returns the separately captured, schema-validated JSON value.
|
|
230
234
|
- Terminal usage reports input, output, cache-read, cache-write, cost, turns, tool calls, and duration alongside the effective model and thinking level when known.
|
|
231
235
|
|
|
236
|
+
Live update events are bounded progress snapshots, not patches, so consumers should replace the prior snapshot rather than merge it as a delta. Structured delegation coalesces heartbeats whose delegation-visible progress and recent output are unchanged; a duration-only heartbeat therefore does not produce another update. The terminal response remains authoritative for the complete result, error, and final usage details.
|
|
237
|
+
|
|
232
238
|
Bounds:
|
|
233
239
|
|
|
234
240
|
- Schemas are capped at 64 KiB; tasks and returned text/structured values are capped at 1 MiB, with smaller bounds on identity/configuration strings and a maximum `timeoutMs` of 2,147,483,647.
|
|
@@ -279,7 +285,7 @@ Schedules created while a ceiling is active are rejected until durable schedule
|
|
|
279
285
|
|
|
280
286
|
## Background-work provider API
|
|
281
287
|
|
|
282
|
-
Other Pi extensions can make their current-session jobs visible to `
|
|
288
|
+
Other Pi extensions can make their current-session jobs visible to `bg_wait` through the process-local provider contract:
|
|
283
289
|
|
|
284
290
|
```ts
|
|
285
291
|
import { registerBackgroundWorkProvider } from "pi-subagents/background-work";
|
|
@@ -287,8 +293,8 @@ import { registerBackgroundWorkProvider } from "pi-subagents/background-work";
|
|
|
287
293
|
const dispose = registerBackgroundWorkProvider({
|
|
288
294
|
name: "my-background-extension",
|
|
289
295
|
wakeChannels: ["my-extension:job-finished"],
|
|
290
|
-
listActiveWork: () => jobs
|
|
291
|
-
.filter((job) => job.status === "running")
|
|
296
|
+
listActiveWork: (context) => jobs
|
|
297
|
+
.filter((job) => job.status === "running" && (!context || job.ownerSessionId === context.sessionId))
|
|
292
298
|
.map((job) => ({ id: job.id, sessionId: job.ownerSessionId })),
|
|
293
299
|
reconcile: ({ sessionId, nowMs }) => reconcileJobs(sessionId, nowMs),
|
|
294
300
|
});
|
|
@@ -296,13 +302,14 @@ const dispose = registerBackgroundWorkProvider({
|
|
|
296
302
|
|
|
297
303
|
Semantics:
|
|
298
304
|
|
|
299
|
-
- Each item needs a stable provider-local ID and the exact Pi session ID that owns it. `
|
|
305
|
+
- Each item needs a stable provider-local ID and the exact Pi session ID that owns it. `bg_wait` captures those identities rather than a count, so one job finishing while another starts still satisfies first-completion waits without losing the replacement.
|
|
306
|
+
- `listActiveWork` receives an optional `{ sessionId, nowMs }` context during snapshots. Providers can use `sessionId` to avoid scanning unrelated work; existing zero-argument `() => items` providers continue to work, and returned items are still validated and filtered to the exact requested session.
|
|
300
307
|
- 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.
|
|
301
308
|
- Wake channels only shorten polling; validated snapshots remain authoritative.
|
|
302
309
|
- Providers share a registry through `Symbol.for("pi-subagents.background-work.v1")`, allowing independently loaded extension modules to meet in one Pi process.
|
|
303
310
|
- 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.
|
|
304
311
|
|
|
305
|
-
Child processes do not gain provider tools or extensions automatically. Add `
|
|
312
|
+
Child processes do not gain provider tools or extensions automatically. Add `bg_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.
|
|
306
313
|
|
|
307
314
|
## External job provider bridge
|
|
308
315
|
|
|
@@ -399,7 +406,7 @@ The API returns discriminated structured results with canonical project root, bi
|
|
|
399
406
|
|
|
400
407
|
A host that embeds this extension owns whether completion wakes can be delivered at all.
|
|
401
408
|
|
|
402
|
-
Ordinary async and foreground completion wakes use `registerSubagentNotify` and `sendCompletion`. They listen for completion events and deliver through `pi.sendMessage(..., { triggerTurn })`. Session shutdown stops the result watcher and disposes this completion notifier. `createWaitSubscriptionManager` is separate: it is the explicit non-blocking `
|
|
409
|
+
Ordinary async and foreground completion wakes use `registerSubagentNotify` and `sendCompletion`. They listen for completion events and deliver through `pi.sendMessage(..., { triggerTurn })`. Session shutdown stops the result watcher and disposes this completion notifier. `createWaitSubscriptionManager` is separate: it is the explicit non-blocking `bg_wait` subscription path for work without native notification, not the ordinary completion wake path.
|
|
403
410
|
|
|
404
411
|
Detached children do not stop when the session does. They are the host process's children, not the session's, so the run keeps going, completes, and notifies nobody. What is lost is the notification, not the work.
|
|
405
412
|
|
package/docs/models.md
CHANGED
|
@@ -100,7 +100,7 @@ A setup that works well in practice: route agents by task shape instead of runni
|
|
|
100
100
|
|
|
101
101
|
The routing rule: use the capability tiers (1–3) when the task is well-scoped, and the intent tier (4) when scoping or judging is the task itself.
|
|
102
102
|
|
|
103
|
-
Give tier-4 agents cross-provider `fallbackModels` so subscription usage limits degrade gracefully instead of failing the run. Fallback triggers on rate-limit and
|
|
103
|
+
Give tier-4 agents cross-provider `fallbackModels` so subscription usage limits degrade gracefully instead of failing the run. Fallback triggers on retryable provider/model failures such as rate-limit, overload, unavailable-model, and provider-reported timeout errors. The outer run-level `timeoutMs` / `maxRuntimeMs` deadline is terminal and does not start another fallback attempt:
|
|
104
104
|
|
|
105
105
|
```yaml
|
|
106
106
|
---
|
package/docs/observability.md
CHANGED
|
@@ -157,7 +157,7 @@ For a top-level async run, `details.asyncDir` points at that directory; the fina
|
|
|
157
157
|
|
|
158
158
|
The result file is consumed and deleted once its completion notice is delivered. Before deletion, the watcher writes a versioned replay record under `<resultsDir>/completion-replay/<runId>.json` and a bounded output archive under `<resultsDir>/output-archives/<runId>.json`. Replay records expire with the completion deduplication window and are best-effort temporary state, not a permanent run ledger.
|
|
159
159
|
|
|
160
|
-
`
|
|
160
|
+
`bg_wait` surfaces a slim projection of each terminal payload it covered in its own tool-result `details.completions` — run identity, per-child agent/`runId`/success, artifact paths, and the bounded `archivePath`, without duplicating output text. It reads the replay when watcher delivery or a watcher restart has removed the one-shot result file and in-memory completion state is unavailable. Durable non-blocking wait subscriptions use the same replay in their delivered details. Workflow result files record each child's `runId` explicitly, since a workflow child's `artifactPaths` entry points at its saved output rather than the artifact files keyed by the id. Extensions observing `tool_result` events can read run and artifact identity from there instead of parsing the text summary.
|
|
161
161
|
|
|
162
162
|
Output archives reference an existing child output artifact or session file when one is available. For children without either file, the archive stores a per-child `result-tail` entry with `resultIndex`, bounded to 64 KiB per child, and records whether it was truncated. Replay and archive JSON use `version: 1`; consumers must ignore unknown fields.
|
|
163
163
|
|
package/docs/tool-reference.md
CHANGED
|
@@ -4,12 +4,21 @@ Parameters and actions for the `subagent` tool. These are what the LLM passes wh
|
|
|
4
4
|
|
|
5
5
|
## Execution examples
|
|
6
6
|
|
|
7
|
-
Chaining is code-driven through `workflowScript`. Use `await runs.run(...)` for sequential steps and `await runs.all([{ key, agent, task }, ...])` for ordinary parallel fanout. `runs.all` resolves to an ordered array, not a key map, so use indexes, destructuring, or `.map(...)`, not `results.<key>`. Do not read `.output` from an unawaited `runs.run` launch. Stored `runs.run` promises are only for the advanced rolling fanout pattern under [Workflow steering](#workflow-steering), where every promise is later observed with direct `await`, `Promise.race`, or `Promise.all`. Legacy top-level `chain`, `tasks`, and `parallel` inputs are not supported. Helper functions must be plain functions or explicit Promise chains. Nested `async function` helpers, async arrows, and async methods are rejected so child-launch tracking stays portable across Node and Bun.
|
|
7
|
+
Chaining is code-driven through `workflowScript`. Use `await runs.run(...)` for sequential steps and `await runs.all([{ key, agent, task }, ...])` for ordinary parallel fanout. `runs.all` resolves to an ordered array, not a key map, so use indexes, destructuring, or `.map(...)`, not `results.<key>`. Do not read `.output` from an unawaited `runs.run` launch. Stored `runs.run` promises are only for the advanced rolling fanout pattern under [Workflow steering](#workflow-steering), where every promise is later observed with direct `await`, `Promise.race`, or `Promise.all`. Legacy top-level `chain`, `tasks`, and `parallel` inputs are not supported. Helper functions must be plain functions or explicit Promise chains. Nested `async function` helpers, async arrows, and async methods are rejected so child-launch tracking stays portable across Node and Bun. For permission-sensitive host calls, use an extension-owned named resource such as `{ workflow: "run-ci", args: { command: "npm test" } }`; raw public `workflowScript`/`workflowScriptPath` inputs have unknown resource provenance and cannot call `runs.host`. A resolved resource may internally use `runs.host(key, { kind: "command", command, timeoutMs, output?, role?, provider? })` within its authority ceiling; there is no per-step `cwd`, and commands and relative output paths use the workflow `cwd`. Set `cwd` on the outer `subagent({...})` request instead, or put a trusted directory change in the command (for example, `cd /path/to/worktree && npm test`).
|
|
8
8
|
|
|
9
9
|
Use `{ action: "validate", workflowScript }` to check statically decidable syntax and structure without launching children. It returns `{ ok, errors }` and fails the tool call when `ok` is false. Dynamic keys and values remain valid because runtime-only cases are not guessed.
|
|
10
10
|
|
|
11
11
|
Use `workflowScriptPath` instead of `workflowScript` to load the same JavaScript statement body from a file. The two fields are mutually exclusive. Relative paths resolve against the request `cwd`, and absolute paths pass through. The host reads the file before validation, scheduling, or sandbox execution. The workflow sandbox still has no filesystem access. Missing, unreadable, and empty files fail as file input errors.
|
|
12
12
|
|
|
13
|
+
For permission-extension interoperability, use one of the package-owned named resources with bounded `args` instead of caller-supplied workflow text:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
{ workflow: "review", args: { task: "Review the auth flow" } }
|
|
17
|
+
{ workflow: "run-ci", args: { command: "npm test" } }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The host resolves the script and authority internally and records bounded provenance in workflow details and receipts. Named resources cannot be combined with `agent`, `task`, `workflowScript`, or `workflowScriptPath`; user/project resource registries are not part of this first slice.
|
|
21
|
+
|
|
13
22
|
```js
|
|
14
23
|
{ workflowScriptPath: "workflows/review.js", cwd: "/path/to/project" }
|
|
15
24
|
{ action: "validate", workflowScriptPath: "workflows/review.js" }
|
|
@@ -99,8 +108,8 @@ The complete plain-JSON inventory is validated before the first launch (maximum
|
|
|
99
108
|
| `async` | boolean | default-on | Background execution. Workflows default to background. `async:false` blocks the parent until completion. |
|
|
100
109
|
| `chatProgress` | `auto \| off \| live-card` | `auto` | WorkflowScript chat projection. `auto` renders a live in-chat card only for watched foreground workflows in the same Git repository, including managed worktrees; it is off otherwise. Explicit `live-card` requires `async:false` and the same Git repository. Async workflows have no inline live card, so omit `chatProgress` or use `auto`/`off`; use `async:false` only when the parent must block. |
|
|
101
110
|
| `isolation` | `none \| worktree` | - | Workflow child isolation. `none` runs in the shared cwd and does not need Git. `worktree` requires a managed Git worktree. Do not combine it with a contradictory `worktree` value. |
|
|
102
|
-
| `timeoutMs` / `maxRuntimeMs` | number | config `timeoutMs`, else 30 min foreground / single-agent async | Optional run-level max runtime in milliseconds. When omitted, the global [`timeoutMs`](configuration.md#timeoutms) config provides the default; absent that, foreground and plain single-agent async runs fall back to 30 minutes, while composite async runs (chains, parallel tasks, workflows) stay unbounded at the top level. |
|
|
103
|
-
| `toolTimeoutMs` | number | fast-tool default | Optional positive hard per-tool-call deadline in milliseconds. Precedence: call value → agent frontmatter → config → `PI_SUBAGENT_TOOL_TIMEOUT_MS`. The timer starts on `tool_execution_start`, clears on the matching `tool_execution_end`, and terminates the run with `timedOut: true` if the tool remains open. When omitted, known-fast built-in tools get a five-minute default; long-running tools get attention notices but no hard default. It never extends the run deadline; `contact_supervisor`, `intercom`, and `
|
|
111
|
+
| `timeoutMs` / `maxRuntimeMs` | number | config `timeoutMs`, else 30 min foreground / single-agent async | Optional run-level max runtime in milliseconds. When omitted, the global [`timeoutMs`](configuration.md#timeoutms) config provides the default; absent that, foreground and plain single-agent async runs fall back to 30 minutes, while composite async runs (chains, parallel tasks, workflows) stay unbounded at the top level. Expiration of this run-level deadline is terminal and does not trigger `fallbackModels`. |
|
|
112
|
+
| `toolTimeoutMs` | number | fast-tool default | Optional positive hard per-tool-call deadline in milliseconds. Precedence: call value → agent frontmatter → config → `PI_SUBAGENT_TOOL_TIMEOUT_MS`. The timer starts on `tool_execution_start`, clears on the matching `tool_execution_end`, and terminates the run with `timedOut: true` if the tool remains open. When omitted, known-fast built-in tools get a five-minute default; long-running tools get attention notices but no hard default. It never extends the run deadline; `contact_supervisor`, `intercom`, and `bg_wait` are exempt. |
|
|
104
113
|
| `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. |
|
|
105
114
|
| `usageBudget` | object | none | Optional root-only reported-usage budget `{ tokens?: { soft?, hard }, costUsd?: { soft?, hard } }`. Soft limits are status-only. Hard limits prevent later child launches after reported usage is reconciled; already-running children are not stopped and no reservations are made. |
|
|
106
115
|
| `cwd` | string | runtime cwd | Override working directory. |
|
|
@@ -411,7 +420,7 @@ Acceptance provenance is stored separately from child prose. `evidenceStatus` pr
|
|
|
411
420
|
|
|
412
421
|
### The acceptance report
|
|
413
422
|
|
|
414
|
-
For `attested` or stricter levels, the child prompt includes a standardized acceptance section and asks for a fenced `acceptance-report` JSON block.
|
|
423
|
+
For `attested` or stricter levels, the child prompt includes a standardized acceptance section and asks for a fenced `acceptance-report` JSON block. With `outputSchema`, set `acceptance.report: "on"` to require the same report in the final `structured_output` call, or `"off"` to keep the fenced-report path. Omitting `report` preserves the default behavior. Runs without `outputSchema` never gain a standalone structured-output tool from this option.
|
|
415
424
|
|
|
416
425
|
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.
|
|
417
426
|
|
package/docs/workflows.md
CHANGED
|
@@ -57,6 +57,17 @@ subagent({ action: "validate", workflowScriptPath: "workflows/review.js" });
|
|
|
57
57
|
|
|
58
58
|
The fields are mutually exclusive. Relative paths resolve against the request `cwd`; absolute paths pass through. The host reads the file before validation, schedule creation, or workflow sandbox execution. The sandbox still has no filesystem access. Missing, unreadable, and empty files return file input errors instead of script syntax errors.
|
|
59
59
|
|
|
60
|
+
### Named workflow resources for permission extensions
|
|
61
|
+
|
|
62
|
+
Use a named workflow resource when a permission or policy extension needs to distinguish extension-resolved workflow content from raw model-authored scripts:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
subagent({ workflow: "review", args: { task: "Review the change" } });
|
|
66
|
+
subagent({ workflow: "run-ci", args: { command: "npm test" } });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The host resolves the name and validates bounded plain-JSON `args` before starting the workflow. Resource provenance is recorded in workflow details and receipts for downstream permission/policy checks. Resource authority is not caller-supplied: `runs.host` is available only when the resolved resource explicitly grants the requested host key and command. Inline `workflowScript` and `workflowScriptPath` remain raw, unknown-provenance inputs, so their `runs.host` calls are unavailable through the public execution boundary. Named resources cannot be combined with `agent`, `task`, `workflowScript`, or `workflowScriptPath`; this first slice ships only the package-owned `review` and `run-ci` resources, not a user/project resource registry.
|
|
70
|
+
|
|
60
71
|
### Opt-in bounded workflows
|
|
61
72
|
|
|
62
73
|
Composite workflows have no default parent deadline. Add bounds only when the workflow contract calls for them:
|
|
@@ -162,23 +173,13 @@ The board is bounded and contains only lane/stage keys, state, success, retained
|
|
|
162
173
|
|
|
163
174
|
### Host command steps
|
|
164
175
|
|
|
165
|
-
Use `
|
|
176
|
+
Use the named `run-ci` resource when a permission/policy extension needs to admit one supported non-interactive command as workflow evidence instead of a child-agent run:
|
|
166
177
|
|
|
167
178
|
```js
|
|
168
|
-
subagent({
|
|
169
|
-
const tests = await runs.host("unit-tests", {
|
|
170
|
-
kind: "command",
|
|
171
|
-
command: "npm run test:unit",
|
|
172
|
-
timeoutMs: 120000,
|
|
173
|
-
output: "reports/unit-tests.log",
|
|
174
|
-
role: "ci",
|
|
175
|
-
provider: "local"
|
|
176
|
-
});
|
|
177
|
-
return { state: tests.state, exitCode: tests.exitCode, outputPath: tests.outputPath };
|
|
178
|
-
` });
|
|
179
|
+
subagent({ workflow: "run-ci", args: { command: "npm test", timeoutMs: 120000 } });
|
|
179
180
|
```
|
|
180
181
|
|
|
181
|
-
The first version supports only `
|
|
182
|
+
The first named resource version supports only `npm test` and `npm run typecheck`, with bounded timeout values. Its resolved script uses `runs.host("ci", ...)` and the resource authority admits only the selected command. **There is no per-step `cwd` field:** the command and relative output path use the workflow cwd. Set `cwd` on the outer `subagent({...})` request when the workflow should run in another directory. The command has no stdin, receives the workflow cwd, and must be awaited or returned. Stdout, stderr, and the saved log are bounded. A nonzero exit, timeout, abort, or output-write failure fails the workflow. Async status and terminal receipts store the bounded host-step state; renderers do not run commands or read command output.
|
|
182
183
|
|
|
183
184
|
### Steering a workflow child
|
|
184
185
|
|
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
|
+
• bg_wait - Wait for background/provider/detached work without native completion notifications
|
|
91
91
|
|
|
92
92
|
Documentation: ${EXTENSION_DIR}/README.md
|
|
93
93
|
`);
|
package/package.json
CHANGED
|
@@ -55,10 +55,12 @@ block. Final reviews, validation gates, oracle checks, and publication checks
|
|
|
55
55
|
stay async.
|
|
56
56
|
|
|
57
57
|
In an ordinary interactive session, yield after launching or triaging useful
|
|
58
|
-
async lanes and let Pi wake the parent on completion;
|
|
59
|
-
|
|
60
|
-
`
|
|
61
|
-
|
|
58
|
+
async lanes and let Pi wake the parent on completion; ordinary async subagents
|
|
59
|
+
already have native completion notifications, so do not call `bg_wait()` merely
|
|
60
|
+
because a child is active. Use blocking `bg_wait()` only for provider,
|
|
61
|
+
detached, or other background work without a native notification when a
|
|
62
|
+
headless/run-to-completion contract or a required same-turn artifact makes the
|
|
63
|
+
result necessary before this turn ends. For
|
|
62
64
|
“continue/orchestrate/work until done,” keep the lane board moving while a safe
|
|
63
65
|
immediate action remains; if only async lanes are running, record the revisit
|
|
64
66
|
trigger and yield.
|
|
@@ -21,7 +21,7 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
|
|
|
21
21
|
become second decision-makers.
|
|
22
22
|
- **Respect the fixed authority policy.** `authorityPolicy` is a small `auto` / `confirm` / `forbid` map for supported operational actions. Worktree discard, destructive cleanup, and spawn-budget grants default to confirmation; stop, steer, and schedule creation remain automatic. Use `worktree.discard` with the durable `handoffPath`; confirm-required actions refuse safely without an interactive UI and retained paths include manual Git recovery commands.
|
|
23
23
|
|
|
24
|
-
Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `
|
|
24
|
+
Runtime config can change orchestration behavior. `intercomBridge.resultDelivery: false` disables only external acknowledged grouped-result delivery when native parent notifications own completion; supervisor asks/progress stay active, and enabled transport failures are still reported. `asyncByDefault` and `forceTopLevelAsync` affect whether launches detach; `waitTool` can make direct `bg_wait()` calls return immediately while headless auto-drain remains active, and its effective value is propagated to child runtimes; `globalConcurrencyLimit` bounds concurrent fanout, while a positive `maxSubagentSpawnsPerSession` optionally caps cumulative launches (`0` or unset is unlimited). Status and doctor report the budget; static work preflights declared capacity; only the settled root interactive parent can use `grant-spawn-budget` after native confirmation, with total grants bounded by the original cap. Compaction does not reset usage or grants; `singleRunOutputBaseDir` and `worktreeBaseDir` route outputs and worktrees; `completionBatch` groups async notifications. `artifactDir` is `session` (default), `project`, or `temp` and chooses where subagent artifacts are stored. Set `asyncWidget: false` to hide the above-editor background-run widget when a companion footer or dashboard owns that space (fleet inspector remains available). Per-run `artifacts: false` disables artifact capture for that launch. Async status and result artifacts include `lifecycleArtifactVersion` and fields such as `workflowGraph`, `steps`, `results`, `totalTokens`, `totalCost`, `turnCount`, `toolCount`, and nested `children`. Child protocol failures expose a structured `protocolError`; `protocol_output_limit` means a child emitted a JSONL line above the 16 MiB live-parser cap. Prefer these artifacts and `status` views over scraping terminal output.
|
|
25
25
|
|
|
26
26
|
### Keep report artifacts out of the repository root
|
|
27
27
|
|
|
@@ -140,17 +140,45 @@ Async does not mean parallel writes. Do not edit the same active worktree while
|
|
|
140
140
|
Do not end your turn immediately after launching an async child if you promised to keep working. Continue the local inspection, synthesis, or validation prep, then check the async run when its result is needed. If no safe independent work remains, return control and let Pi wake the session; do not convert the child to foreground.
|
|
141
141
|
|
|
142
142
|
In an ordinary interactive chat, normally return control after launching or
|
|
143
|
-
triaging useful async work and let Pi wake the session on completion;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
143
|
+
triaging useful async work and let Pi wake the session on completion; ordinary
|
|
144
|
+
async subagents already have native completion notifications, so do not call
|
|
145
|
+
`bg_wait()` merely to wait. A run-to-completion user request is not by itself a
|
|
146
|
+
reason to use foreground children. Override the normal yield-and-wake flow
|
|
147
|
+
only when this exact turn cannot safely end without the result of provider,
|
|
148
|
+
detached, or other background work without a native notification, such as a
|
|
149
|
+
headless provider flow or a skill contract that must produce a same-turn
|
|
150
|
+
artifact. Use `bg_wait()`, not `async:false`, for that current-turn dependency.
|
|
151
|
+
Never substitute sleep or status-polling loops.
|
|
152
|
+
|
|
153
|
+
`bg_wait()` returns when the next initially active async run or registered
|
|
154
|
+
provider item finishes or a subagent needs attention. Use it for background,
|
|
155
|
+
provider, or detached work without native completion delivery; ordinary async
|
|
156
|
+
subagent runs notify the parent automatically. Use `bg_wait({ all: true })` for
|
|
157
|
+
all work active at call time, `bg_wait({ id: "..." })` for one async or
|
|
158
|
+
remembered detached foreground run, and `bg_wait({ timeoutMs })` to cap the
|
|
159
|
+
block; active work keeps running if it elapses. `bg_wait({ stopOnAttention:
|
|
160
|
+
false })` keeps a blocking wait through idle or long-thinking attention, but
|
|
161
|
+
supervisor/contact requests still stop it. In a long-lived interactive parent
|
|
162
|
+
session, use `bg_wait({ id: "...", nonBlocking: true })` only for a known
|
|
163
|
+
detached or otherwise non-notifying run to resolve the prefix to one exact run,
|
|
164
|
+
persist an armed subscription, return immediately, and wake later on
|
|
165
|
+
completion, failure, attention, reconciliation failure, or timeout. Ordinary
|
|
166
|
+
status lists armed subscriptions separately from active children. This differs
|
|
167
|
+
from disabling `waitTool`, which returns immediately without arming a future
|
|
168
|
+
wake. If a foreground child detaches for supervisor coordination, reply first,
|
|
169
|
+
then wait on its id; do not resume or launch a replacement while it remains
|
|
170
|
+
detached. Headless sessions also auto-drain exact current-session work at
|
|
171
|
+
`agent_end` as a final safeguard.
|
|
172
|
+
|
|
173
|
+
Providers are discovered through the `pi-subagents/background-work` registry and
|
|
174
|
+
must expose a stable item id and owning session id. Load a provider through the
|
|
175
|
+
child’s `extensions` or `subagentOnlyExtensions` and allow `bg_wait` in its
|
|
176
|
+
tools. For
|
|
177
|
+
non-interactive fleets, launch N workers, wait for the next completion, react,
|
|
178
|
+
and replace as needed; use `all: true` only when intentionally draining the
|
|
179
|
+
fleet. If `PI_SUBAGENT_WAIT_TOOL_ENABLED` disables blocking, direct waits return
|
|
180
|
+
immediately, but headless `agent_end` auto-drain still surfaces provider,
|
|
181
|
+
reconciliation, or timeout failures.
|
|
154
182
|
|
|
155
183
|
```typescript
|
|
156
184
|
subagent({
|
|
@@ -455,6 +483,8 @@ history as a baseline contract.
|
|
|
455
483
|
|
|
456
484
|
Use `oracle` as a smart-friend escalation when the parent needs help with trajectory rather than diff inspection: architectural boundaries, model capability routing, merge conflicts, reviewer disagreement, context drift after long work, a worker about to invent a pattern, or fixes that require product/scope tradeoffs. Ask broad questions when the right concern is unclear, and let `oracle` point out missing context or files the parent should inspect before asking again. Keep `oracle` advisory unless it has been explicitly assigned the single writer role.
|
|
457
485
|
|
|
486
|
+
Do not use `oracle` or Sol-high models to satisfy routine fresh-review gates, ordinary follow-up reviews, or ordinary performance crit passes. Use the `reviewer` role for those reviews, then escalate only when normal review/bot/CI evidence exposes an unresolved invariant, root-cause, model-routing, or product-tradeoff question.
|
|
487
|
+
|
|
458
488
|
## Subagent + Intercom Coordination
|
|
459
489
|
|
|
460
490
|
`pi-subagents` includes native supervisor coordination. Child agents can use `contact_supervisor` to ask the exact parent session that spawned them; messages are scoped by parent session id and should not appear in other Pi sessions. Parents inspect or reply with `subagent_supervisor`. This path does not require `pi-intercom`.
|
|
@@ -34,7 +34,7 @@ While one lane waits, run safe independent preparation, validation, or fresh rea
|
|
|
34
34
|
|
|
35
35
|
In an ordinary interactive session, completion wakes the parent; after useful
|
|
36
36
|
async lanes are launched or triaged, yield rather than use
|
|
37
|
-
`
|
|
37
|
+
`bg_wait({ all: true })` as a barrier. “Continue/orchestrate/work until
|
|
38
38
|
done” means keep the board moving while safe immediate work remains. If only
|
|
39
39
|
async lanes are running, record the revisit trigger and yield.
|
|
40
40
|
|
|
@@ -9,7 +9,7 @@ Parent extensions may register a session-scoped, out-of-band ceiling through `pi
|
|
|
9
9
|
## When to Use
|
|
10
10
|
|
|
11
11
|
- **Complex work orchestration**: keep the parent on its ordinary strong default model. Delegate only when another child materially improves evidence, independent review, or isolated execution; omission failures are cheaper than unnecessary commissions. For hard orchestration or root-cause questions, use a top-reasoning model only as a bounded read-only critic/oracle escalation, never as an autonomous root. Complex means the task has multiple moving parts, unclear acceptance, cross-cutting code, meaningful user-visible impact, expensive or irreversible validation, broad review surface, or the user asks for orchestration. Lightweight one-off delegation can stay lightweight.
|
|
12
|
-
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review
|
|
12
|
+
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review; fork to `oracle` only for rare escalation where inherited decisions, drift, model routing, root cause, or hard tradeoffs matter
|
|
13
13
|
- **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
|
|
14
14
|
- **Recon and planning**: use `scout`, then write a plan when needed
|
|
15
15
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
@@ -178,8 +178,8 @@ and user/project agents override builtins with the same name.
|
|
|
178
178
|
| `reviewer` | Review specialist | strong reviewer tier; high thinking for serious reviews | Default recipes are review-only; tools include edit/write when a fix pass is explicit |
|
|
179
179
|
| `researcher` | Web research brief generator | inherits configured default | Writes `research.md` |
|
|
180
180
|
| `delegate` | Lightweight generic delegate | inherits configured default | No fixed output; generic delegated work |
|
|
181
|
-
| `oracle` |
|
|
182
|
-
| `advisor` | Compatibility alias for `oracle` | top-reasoning critic tier, bounded read-only; high thinking escalation only | Same advisory role as `oracle` |
|
|
181
|
+
| `oracle` | Rare hard-decision/root-cause escalation | top-reasoning critic tier, bounded read-only; high thinking escalation only | Advisory trajectory review, not routine code review |
|
|
182
|
+
| `advisor` | Compatibility alias for `oracle` | top-reasoning critic tier, bounded read-only; high thinking escalation only | Same advisory escalation role as `oracle` |
|
|
183
183
|
|
|
184
184
|
Builtin `worker` and `delegate` use strict tool allowlists and do not inherit ambient parent extension tools. To give a child an extension tool, name it in `tools` and load its provider via `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. Custom agents without an `extensions` field follow `subagents.defaultExtensions` when set.
|
|
185
185
|
|
|
@@ -279,7 +279,7 @@ agent with the same name only when you want a substantially different agent.
|
|
|
279
279
|
|
|
280
280
|
### Recommended model tiering (optional)
|
|
281
281
|
|
|
282
|
-
Keep the parent/orchestrator on the ordinary strong default model because omission failures are cheaper than unnecessary commissions. Route workers and scouts to a fast, capable worker tier, and keep serious reviews on the strong tier at high thinking.
|
|
282
|
+
Keep the parent/orchestrator on the ordinary strong default model because omission failures are cheaper than unnecessary commissions. Route workers and scouts to a fast, capable worker tier, and keep serious reviews on the strong reviewer tier at high thinking. Do not use `oracle` or a top-reasoning model as the routine fresh-review default. Use that tier only for bounded, read-only critic/oracle/root-cause audits after ordinary review, CI, bot, or source evidence is insufficient; critic-tier high thinking is escalation-only and never an autonomous root. Explicit parent/user model policy wins over these recommendations.
|
|
283
283
|
|
|
284
284
|
Examples are illustrative, not requirements. Map these tiers to concrete models in user/project settings or a profile. A non-OpenAI setup should choose comparable available models by capability.
|
|
285
285
|
|
|
@@ -25,7 +25,7 @@ Skip review ceremony for trivial wording, renames, or local-only probes when dir
|
|
|
25
25
|
| Possible over-scope or needless complexity | same-writer challenge before fresh review |
|
|
26
26
|
| Material design tradeoff | council mode |
|
|
27
27
|
|
|
28
|
-
Reviewers are fresh-context by default. Forked
|
|
28
|
+
Reviewers are fresh-context by default. Use the ordinary `reviewer` role for routine code review. Forked oracle/advisor runs are escalation-only for parent-history, drift, root-cause, model-routing, or hard tradeoff evidence.
|
|
29
29
|
|
|
30
30
|
## Finding disposition
|
|
31
31
|
|