pi-subagents 0.57.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/docs/agents.md +13 -6
  3. package/docs/extension-api.md +39 -0
  4. package/docs/models.md +3 -3
  5. package/docs/tool-reference.md +3 -2
  6. package/docs/workflows.md +24 -0
  7. package/package.json +1 -1
  8. package/skills/pi-subagents/SKILL.md +2 -0
  9. package/skills/pi-subagents/references/execution-controls.md +1 -1
  10. package/skills/pi-subagents/references/management-authoring-rpc.md +1 -0
  11. package/skills/pi-subagents/references/prompting-and-roles.md +2 -2
  12. package/src/agents/agent-management.ts +23 -0
  13. package/src/agents/agent-serializer.ts +5 -0
  14. package/src/agents/agents.ts +38 -3
  15. package/src/agents/runtime-agent-events.ts +70 -0
  16. package/src/agents/runtime-agent-registry.ts +10 -2
  17. package/src/api/agents.ts +10 -5
  18. package/src/api/preflight.ts +26 -1
  19. package/src/extension/index.ts +15 -4
  20. package/src/extension/rpc.ts +35 -14
  21. package/src/extension/schemas.ts +2 -2
  22. package/src/extension/tool-description.ts +8 -4
  23. package/src/integrations/herdr-status.ts +5 -0
  24. package/src/runs/background/async-execution.ts +29 -12
  25. package/src/runs/background/async-resume.ts +6 -2
  26. package/src/runs/background/async-status.ts +2 -0
  27. package/src/runs/background/chain-append.ts +2 -0
  28. package/src/runs/background/notify.ts +26 -3
  29. package/src/runs/background/result-delivery-ownership.ts +45 -0
  30. package/src/runs/background/result-watcher.ts +27 -10
  31. package/src/runs/background/subagent-runner.ts +71 -21
  32. package/src/runs/foreground/execution.ts +20 -1
  33. package/src/runs/foreground/subagent-executor.ts +57 -26
  34. package/src/runs/foreground/workflow-detach-reconcile.ts +128 -17
  35. package/src/runs/shared/completion-guard.ts +4 -3
  36. package/src/runs/shared/dynamic-fanout.ts +3 -3
  37. package/src/runs/shared/fast-mode-extension.ts +5 -5
  38. package/src/runs/shared/launch-cwd.ts +16 -0
  39. package/src/runs/shared/long-running-guard.ts +2 -1
  40. package/src/runs/shared/mcp-config-sources.ts +386 -0
  41. package/src/runs/shared/mcp-direct-tool-allowlist.ts +155 -42
  42. package/src/runs/shared/model-exclusions.ts +12 -0
  43. package/src/runs/shared/model-fallback.ts +16 -4
  44. package/src/runs/shared/parallel-utils.ts +8 -1
  45. package/src/runs/shared/pi-args.ts +61 -6
  46. package/src/runs/shared/single-output.ts +17 -0
  47. package/src/runs/shared/subagent-prompt-runtime.ts +85 -9
  48. package/src/shared/formatters.ts +6 -0
  49. package/src/shared/launch-contract.ts +4 -0
  50. package/src/shared/types.ts +42 -1
  51. package/src/shared/utils.ts +6 -29
  52. package/src/slash/subagents-admin.ts +3 -0
  53. package/src/tui/render.ts +14 -6
  54. package/src/workflows/scripted-workflow.ts +52 -5
  55. package/src/workflows/workflow-receipt.ts +39 -4
package/CHANGELOG.md CHANGED
@@ -2,6 +2,45 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.58.0] - 2026-08-27
6
+
7
+ ### Highlights
8
+ - Launch MCP tools from more places, including runtime-registered servers, Pi package manifests, and Agent Plugin configs.
9
+ - Keep agent context smaller by default, with an explicit `inheritGlobalContext` opt-in when a child needs the operator's global context.
10
+ - Make detached and recovered workflow results more reliable, with clearer terminal handoffs and recovery actions.
11
+ - Show better launch and status diagnostics for workspace, authority, context-window, and missing-directory problems.
12
+ - Keep fast OpenAI-Codex launches compatible with priority service tier without losing provider request fields.
13
+
14
+ ### Added
15
+ - Support direct MCP tool launches from runtime-registered servers.
16
+ - Add `inheritGlobalContext` agent configuration so children can opt into the operator's global context file separately from repository context. Thanks to [@hknatm](https://github.com/hknatm) for #1560.
17
+ - Add process-local event registration so independent Pi extensions can register runtime agents through the installed owner. Thanks to [@fmoda3](https://github.com/fmoda3) for #1533.
18
+ - Add advisory launch preflight diagnostics for likely workspace scope and authority mismatches.
19
+ - Document per-run thinking suffixes in model-facing subagent guidance. Thanks to [@yanqianglu](https://github.com/yanqianglu) for #1565.
20
+ - Document unsupported native child options for external CLI agents in the subagent tool help, packaged guide, and packaged skill.
21
+
22
+ ### Changed
23
+ - Agents now omit the operator's global context file by default, including existing agents with `inheritProjectContext: true`; set `inheritGlobalContext: true` to preserve the previous behavior. Thanks to [@hknatm](https://github.com/hknatm) for #1560.
24
+
25
+ ### Fixed
26
+ - Fail explicitly requested models closed when a cached model exclusion is active, instead of silently selecting a fallback. Thanks to [@harpsychord](https://github.com/harpsychord) for #1556.
27
+ - Preserve fast-mode provider request root fields when adding OpenAI's priority service tier. Thanks to [@nothingrotf](https://github.com/nothingrotf) for #1570.
28
+ - Classify workflow budget and timeout stops as partial terminal outcomes while preserving settled child evidence. Thanks to [@yceachan](https://github.com/yceachan) for #1530.
29
+ - Publish a deterministic terminal handoff with settled child evidence and keyed recovery actions when detached workflow lanes settle. Thanks to [@yceachan](https://github.com/yceachan) for #1530.
30
+ - Resolve direct MCP tool selections from Pi package manifests and Agent Plugin configs. Thanks to [@fmoda3](https://github.com/fmoda3) for #1541.
31
+ - Fail closed with a launch diagnostic when configured runtime-style MCP direct-tool selectors cannot be resolved.
32
+ - Sync Herdr status after restoring active async jobs, so recovered work appears without waiting for another lifecycle event. Thanks to [@vicocamacho](https://github.com/vicocamacho) for #1553.
33
+ - Show task intent and context-window use in compact in-progress async status rows.
34
+ - Report deterministic settlement diagnostics when background children fail before required output handoff.
35
+ - Auto-resume workflow children once after setup-phase aborts that produce zero usage, preserving the retained transcript instead of rerunning the whole task.
36
+ - Finalize detached foreground worktree handoffs after terminal child completion, preserving captured changes before cleanup. Thanks to [@jpriverar](https://github.com/jpriverar) for #1562.
37
+ - Fail native child launches before spawn when the requested local working directory is missing or not a directory, with the requested and resolved paths in the error.
38
+ - Map report paths requested in workflow child tasks to the actual saved child output when workflow output routing overrides them.
39
+ - Stop same-session workflows recovered after extension reload through the durable control channel.
40
+ - Let agents declare extension mutation tools so real non-Git or untracked edits satisfy the implementation completion guard. Thanks to [@AlphaGodzilla](https://github.com/AlphaGodzilla) for #1532.
41
+ - Deliver async results from an explicitly replaced predecessor session without accepting unrelated session results. Thanks to [@DresvyanskiyDenis](https://github.com/DresvyanskiyDenis) for #1531.
42
+ - Avoid attributing assistant-issued workflow stops to the user.
43
+
5
44
  ## [0.57.0] - 2026-08-26
6
45
 
7
46
  ### Highlights
package/docs/agents.md CHANGED
@@ -57,6 +57,8 @@ The Pi async run remains the source of truth for status, artifacts, wake/wait, m
57
57
 
58
58
  ### Advisory runner data boundary
59
59
 
60
+ External CLI agents use their own runner contract. Do not pass native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless the adapter explicitly implements them.
61
+
60
62
  The built-in `codex-exec` and `codex-exec-writer` profiles are the supported Codex one-shot modes. Both require an installed and authenticated Codex CLI. The adapters own `codex exec --json` argv with ignored user config and rules, ephemeral sessions, approval policy `never`, and a final-message artifact.
61
63
 
62
64
  | Profile | Access | Sandbox |
@@ -207,7 +209,7 @@ You can override selected builtin fields without copying the whole agent. Overri
207
209
  }
208
210
  ```
209
211
 
210
- Supported override fields: `description`, `output`, `outputMode`, `defaultReads`, `model`, `defaultProvider`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`, `acceptanceRole`, `disabled`, `skills`, `tools`, and `systemPrompt`.
212
+ Supported override fields: `description`, `output`, `outputMode`, `defaultReads`, `model`, `defaultProvider`, `fallbackModels`, `thinking`, `systemPromptMode`, `inheritProjectContext`, `inheritGlobalContext`, `inheritSkills`, `defaultContext`, `acceptanceRole`, `disabled`, `skills`, `tools`, and `systemPrompt`.
211
213
 
212
214
  - `description` replaces the discovered description for builtin and custom agents, which lets list output show deployment-specific routing or model metadata.
213
215
  - Use `output: false`, `defaultReads: false`, `defaultContext: false`, or `acceptanceRole: false` to clear an inherited value.
@@ -234,11 +236,12 @@ Use these fields when an agent should see more:
234
236
  | Field | Effect |
235
237
  |-------|--------|
236
238
  | `systemPromptMode: append` | Append the agent prompt to Pi's normal base prompt. |
237
- | `inheritProjectContext: true` | Keep inherited project instructions from files like `AGENTS.md` and `CLAUDE.md`. |
239
+ | `inheritProjectContext: true` | Keep inherited repository instructions from files like `AGENTS.md` and `CLAUDE.md`. |
240
+ | `inheritGlobalContext: true` | Also keep the operator's global context file from the Pi config agent directory (such as `~/.pi/agent/AGENTS.md`). Defaults to `false`. |
238
241
  | `inheritSkills: true` | Let the child see Pi's discovered skills catalog. |
239
242
  | `defaultContext: fork` | Prefer forked session context when a launch omits `context`; if the parent has no persisted session file or current leaf yet, the implicit default falls back to `fresh` without a failed first attempt. Explicit `context: "fork"` remains strict, and explicit `context: "fresh"` still wins. |
240
243
 
241
- Builtin agents opt into project instruction inheritance by default so they follow repo-specific rules out of the box. `delegate` also uses append mode because its job is orchestration inside the parent workflow.
244
+ Builtin agents opt into repository instruction inheritance by default so they follow repo-specific rules out of the box, but global context remains excluded unless `inheritGlobalContext: true` is set. This changes the behavior of existing agents that previously received global context as part of `inheritProjectContext: true`. `delegate` also uses append mode because its job is orchestration inside the parent workflow.
242
245
 
243
246
  ## Frontmatter reference
244
247
 
@@ -255,10 +258,11 @@ tools: read, grep, find, ls, bash, mcp:chrome-devtools
255
258
  extensions:
256
259
  subagentOnlyExtensions: ./tools/child-only-search.ts
257
260
  model: claude-haiku-4-5
258
- fallbackModels: openai/gpt-5-mini, anthropic/claude-sonnet-4
261
+ fallbackModels: openai-codex/gpt-5.6-luna:low, anthropic/claude-sonnet-4
259
262
  thinking: high
260
263
  systemPromptMode: replace
261
264
  inheritProjectContext: false
265
+ inheritGlobalContext: false
262
266
  inheritSkills: false
263
267
  skills: safe-bash, review-checklist
264
268
  skillPath: ./skills, ../shared-skills
@@ -286,7 +290,7 @@ tools:
286
290
  - read
287
291
  - mcp:github/search_repositories
288
292
  fallbackModels:
289
- - openai/gpt-5-mini
293
+ - openai-codex/gpt-5.6-luna:low
290
294
  - anthropic/claude-sonnet-4
291
295
  ```
292
296
 
@@ -303,7 +307,8 @@ Field notes:
303
307
  | `fallbackModels` | Ordered backup models for provider/model failures such as quota, auth, timeout, or unavailable model. Ordinary task failures do not trigger fallback. |
304
308
  | `thinking` | Appended as a `:level` suffix at runtime unless a suffix is already present. |
305
309
  | `systemPromptMode` | `replace` by default; `append` keeps Pi's base prompt. |
306
- | `inheritProjectContext` | Keeps or strips inherited project instruction blocks. |
310
+ | `inheritProjectContext` | Keeps or strips inherited repository instruction blocks. |
311
+ | `inheritGlobalContext` | Keeps or strips the operator's global context file from the Pi config agent directory (e.g. `~/.pi/agent/AGENTS.md`). It has an effect only when `inheritProjectContext` is `true`; otherwise all context files are already disabled. Defaults to `false`. |
307
312
  | `inheritSkills` | Keeps or strips Pi's discovered skills catalog. |
308
313
  | `defaultContext` | Optional `fresh` or `fork` launch-context preference. An implicit `fork` falls back to `fresh` when the parent has no persisted session file or current leaf; an explicit launch `context: "fork"` remains strict. |
309
314
  | `skills` | Selects specific skills for the child, regardless of `inheritSkills`. |
@@ -317,6 +322,7 @@ Field notes:
317
322
  | `turnBudget` | JSON object default such as `{"maxTurns":20,"graceTurns":2}` for single-agent launches. An explicit call value wins, followed by this agent default, then global `turnBudget` config. |
318
323
  | `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. |
319
324
  | `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
+ | `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. |
320
326
  | `completionGuard` | Set `false` only for non-implementation agents that may mention implementation words while using mutation-capable tools such as `bash`. |
321
327
  | `interactive` | Parsed for compatibility but not currently enforced. |
322
328
  | `maxSubagentDepth` | Tightens nested delegation for this agent's children. |
@@ -385,6 +391,7 @@ More rules:
385
391
  - `mcp:` entries are split out and forwarded as direct MCP selections without granting normal builtins unless those builtins are also listed.
386
392
  - Path-like `tools` entries, such as extension paths or `.ts`/`.js` files, are treated as tool-extension paths rather than tool names.
387
393
  - Internal runtime tools such as `structured_output` are added to an explicit allowlist only when their contract is active.
394
+ - Unknown extension tool calls count as mutation attempts only when their names are listed in `mutationTools`; undeclared unknown tools keep the no-edit guard active.
388
395
  - Agents that declare only known read-only builtin tools skip the implementation completion guard. `bash`, unknown tools, and MCP tools stay mutation-capable. Use `completionGuard: false` for bash-enabled validators or advisors that should never be judged as implementation agents.
389
396
 
390
397
  Examples:
@@ -58,6 +58,45 @@ The DTO intentionally never exposes run, async, or tool IDs. Clients must ignore
58
58
 
59
59
  `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.
60
60
 
61
+ ## Runtime agent registration from independent extensions
62
+
63
+ An independently installed Pi extension can register an agent with the installed `pi-subagents` owner through the process-local `pi-subagents:runtime-agent-register:v1` event. Emit after extension setup, such as during `session_start`. Event delivery is synchronous, so the owner writes the result onto the request before `emit()` returns.
64
+
65
+ ```typescript
66
+ const request: {
67
+ version: 1;
68
+ name: string;
69
+ definition: {
70
+ description: string;
71
+ systemPrompt: string;
72
+ tools?: readonly string[];
73
+ };
74
+ result?:
75
+ | { ok: true; registration: { dispose(): void } }
76
+ | { ok: false; error: Error };
77
+ } = {
78
+ version: 1,
79
+ name: "runtime-probe-agent",
80
+ definition: {
81
+ description: "Agent registered by an independent extension",
82
+ systemPrompt: "Return the words runtime probe.",
83
+ tools: [],
84
+ },
85
+ };
86
+
87
+ pi.events.emit("pi-subagents:runtime-agent-register:v1", request);
88
+ if (!request.result) throw new Error("pi-subagents is not installed or not ready");
89
+ if (!request.result.ok) throw request.result.error;
90
+ const registration = request.result.registration;
91
+ // Call registration.dispose() during your extension cleanup.
92
+ ```
93
+
94
+ If `pi-subagents` is a resolvable dependency of the consumer package, `pi-subagents/agents` exports `RUNTIME_AGENT_REGISTER_EVENT`, the request/result types, and `registerAgentViaEvents()` for the same contract. A separately installed Pi package is not automatically a Node dependency of another package. In that case, use the event contract directly instead of a runtime import. A type-only development dependency is optional.
95
+
96
+ The installed owner applies the existing runtime-agent validation, collision checks, limits, runtime source metadata, and cleanup. If more than one owner listens, the first handler that writes `request.result` wins. Unsupported versions, malformed requests, and registration failures return `{ ok: false, error }`. No result means no compatible owner handled the event.
97
+
98
+ This contract is process-local. It does not register agents in child processes or other Pi processes, and it does not change package discovery or package resolution.
99
+
61
100
  ## External jobs in FleetView
62
101
 
63
102
  Use `pi-subagents/external-runs` to publish display-only current-session jobs owned by another extension:
package/docs/models.md CHANGED
@@ -51,7 +51,7 @@ For a persistent role override with a backup model for provider failures:
51
51
  "reviewer": {
52
52
  "model": "anthropic/claude-sonnet-4",
53
53
  "thinking": "high",
54
- "fallbackModels": ["openai/gpt-5-mini"]
54
+ "fallbackModels": ["openai-codex/gpt-5.6-luna:low"]
55
55
  }
56
56
  }
57
57
  }
@@ -182,9 +182,9 @@ To keep subagents inside a budget or compliance profile, enforce a model scope.
182
182
  "modelScope": {
183
183
  "enforce": true,
184
184
  "strict": true,
185
- "allow": ["inherit", "openai/gpt-5-*"],
185
+ "allow": ["inherit", "openai/gpt-5-*", "openai-codex/gpt-5.6-*"],
186
186
  "agents": {
187
- "worker": { "allow": ["openai/gpt-5-mini"] },
187
+ "worker": { "allow": ["openai-codex/gpt-5.6-luna"] },
188
188
  "reviewer": { "allow": ["inherit"] }
189
189
  }
190
190
  }
@@ -159,9 +159,10 @@ Agent definitions are not loaded into context by default. Management actions let
159
159
  systemPrompt: "You are a code scout...",
160
160
  systemPromptMode: "replace",
161
161
  inheritProjectContext: false,
162
+ inheritGlobalContext: false,
162
163
  inheritSkills: false,
163
164
  model: "anthropic/claude-sonnet-4",
164
- fallbackModels: ["openai/gpt-5-mini", "anthropic/claude-haiku-4-5"],
165
+ fallbackModels: ["openai-codex/gpt-5.6-luna:low", "anthropic/claude-haiku-4-5"],
165
166
  tools: "read, bash, mcp:github/search_repositories",
166
167
  extensions: "",
167
168
  skills: "parallel-scout",
@@ -371,7 +372,7 @@ async: true
371
372
 
372
373
  Supported: status artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are written to log files, while the in-memory final stdout response and stderr error are limited to their last 64 KiB.
373
374
 
374
- Intentionally unsupported: foreground/clarify, steer/resume/interrupt-as-pause, Pi models/tools/extensions, skills, structured output, nested subagents, and fallback models.
375
+ Intentionally unsupported: native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless the runner explicitly implements them. Foreground/clarify, steer/resume/interrupt-as-pause, nested subagents, and fallback models are also unsupported.
375
376
 
376
377
  ## Session sharing
377
378
 
package/docs/workflows.md CHANGED
@@ -57,6 +57,30 @@ 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
+ ### Opt-in bounded workflows
61
+
62
+ Composite workflows have no default parent deadline. Add bounds only when the workflow contract calls for them:
63
+
64
+ ```js
65
+ subagent({
66
+ workflowScript: `
67
+ const scan = await runs.run("scan", { agent: "scout", task: "Inspect the named files." });
68
+ return runs.run("review", { agent: "reviewer", task: "Review:\n" + scan.output });
69
+ `,
70
+ timeoutMs: 900000,
71
+ turnBudget: { maxTurns: 30, graceTurns: 2 },
72
+ toolBudget: { soft: 40, hard: 60 },
73
+ usageBudget: { tokens: { soft: 100000, hard: 150000 } }
74
+ });
75
+ ```
76
+
77
+ - `timeoutMs` sets the workflow deadline and bounds child deadlines to the remaining time.
78
+ - `turnBudget` and `toolBudget` become defaults for each child unless that child supplies a narrower value.
79
+ - `usageBudget` accounts for reported usage across completed workflow children. Once exhausted, it rejects later child launches but does not stop children that are already running.
80
+ - Budget and timeout stops return a structured `terminalOutcome` with `state: "partial"` and reason `budget_exhausted` or `timeout`. Workflow receipts keep settled child evidence for recovery.
81
+
82
+ These controls are opt-in. Avoid tight hard budgets for mutation-capable workers unless the workflow has an explicit checkpoint and handoff path.
83
+
60
84
  The result is `{ ok, errors }`. Invalid scripts return a tool error and include line and column data when available. Validation checks syntax, portable nested-async rules, literal `runs.run` and `runs.all` keys, duplicate literal keys in one `runs.all` group, direct keyed access to a known `runs.all` result, and statically clear non-JSON boundary values. Dynamic keys and other runtime-only values are accepted without a warning. Validation does not discover agents, launch children, or create run artifacts.
61
85
 
62
86
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.57.0",
3
+ "version": "0.58.0",
4
4
  "description": "Pi extension for single-agent delegation and scripted multi-agent workflows",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
@@ -31,6 +31,8 @@ Read the matching reference file before acting. Paths are relative to this `SKIL
31
31
 
32
32
  For broad or uncertain requests, read more than one reference. For complex work, start with `references/prompting-and-roles.md` and `references/execution-controls.md`, then consult `references/constraints-and-recipes.md` before launching or reviewing child work.
33
33
 
34
+ External CLI agents such as `codex-exec`, `codex-exec-writer`, `claude-code`, and `cursor-agent` use their own runner contract. Do not pass native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless that runner explicitly implements them.
35
+
34
36
  ## Always-on constraints
35
37
 
36
38
  - Keep the parent as orchestrator and final decision-maker.
@@ -24,7 +24,7 @@ Project settings resolve from the nearest parent directory containing `.pi` or `
24
24
 
25
25
  An agent may set `runner.type: external-cli` with a non-empty `command`, optional string `args`, and `promptDelivery: stdin` (the default). The command runs with `shell: false`, inherits the resolved cwd and environment, and receives the combined agent instructions and task through stdin. It must already be installed; pi-subagents adds no CLI dependency.
26
26
 
27
- External CLI profiles are async-only and one-shot. They support lifecycle artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are retained in their log files, while the final stdout response and stderr error kept in memory are each limited to their last 64 KiB. They do not support foreground/clarify, steer/resume/interrupt-as-pause, Pi models/tools/extensions/skills, tool or turn budgets, structured output, nested subagents, fallbacks, or sessions.
27
+ External CLI profiles are async-only and one-shot. They support lifecycle artifacts, stdout/stderr logs, timeout, and stop. Full stdout and stderr are retained in their log files, while the final stdout response and stderr error kept in memory are each limited to their last 64 KiB. They do not support native Pi child options such as model override, structured output, acceptance/agent contract, tool budgets, fast mode, fork context, skills, or native Pi tools unless the runner explicitly implements them. Foreground/clarify, steer/resume/interrupt-as-pause, nested subagents, fallbacks, and sessions are also unsupported.
28
28
 
29
29
  ### External job profiles
30
30
 
@@ -102,6 +102,7 @@ thinking: high
102
102
  tools: read, grep, find, ls, bash
103
103
  systemPromptMode: replace
104
104
  inheritProjectContext: true
105
+ inheritGlobalContext: false
105
106
  inheritSkills: false
106
107
  skills: safe-bash, review-checklist
107
108
  skillPath: ./skills, ../shared-skills
@@ -230,7 +230,7 @@ Direct settings example:
230
230
  "reviewer": {
231
231
  "model": "anthropic/claude-sonnet-4",
232
232
  "thinking": "high",
233
- "fallbackModels": ["openai/gpt-5-mini"],
233
+ "fallbackModels": ["openai-codex/gpt-5.6-luna:low"],
234
234
  "acceptanceRole": "read-only"
235
235
  }
236
236
  }
@@ -239,7 +239,7 @@ Direct settings example:
239
239
  ```
240
240
 
241
241
  Useful override fields: `description`, `model`, `fallbackModels`, `thinking`,
242
- `systemPromptMode`, `inheritProjectContext`, `inheritSkills`, `defaultContext`,
242
+ `systemPromptMode`, `inheritProjectContext`, `inheritGlobalContext`, `inheritSkills`, `defaultContext`,
243
243
  `acceptanceRole`, `disabled`, `skills`, `tools`, `extensions`, and `systemPrompt`.
244
244
  `description` replaces the discovered description for builtin and custom agents
245
245
  in `list` output, which is useful for deployment-specific routing notes.
@@ -230,6 +230,7 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
230
230
  thinking: _thinking,
231
231
  systemPromptMode: _systemPromptMode,
232
232
  inheritProjectContext: _inheritProjectContext,
233
+ inheritGlobalContext: _inheritGlobalContext,
233
234
  inheritSkills: _inheritSkills,
234
235
  defaultContext: _defaultContext,
235
236
  acceptanceRole: _acceptanceRole,
@@ -240,6 +241,7 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
240
241
  tools: _tools,
241
242
  mcpDirectTools: _mcpDirectTools,
242
243
  subagentOnlyExtensions: _subagentOnlyExtensions,
244
+ mutationTools: _mutationTools,
243
245
  completionGuard: _completionGuard,
244
246
  ...editable
245
247
  } = withoutExtensions;
@@ -260,6 +262,7 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
260
262
  ...(base.thinking !== undefined ? { thinking: base.thinking } : {}),
261
263
  systemPromptMode: base.systemPromptMode,
262
264
  inheritProjectContext: base.inheritProjectContext,
265
+ inheritGlobalContext: base.inheritGlobalContext,
263
266
  inheritSkills: base.inheritSkills,
264
267
  ...(base.defaultContext !== undefined ? { defaultContext: base.defaultContext } : {}),
265
268
  ...(base.acceptanceRole !== undefined ? { acceptanceRole: base.acceptanceRole } : {}),
@@ -271,6 +274,7 @@ export function editableAgentConfig(agent: AgentConfig): AgentConfig {
271
274
  ...(base.mcpDirectTools !== undefined ? { mcpDirectTools: [...base.mcpDirectTools] } : {}),
272
275
  ...(base.extensions !== undefined ? { extensions: [...base.extensions] } : {}),
273
276
  ...(base.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: [...base.subagentOnlyExtensions] } : {}),
277
+ ...(base.mutationTools !== undefined ? { mutationTools: [...base.mutationTools] } : {}),
274
278
  ...(base.completionGuard !== undefined ? { completionGuard: base.completionGuard } : {}),
275
279
  }, agent.filePath);
276
280
  }
@@ -303,6 +307,7 @@ export function preservedAgentFrontmatterFields(agent: AgentConfig, cfg: Record<
303
307
  if (hasKey(cfg, "skillPath")) changed("skillPath");
304
308
  if (hasKey(cfg, "extensions")) changed("extensions");
305
309
  if (hasKey(cfg, "subagentOnlyExtensions")) changed("subagentOnlyExtensions");
310
+ if (hasKey(cfg, "mutationTools")) changed("mutationTools");
306
311
  if (hasKey(cfg, "thinking")) {
307
312
  changed("thinking");
308
313
  if (cfg.thinking === "off") fields.add("thinking");
@@ -315,6 +320,10 @@ export function preservedAgentFrontmatterFields(agent: AgentConfig, cfg: Record<
315
320
  changed("inheritProjectContext");
316
321
  fields.add("inheritProjectContext");
317
322
  }
323
+ if (hasKey(cfg, "inheritGlobalContext")) {
324
+ changed("inheritGlobalContext");
325
+ fields.add("inheritGlobalContext");
326
+ }
318
327
  if (hasKey(cfg, "inheritSkills")) {
319
328
  changed("inheritSkills");
320
329
  fields.add("inheritSkills");
@@ -457,6 +466,12 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
457
466
  else if (typeof cfg.subagentOnlyExtensions === "string") target.subagentOnlyExtensions = parseCsv(cfg.subagentOnlyExtensions);
458
467
  else return "config.subagentOnlyExtensions must be a comma-separated string, empty string, or false when provided.";
459
468
  }
469
+ if (hasKey(cfg, "mutationTools")) {
470
+ if (cfg.mutationTools === false) delete target.mutationTools;
471
+ else if (cfg.mutationTools === "") target.mutationTools = [];
472
+ else if (typeof cfg.mutationTools === "string") target.mutationTools = parseCsv(cfg.mutationTools);
473
+ else return "config.mutationTools must be a comma-separated string, empty string, or false when provided.";
474
+ }
460
475
  if (hasKey(cfg, "thinking")) {
461
476
  if (cfg.thinking === false || cfg.thinking === "") delete target.thinking;
462
477
  else if (typeof cfg.thinking === "string") {
@@ -473,6 +488,10 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
473
488
  if (typeof cfg.inheritProjectContext !== "boolean") return "config.inheritProjectContext must be a boolean when provided.";
474
489
  target.inheritProjectContext = cfg.inheritProjectContext;
475
490
  }
491
+ if (hasKey(cfg, "inheritGlobalContext")) {
492
+ if (typeof cfg.inheritGlobalContext !== "boolean") return "config.inheritGlobalContext must be a boolean when provided.";
493
+ target.inheritGlobalContext = cfg.inheritGlobalContext;
494
+ }
476
495
  if (hasKey(cfg, "inheritSkills")) {
477
496
  if (typeof cfg.inheritSkills !== "boolean") return "config.inheritSkills must be a boolean when provided.";
478
497
  target.inheritSkills = cfg.inheritSkills;
@@ -561,6 +580,7 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
561
580
  target.thinking ? "thinking" : undefined,
562
581
  target.extensions?.length ? "extensions" : undefined,
563
582
  target.subagentOnlyExtensions?.length ? "subagentOnlyExtensions" : undefined,
583
+ target.mutationTools?.length ? "mutationTools" : undefined,
564
584
  target.skills?.length || target.skillPath?.length ? "skills" : undefined,
565
585
  target.maxSubagentDepth !== undefined ? "maxSubagentDepth" : undefined,
566
586
  target.completionGuard !== undefined ? "completionGuard" : undefined,
@@ -699,6 +719,7 @@ function formatAgentDetail(agent: AgentConfig): string {
699
719
  if (agent.runner?.type === "external-job" && agent.runner.options) lines.push(`Runner options: ${JSON.stringify(agent.runner.options)}`);
700
720
  }
701
721
  lines.push(`Inherit project context: ${agent.inheritProjectContext ? "true" : "false"}`);
722
+ lines.push(`Inherit global context: ${agent.inheritGlobalContext ? "true" : "false"}`);
702
723
  lines.push(`Inherit skills: ${agent.inheritSkills ? "true" : "false"}`);
703
724
  if (agent.defaultContext) lines.push(`Default context: ${agent.defaultContext}`);
704
725
  if (agent.defaultAsync !== undefined) lines.push(`Async: ${agent.defaultAsync ? "true" : "false"}`);
@@ -709,6 +730,7 @@ function formatAgentDetail(agent: AgentConfig): string {
709
730
  if (agent.source === "builtin") lines.push(`Disabled: ${agent.disabled ? "true" : "false"}`);
710
731
  if (agent.extensions !== undefined) lines.push(`Extensions: ${agent.extensions.length ? agent.extensions.join(", ") : "(none)"}`);
711
732
  if (agent.subagentOnlyExtensions !== undefined) lines.push(`Subagent-only extensions: ${agent.subagentOnlyExtensions.length ? agent.subagentOnlyExtensions.join(", ") : "(none)"}`);
733
+ if (agent.mutationTools !== undefined) lines.push(`Mutation tools: ${agent.mutationTools.length ? agent.mutationTools.join(", ") : "(none)"}`);
712
734
  if (agent.thinking) lines.push(`Thinking: ${agent.thinking}`);
713
735
  if (agent.output) lines.push(`Output: ${agent.output}`);
714
736
  if (agent.outputMode) lines.push(`Output mode: ${agent.outputMode}`);
@@ -915,6 +937,7 @@ export function handleCreate(params: ManagementParams, ctx: ManagementContext):
915
937
  systemPrompt: "",
916
938
  systemPromptMode: defaultSystemPromptMode(name),
917
939
  inheritProjectContext: defaultInheritProjectContext(name),
940
+ inheritGlobalContext: false,
918
941
  inheritSkills: defaultInheritSkills(),
919
942
  };
920
943
  const applyError = applyAgentConfig(agent, cfg);
@@ -15,6 +15,7 @@ export const KNOWN_FIELDS = new Set([
15
15
  "thinking",
16
16
  "systemPromptMode",
17
17
  "inheritProjectContext",
18
+ "inheritGlobalContext",
18
19
  "inheritSkills",
19
20
  "defaultContext",
20
21
  "async",
@@ -28,6 +29,7 @@ export const KNOWN_FIELDS = new Set([
28
29
  "skillPath",
29
30
  "extensions",
30
31
  "subagentOnlyExtensions",
32
+ "mutationTools",
31
33
  "output",
32
34
  "outputMode",
33
35
  "defaultReads",
@@ -78,6 +80,7 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
78
80
  }
79
81
  if (!preservingExistingFrontmatter || preserve("systemPromptMode")) lines.push(`systemPromptMode: ${config.systemPromptMode}`);
80
82
  if (!preservingExistingFrontmatter || preserve("inheritProjectContext")) lines.push(`inheritProjectContext: ${config.inheritProjectContext ? "true" : "false"}`);
83
+ if (config.inheritGlobalContext || preserve("inheritGlobalContext")) lines.push(`inheritGlobalContext: ${config.inheritGlobalContext ? "true" : "false"}`);
81
84
  if (!preservingExistingFrontmatter || preserve("inheritSkills")) lines.push(`inheritSkills: ${config.inheritSkills ? "true" : "false"}`);
82
85
  if (config.defaultContext || preserve("defaultContext")) lines.push(`defaultContext: ${config.defaultContext ?? ""}`);
83
86
  if (config.runner || preserve("runner")) {
@@ -114,6 +117,8 @@ export function serializeAgent(config: AgentConfig, options: SerializeAgentOptio
114
117
  const subagentOnlyExtensionsValue = joinComma(config.subagentOnlyExtensions);
115
118
  lines.push(`subagentOnlyExtensions: ${subagentOnlyExtensionsValue ?? ""}`);
116
119
  }
120
+ const mutationToolsValue = joinComma(config.mutationTools);
121
+ if (mutationToolsValue || preserve("mutationTools")) lines.push(`mutationTools: ${mutationToolsValue ?? ""}`);
117
122
 
118
123
  if (config.output || preserve("output")) lines.push(`output: ${config.output ?? ""}`);
119
124
  if (config.outputMode || preserve("outputMode")) lines.push(`outputMode: ${config.outputMode ?? ""}`);