pi-subagents 0.66.0 → 0.67.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 (115) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +4 -3
  3. package/agents/evidence-auditor.md +34 -0
  4. package/agents/reviewer.md +3 -2
  5. package/docs/agents.md +6 -3
  6. package/docs/configuration.md +7 -5
  7. package/docs/extension-api.md +33 -18
  8. package/docs/missions.md +8 -0
  9. package/docs/models.md +1 -1
  10. package/docs/observability.md +4 -4
  11. package/docs/standalone-background.md +49 -0
  12. package/docs/tool-reference.md +18 -8
  13. package/docs/watchdog.md +35 -4
  14. package/docs/workflows.md +26 -12
  15. package/inspector-runner.mjs +2 -2
  16. package/package.json +1 -1
  17. package/prompts/parallel-review.md +1 -1
  18. package/{runner-server-preload.mjs → runner-peer-preload.mjs} +8 -3
  19. package/skills/pi-subagents/SKILL.md +14 -0
  20. package/skills/pi-subagents/references/execution-controls.md +7 -5
  21. package/skills/pi-subagents/references/prompting-and-roles.md +2 -2
  22. package/src/agents/advertised-agent-prompt.ts +34 -3
  23. package/src/agents/agents.ts +6 -0
  24. package/src/agents/builtin-names.ts +1 -0
  25. package/src/api/delegation.ts +4 -0
  26. package/src/api/preflight.ts +76 -45
  27. package/src/api/shared-types.ts +2 -0
  28. package/src/extension/fanout-child.ts +63 -4
  29. package/src/extension/index.ts +20 -8
  30. package/src/extension/public-execution.ts +4 -2
  31. package/src/extension/rpc.ts +4 -0
  32. package/src/extension/schemas.ts +67 -78
  33. package/src/extension/tool-description.ts +29 -82
  34. package/src/inspectors/actions.ts +148 -0
  35. package/src/inspectors/ghostty/actions.ts +74 -0
  36. package/src/inspectors/ghostty/plugin.ts +17 -0
  37. package/src/inspectors/herdr/actions.ts +99 -179
  38. package/src/inspectors/herdr/plugin.ts +20 -0
  39. package/src/inspectors/herdr/project-panes.ts +1 -1
  40. package/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +12 -12
  41. package/src/inspectors/plugins.ts +8 -0
  42. package/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +3 -14
  43. package/src/inspectors/types.ts +51 -0
  44. package/src/intercom/intercom-bridge.ts +50 -8
  45. package/src/intercom/native-supervisor-channel.ts +22 -13
  46. package/src/runs/background/active-async-capacity.ts +4 -0
  47. package/src/runs/background/async-execution.ts +45 -56
  48. package/src/runs/background/async-resume.ts +5 -9
  49. package/src/runs/background/auto-drain.ts +6 -3
  50. package/src/runs/background/binary-bootstrap.ts +33 -0
  51. package/src/runs/background/fleet-view.ts +30 -2
  52. package/src/runs/background/notify.ts +31 -1
  53. package/src/runs/background/owned-process-tree.ts +29 -2
  54. package/src/runs/background/run-child-session.ts +61 -4
  55. package/src/runs/background/run-status.ts +3 -0
  56. package/src/runs/background/runner-aliases.ts +11 -3
  57. package/src/runs/background/runner-child-launch.ts +2 -0
  58. package/src/runs/background/runner-child-sessions.ts +5 -4
  59. package/src/runs/background/scheduled-runs.ts +40 -13
  60. package/src/runs/background/steering.ts +20 -2
  61. package/src/runs/background/subagent-runner.ts +47 -31
  62. package/src/runs/background/subagent-wait.ts +51 -8
  63. package/src/runs/background/wait-tool.ts +1 -1
  64. package/src/runs/foreground/async-steering-action.ts +18 -7
  65. package/src/runs/foreground/execution.ts +44 -31
  66. package/src/runs/foreground/prompt-audit.ts +3 -1
  67. package/src/runs/foreground/subagent-executor.ts +110 -100
  68. package/src/runs/foreground/workflow-detach-reconcile.ts +2 -0
  69. package/src/runs/foreground/workflow-foreground-steering.ts +2 -1
  70. package/src/runs/shared/acceptance.ts +5 -2
  71. package/src/runs/shared/async-status-projection.ts +4 -0
  72. package/src/runs/shared/capability-ceiling.ts +2 -0
  73. package/src/runs/shared/child-hooks.ts +25 -10
  74. package/src/runs/shared/child-launch.ts +12 -2
  75. package/src/runs/shared/child-lifecycle.ts +6 -3
  76. package/src/runs/shared/child-runtime-config.ts +3 -1
  77. package/src/runs/shared/child-session.ts +33 -2
  78. package/src/runs/shared/child-tool-plan.ts +122 -3
  79. package/src/runs/shared/completion-guard.ts +5 -3
  80. package/src/runs/shared/effective-system-prompt.ts +33 -0
  81. package/src/runs/shared/external-cli-runner.ts +9 -7
  82. package/src/runs/shared/llm-intent-arbiter.ts +12 -3
  83. package/src/runs/shared/model-fallback.ts +2 -0
  84. package/src/runs/shared/orca-progress-tabs.ts +1 -1
  85. package/src/runs/shared/pi-spawn.ts +10 -0
  86. package/src/runs/shared/subagent-prompt-runtime.ts +9 -3
  87. package/src/runs/shared/task-intent.ts +46 -13
  88. package/src/runs/shared/workflow-async-child-guidance.ts +18 -0
  89. package/src/runs/shared/worktree.ts +42 -12
  90. package/src/shared/fork-context.ts +15 -72
  91. package/src/shared/launch-contract.ts +65 -2
  92. package/src/shared/opencode-session-headers.ts +30 -0
  93. package/src/shared/types.ts +4 -1
  94. package/src/slash/delegation-adapters.ts +3 -1
  95. package/src/slash/delegation-request.ts +14 -0
  96. package/src/slash/slash-commands.ts +2 -1
  97. package/src/slash/subagents-admin.ts +11 -4
  98. package/src/tui/fleet-status.ts +164 -19
  99. package/src/tui/fleet.ts +16 -14
  100. package/src/tui/render.ts +149 -28
  101. package/src/watchdog/child-status.ts +8 -0
  102. package/src/watchdog/model-selection.ts +20 -0
  103. package/src/watchdog/permission-arbiter.ts +3 -1
  104. package/src/watchdog/register-child.ts +1 -0
  105. package/src/watchdog/register-main.ts +31 -27
  106. package/src/watchdog/review.ts +132 -67
  107. package/src/watchdog/runtime.ts +82 -20
  108. package/src/watchdog/scope.ts +1 -1
  109. package/src/watchdog/settings.ts +9 -3
  110. package/src/watchdog/tool-actions.ts +13 -12
  111. package/src/watchdog/turn-delta.ts +23 -0
  112. package/src/watchdog/types.ts +4 -0
  113. package/src/workflows/scripted-workflow.ts +237 -7
  114. package/src/workflows/workflow-checklist.ts +2 -2
  115. /package/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +0 -0
package/docs/watchdog.md CHANGED
@@ -7,10 +7,11 @@ The watchdog is an opt-in second model that reviews what the agent just did and
7
7
  | Timing | Trigger | Gate | Delivery |
8
8
  |---|---|---|---|
9
9
  | Boundary review | `agent_end` of every main or child turn | Repo changed | Steered into the transcript; the agent gets one continuation, then that turn is reviewed again |
10
+ | Main activity review | `agent_end`, with `clarification: true` | New delivered orchestration evidence; at most one additional review per user prompt | Same warning/clarification path, even without local edits |
10
11
  | Cadence review | Every `cadence.everyNTools` tool results, minimum 5 | Opt-in | Steered after the current tool, before the next step |
11
12
  | LSP pre-pass | Before boundary review | Changed TypeScript/JavaScript files | Diagnostics become watchdog findings without a model call |
12
13
 
13
- Boundary reviews coalesce a turn's edits into one final-state review. Unchanged or reverted diffs are skipped, as are `.pi/subagents/` and `tmp/` artifacts. In orchestrated runs, each writing child reviews its own worktree and the parent reviews the aggregate diff after child changes land. There is no timer or "every turn regardless of edits" mode; the closest is a low cadence such as `everyNTools: 5`. Cadence monitoring is inspired by [Scopey](https://github.com/ArchAstro/scopey).
14
+ Boundary reviews coalesce a turn's edits into one final-state review. Unchanged or reverted diffs are skipped unless the main-only activity opt-in below admits new evidence; `.pi/subagents/` and `tmp/` artifacts remain excluded. In orchestrated runs, each writing child reviews its own worktree and the parent reviews the aggregate diff after child changes land. There are no idle timer reviews. Cadence monitoring is inspired by [Scopey](https://github.com/ArchAstro/scopey).
14
15
 
15
16
  Children get the same boundary, cadence, and LSP behavior. Child cadence resolves from `children.overrides.<agent>.cadence`, then `children.cadence`, then top-level `cadence`:
16
17
 
@@ -67,7 +68,7 @@ Child watchdog findings are lifted into the parent in three ways:
67
68
  ## What the reviewer is given
68
69
 
69
70
  - **Turn delta** with changed repo paths. Over-long input keeps the first 6,000 characters and the tail.
70
- - **Current scope** (`scope.enabled`, default on): bounded real user prompts, with newer prompts superseding older ones.
71
+ - **Current scope** (`scope.enabled`, default on): bounded real user prompts. Side questions are additive; only explicit changes supersede older requirements.
71
72
  - **`watchdog_diff`** when inside git: diff since the session-start commit, including later commits, plus untracked paths to inspect with `read`; accepts `path` and `stat:true`.
72
73
  - **`WATCHDOG.md`** standing instructions, read fresh on every review: `<project>/.pi/WATCHDOG.md` first, then `~/.pi/agent/WATCHDOG.md`, capped at 8,000 characters. Set `guidance.watchdogMd: false` to ignore them.
73
74
  - **LSP diagnostics** from `typescript-language-server`, auto-detected in `node_modules/.bin` or `PATH`; it is never installed and never run over the whole workspace. Errors become blockers, warnings concerns, and info/hints stay in status.
@@ -87,7 +88,9 @@ One model setting serves both boundary and cadence reviews per endpoint. Use a s
87
88
  /subagents-watchdog on
88
89
  ```
89
90
 
90
- The recommendation is Opus 4.8 or GPT 5.5 at thinking high, whichever your main session is not using and is authenticated. Saving a model does not enable the watchdog; use `on` separately.
91
+ When a main watchdog model is configured (including a session override), recommendations keep that model and its effective thinking level rather than judging its strength or independence. An unavailable or unauthenticated configured model is reported, not replaced. Without a configured main model, the recommendation remains Opus 4.8 or GPT 5.5 at thinking high, whichever your main session is not using and is authenticated.
92
+
93
+ `session model recommended` changes only this session. `model recommended` explicitly saves the recommendation to **user settings**, affecting other projects without overrides; it does not change project settings. Project and session overrides still take precedence. Use an explicit model to replace a configured choice. Saving a model does not enable the watchdog; use `on` separately.
91
94
 
92
95
  ```json
93
96
  {
@@ -105,11 +108,39 @@ The recommendation is Opus 4.8 or GPT 5.5 at thinking high, whichever your main
105
108
 
106
109
  Omit `main.model` to inherit the session model and thinking level. A `main.model` without a thinking suffix or `main.thinking` runs with thinking off, so prefer `:high` for the strong pairing.
107
110
 
111
+ Set `fallbackModels` in JSON settings on `main`, `children`, or `children.overrides.<agent>` to opt into an ordered fallback chain, for example `"fallbackModels": ["openai-codex/gpt-5.5:high"]`. Child overrides win over `children.fallbackModels`; neither inherits the main watchdog's chain. Arrays replace across user → project → session settings, and `[]` clears an inherited chain. Status shows configured chains.
112
+
113
+ Unavailable configured candidates are skipped and resolved duplicates are tried once. Each attempt uses a fresh reviewer with its own model auth, provider stream, and thinking; an inherited primary keeps the actual session model/thinking, while fallbacks use explicit-model thinking rules. Fallback follows normal subagent provider-failure semantics (including rate limits, quota, auth, unavailability, and provider timeouts), **only before any tool work**, including read-only inspection. Clean/normal completion, length limits, findings, clarification, cancellation, and the overall watchdog deadline never trigger fallback. All attempts share the original deadline; exhaustion remains a failed review. With no fallback chain, existing single-model behavior is unchanged.
114
+
108
115
  Agents can call `subagent({ action: "watchdog.recommend-model" })` and `subagent({ action: "watchdog.configure", model: "recommended", scope: "session" | "user" | "project" })`. They should use `scope: "session"` unless you ask for a lasting default.
109
116
 
117
+ ## Optional main-session clarification
118
+
119
+ Use `watchdog_warn` directly for evidence-backed reminders of forgotten authorized work; a question is not a prerequisite. Distinguish forgotten work from dependencies still pending or explicit holds. Use clarification when task status or intent is genuinely unclear. The orchestrator remains owner of its task/lane board.
120
+
121
+ With this opt-in, completed `turn_end` events retain a recent actual-activity tail: paired calls/results for `subagent` dispatch (no action), `subagent` actions `status`, `resume`, `interrupt`, `steer`, `stop`, `bg_wait`, and `subagent_supervisor` actions `pending`, `list`, `reply`. Pairing requires the same tool name and exact tool-call ID; raw results, unrelated tool names and watchdog management actions do not qualify. Each activity entry is bounded to 3,000 characters, with a 6,000-character recent tail retained across ordinary new prompts and skipped edit boundaries. Session replacement, compaction, shutdown or disabling clears it. This is observed text, not an inferred task board.
122
+
123
+ New unreviewed activity permits at most one additional boundary review per user prompt even with no local edit. Side questions keep earlier authorized task evidence available; they do not themselves trigger a model call. Activity gathered after that prompt's extra review remains available for the next prompt. Warning continuations cannot supply fresh triggering activity. No polling, task scheduling, cross-worktree scans or idle calls are added.
124
+
125
+ **Visibility limit:** external task/gate completions are visible when returned through those parent tool results. Standalone native completion notifications, arbitrary custom messages, direct shell/CI output, and events not delivered to the parent through these contracts are not ingested by this activity tail. Existing scope retains at most eight prompts (2,000 characters each); new streaming user input cancels an active review but is not added to scope unless `before_agent_start` fires. Reminders depend on retained evidence and model judgment, not an exhaustive view of running work.
126
+
127
+ Set `subagents.watchdog.clarification: true` in Pi settings alongside `enabled: true`. It defaults to `false` and applies **only to the main watchdog**, not child watchdogs or child permission arbitration.
128
+
129
+ ```json
130
+ { "subagents": { "watchdog": { "enabled": true, "clarification": true } } }
131
+ ```
132
+
133
+ At an eligible activity or repo-edit boundary, the reviewer may use `watchdog_ask` for one focused question when missing orchestrator context prevents a concrete judgment. It cannot ask during cadence reviews, after an accepted warning, or during stalemate. There is at most one question per real user prompt.
134
+
135
+ The tool **yields and ends that review**. A visible question with concrete evidence steers the main session into Pi's native automatic continuation after the boundary hook returns. The orchestrator handles the context as needed and continues; no answer, receipt, deadline or follow-up review is required or tracked. Questions are **not approval, permission, or warnings**.
136
+
137
+ Asking consumes the current review evidence, so an unchanged Git-backed boundary does not immediately review it again. Later reviews use the normal edit, cadence and bounded activity triggers, with the same read-only tools, warning thresholds, budgets and stalemate protections. Non-Git observed edits can also prompt a question: there is no cross-answer evidence guarantee to verify. Disabling watchdog or clarification, new user input, model changes and session lifecycle resets cancel applicable active reviews and suppress stale results; already delivered questions remain ordinary transcript messages.
138
+
139
+ Reviews retain the existing `agentEndTimeoutMs`. Questions and evidence are capped at 1,000 and 2,000 characters; scope, activity and delta share the existing 24,000-character input limit. Enabled cost adds at most one activity boundary review and one question-triggered continuation per prompt, not a dedicated answer review. Disabled execution does not collect activity or add polling, model calls or reviewer prompt/tool content. Child warning messaging and permission decisions remain unchanged.
140
+
110
141
  ## Child watchdogs
111
142
 
112
- Opt in under `subagents.watchdog.children`. `model` and `thinking` set the default child watchdog; `overrides.<agent>` can set `model`, `thinking`, `enabled`, or `cadence` per role.
143
+ Opt in under `subagents.watchdog.children`. `model`, `fallbackModels`, and `thinking` set the default child watchdog; `overrides.<agent>` can set `model`, `fallbackModels`, `thinking`, `enabled`, or `cadence` per role.
113
144
 
114
145
  ## Launch rules
115
146
 
package/docs/workflows.md CHANGED
@@ -45,6 +45,10 @@ Add `autofix` to `/parallel-review` or `/parallel-cleanup` to apply only the syn
45
45
 
46
46
  Use direct `{ agent, task }` for one bounded child. Use `workflowScript` when the parent needs a stable keyed child, sequence, fanout, steering, retry, or aggregation. For ordinary parallel fanout, use `await runs.all([{ key, agent, task }, ...])`. It resolves to an ordered array, not a key map, so use indexes, destructuring, or `.map(...)`, not `results.<key>`. Do not read `.output` from unawaited `runs.run` launches. Store a `runs.run` promise only when the script later observes it with `await`, `Promise.race`, or `Promise.all`, such as steering a live child before awaiting its result. Scripts are ordinary JavaScript statement bodies. Use an explicit `return` for a useful result:
47
47
 
48
+ For multi-step or parallel work, make exactly one top-level `subagent` workflow call with `async:true` and launch children only inside it. Read this guide for recipes rather than constructing a second top-level orchestration. Available sandbox helpers include `runs.run`, `runs.all`, `runs.lanes`, `runs.steer`, `runs.status`, `runs.ref`/`runs.refs`, `emit`, `console`, standard JavaScript, and mission `state` when enabled. No filesystem, shell, arbitrary Pi tools, or host globals are available; named resources alone may grant `runs.host` authority.
49
+
50
+ Workflow-level child controls default onto each `runs.run`/`runs.all` launch; explicit child fields override them. See [retained children](tool-reference.md#retained-children) for follow-up challenges, [output binding](tool-reference.md#output-mode-details) for durable artifacts, and [schedules](missions.md#schedules) for delayed/recurring scripts.
51
+
48
52
  Child results cross into the script as plain JSON data. Non-JSON host metadata is omitted, so use returned fields such as `runId`, `ok`, `output`, and `structuredOutput` for workflow control.
49
53
 
50
54
  Validate a script without launching children:
@@ -104,10 +108,10 @@ The result is `{ ok, errors }`. Invalid scripts return a tool error and include
104
108
 
105
109
  ```js
106
110
  subagent({ workflowScript: `
107
- const scan = await runs.run("scan", { agent: "scout", task: "Scan the codebase" });
111
+ const scan = await runs.run("scan", { label: "Map codebase behavior", agent: "scout", task: "Scan the codebase" });
108
112
  const reviews = await runs.all([
109
- { key: "correctness", agent: "reviewer", task: "Review correctness: " + scan.output },
110
- { key: "tests", agent: "reviewer", task: "Review tests: " + scan.output }
113
+ { key: "correctness", label: "Review codebase correctness", agent: "reviewer", task: "Review correctness: " + scan.output },
114
+ { key: "tests", label: "Review test coverage", agent: "reviewer", task: "Review tests: " + scan.output }
111
115
  ]);
112
116
  return reviews.map(result => result.output);
113
117
  ` });
@@ -118,7 +122,7 @@ Keep helper functions portable across Node and Bun. Use top-level `await`, plain
118
122
  ```js
119
123
  subagent({ workflowScript: `
120
124
  function scan() {
121
- return runs.run("scan", { agent: "scout", task: "Scan the codebase" });
125
+ return runs.run("scan", { label: "Map codebase behavior", agent: "scout", task: "Scan the codebase" });
122
126
  }
123
127
  const result = await scan();
124
128
  return result.output;
@@ -129,8 +133,8 @@ Chaining is still supported. The supported form is scripted chaining: await one
129
133
 
130
134
  ```js
131
135
  subagent({ workflowScript: `
132
- const plan = await runs.run("plan", { agent: "scout", task: "Plan the migration" });
133
- const patch = await runs.run("patch", { agent: "worker", task: "Implement this plan:\n" + plan.output });
136
+ const plan = await runs.run("plan", { label: "Plan migration behavior", agent: "scout", task: "Plan the migration" });
137
+ const patch = await runs.run("patch", { label: "Implement migration behavior", agent: "worker", task: "Implement this plan:\n" + plan.output });
134
138
  return patch.output;
135
139
  ` });
136
140
  ```
@@ -145,16 +149,16 @@ subagent({ workflowScript: `
145
149
  {
146
150
  key: "api",
147
151
  stages: [
148
- { key: "writer", agent: "worker", task: "Implement the API change" },
149
- { key: "challenge", resume: "previous", task: "Challenge the API implementation" },
150
- { key: "review", agent: "reviewer", task: "Review the API lane" }
152
+ { key: "writer", label: "Implement API behavior", agent: "worker", task: "Implement the API change" },
153
+ { key: "challenge", label: "Challenge API behavior", resume: "previous", task: "Challenge the API implementation" },
154
+ { key: "review", label: "Review API behavior", agent: "reviewer", task: "Review the API lane" }
151
155
  ]
152
156
  },
153
157
  {
154
158
  key: "ui",
155
159
  stages: [
156
- { key: "writer", agent: "worker", task: "Implement the UI change" },
157
- { key: "review", agent: "reviewer", task: "Review the UI lane" }
160
+ { key: "writer", label: "Implement UI behavior", agent: "worker", task: "Implement the UI change" },
161
+ { key: "review", label: "Review UI behavior", agent: "reviewer", task: "Review the UI lane" }
158
162
  ]
159
163
  }
160
164
  ]);
@@ -203,7 +207,7 @@ subagent({ workflowScript: `
203
207
  ` });
204
208
  ```
205
209
 
206
- The receipt state is `queued`, `delivered`, `missed`, or `failed`. `delivered` means the child Pi session accepted the input. It does not mean the model followed it. `missed` means the keyed child became terminal or had no live route before delivery. This first slice uses the existing foreground and async steering transports but does not start steering recovery. Workflow traces include one steering attempt entry and one receipt entry.
210
+ The receipt state is `queued`, `delivered`, `missed`, or `failed`. For an async child, `delivered` means it consumed the correlated user input; for a foreground child, it means the in-process Pi transport accepted the input. It does not mean the model followed it. `missed` means the keyed child became terminal or had no live route before delivery. This first slice uses the existing foreground and async steering transports but does not start steering recovery. Workflow traces include one steering attempt entry and one receipt entry.
207
211
 
208
212
  Always await or return a `runs.steer` promise. The workflow waits for an observed steering side effect to settle before it exits and rejects fire-and-forget calls. Use ordinary `Promise.race` when the first child or steering receipt should advance the script. There is no callback API or child inbox access.
209
213
 
@@ -380,6 +384,8 @@ Each child uses the existing worktree lifecycle: it branches from clean HEAD, jo
380
384
 
381
385
  A top-level `{ workflowScript, worktree: true }` makes isolation the default for every workflow child. An individual child can override that default with `worktree: false`. Keep one writer when parallel writes are not intentionally isolated.
382
386
 
387
+ Before a materialized `runs.run` or `runs.all` group dispatches fresh children, isolated sources must be Git repositories with clean working trees (excluding `.pi/subagents/` runtime state). A rejected group dispatches no children and spends no fan-out slots or child output claims; key-level failure traces can remain. Checks are shared only within that group, are cancellable, and run again at allocation because sources can change. Retained resumes keep their stored contracts. Select the correct cwd or arrange an operator-approved commit/stash; isolation is never dropped automatically.
388
+
383
389
  Use `baseRef` to branch managed worktrees from `HEAD` or a supported named ref such as `refs/heads/release`, `refs/tags/v1`, or `origin/main`. Full 40/64-character commit IDs and revision expressions such as `HEAD~1` are unsupported. For example, `{ workflowScript, worktree: true, baseRef: "refs/heads/release" }` applies the release ref to children unless a child supplies its own `baseRef`. If omitted, the default `HEAD` is resolved at worktree allocation, not when the script is validated or a schedule is created. The source checkout must still be clean, and the ref must resolve to a commit before any worktree is allocated.
384
390
 
385
391
  Configure the worktree provider, native path layout, base directory, and setup hook in [configuration.md](configuration.md).
@@ -439,6 +445,14 @@ Children should not ask for clarification when the only conflict is review-only/
439
445
 
440
446
  The parent replies with `subagent_supervisor({ action: "reply", replyTo, message })` or checks pending requests with `subagent_supervisor({ action: "pending" })`. Supervisor messages are scoped to the exact Pi session id that spawned the child. A second Pi session in the same repository does not receive those requests.
441
447
 
448
+ A nested coordinator needs both directions of coordination. If its agent declares an explicit `tools` allowlist, include `subagent_supervisor` to answer its own children, alongside `subagent` for delegation and `contact_supervisor` for asking its parent:
449
+
450
+ ```yaml
451
+ tools: read, subagent, contact_supervisor, subagent_supervisor
452
+ ```
453
+
454
+ For A → B → C, C's request belongs to B, not A. B can escalate a separate question to A with `contact_supervisor`, then answer C using C's original `replyTo` request id. A's reply to B does not resolve C's request, and steering is not a substitute for replying. Only fanout-authorized children get the downward supervisor provider; explicit tool exclusions and capability ceilings still apply, and ordinary leaves do not gain delegation or reply tools. Requesting `subagent_supervisor` without fanout authorization fails at launch with an actionable error. A coordinator that excludes the reply tool does not start downward supervision or receive prompts to use it. Explicitly selected native coordination tools survive host-builtin filtering because their providers are child runtime hooks, not host builtins.
455
+
442
456
  Child-side routine completion handoffs are not expected. If a child appears stalled, needs-attention notices show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
443
457
 
444
458
  If a `workflowScript` child detaches through `contact_supervisor`, the enclosing async workflow stays `paused` until that child exits. Then the extension reconciles it to `complete` or `failed`. Wait on the child until that happens.
@@ -1,11 +1,11 @@
1
1
  import { createJiti } from "jiti";
2
2
 
3
3
  const jiti = createJiti(import.meta.url);
4
- const { runInspector } = await jiti.import("./src/inspectors/herdr/inspector-runner.ts");
4
+ const { runInspector } = await jiti.import("./src/inspectors/inspector-runner.ts");
5
5
 
6
6
  try {
7
7
  runInspector();
8
8
  } catch (cause) {
9
- process.stderr.write(`Herdr inspector failed: ${cause instanceof Error ? cause.message : String(cause)}\n`);
9
+ process.stderr.write(`Inspector failed: ${cause instanceof Error ? cause.message : String(cause)}\n`);
10
10
  process.exitCode = 1;
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.66.0",
3
+ "version": "0.67.0",
4
4
  "description": "Pi extension for single-agent delegation and scripted multi-agent workflows",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
@@ -28,7 +28,7 @@ Choose or adapt angles when the work calls for it:
28
28
 
29
29
  Prefer three strong reviewers over many vague reviewers.
30
30
 
31
- Give every reviewer a specific task prompt naming its angle. Ask reviewers to return concise, evidence-backed findings with file/line references and suggested fixes. Filter on evidence, not severity: a finding must be concrete, current, caused or made reachable by the target diff, and supported by source proof, a test or repro, or a contract contradiction. Label findings P0/P1/P2. P0 blocks merge. P1 should be fixed before release. P2 is report-only. End each review with `Merge verdict: BLOCK`, `Merge verdict: OK`, or `Merge verdict: OK with notes`. If nothing qualifies, ask the reviewer to say exactly `No issues found.` The response should be review feedback, not a context summary. Reviewers must not edit files unless I explicitly ask for a writer pass.
31
+ Give every reviewer a specific task prompt naming its angle. Ask reviewers to return concise, evidence-backed findings with file/line references and suggested fixes. Filter on evidence, not severity: a finding must be concrete and current within the named review target, and supported by source proof, a test or repro, or a contract contradiction. For a diff review, require that the issue is caused or made reachable by that diff. Label findings P0/P1/P2. P0 blocks merge. P1 should be fixed before release. P2 is report-only. End each review with `Merge verdict: BLOCK`, `Merge verdict: OK`, or `Merge verdict: OK with notes`. If nothing qualifies, ask the reviewer to say exactly `No issues found.` The response should be review feedback, not a context summary. Reviewers must not edit files unless I explicitly ask for a writer pass.
32
32
 
33
33
  Do not default first-pass reviews to `blockers only`. That phrase is valid only for final pre-merge re-checks after P1/P2 findings are already inventoried, or for explicit emergency hotfix lanes where non-blocking findings are intentionally deferred.
34
34
 
@@ -1,11 +1,16 @@
1
- // Only loaded when the parent supplies Pi 0.85.0's missing server exports.
2
1
  import { registerHooks } from "node:module";
3
2
  import { pathToFileURL } from "node:url";
4
3
 
5
- const aliases = JSON.parse(process.env.JITI_ALIAS);
4
+ const aliases = JSON.parse(process.env.JITI_ALIAS ?? "{}");
5
+ const redirected = new Set([
6
+ "@earendil-works/pi-server",
7
+ "@earendil-works/pi-server/unix",
8
+ "@earendil-works/pi-tui",
9
+ ]);
10
+
6
11
  registerHooks({
7
12
  resolve(specifier, context, nextResolve) {
8
- if (specifier === "@earendil-works/pi-server" || specifier === "@earendil-works/pi-server/unix") {
13
+ if (redirected.has(specifier) && aliases[specifier]) {
9
14
  return nextResolve(pathToFileURL(aliases[specifier]).href, context);
10
15
  }
11
16
  return nextResolve(specifier, context);
@@ -50,6 +50,18 @@ use ordinary `runs.run(...)` / `runs.all(...)`. See the [canonical staged-lane
50
50
  example](../../docs/workflows.md#parallel-sequential-lanes). Keep assignments
51
51
  bounded, but do not add stages or ceremony just to satisfy this skill.
52
52
 
53
+ When composing `runs.run(...)`, `runs.all(...)`, or `runs.lanes(...)`, always
54
+ supply a short verb + behavior display `label` derived from the task, unless
55
+ the user supplied an explicit label; preserve that label. Keep the stable
56
+ machine `key` independent (for example, `issue2011-writer` with
57
+ `label: "Fix workflow steering"`). For `runs.lanes`, put labels on stage
58
+ items, not lane objects. Use stage-appropriate labels for reviews and retained-child
59
+ follow-ups too (for example, `Review workflow steering`). Generate labels in
60
+ the orchestrator while composing the launch—no extra model call, runtime
61
+ generator, or schema change. Native direct `{ agent, task }` calls have no
62
+ top-level `label` parameter; do not invent one or wrap a tiny single task in
63
+ a workflow just to label it.
64
+
53
65
  Use async/background by default. Set `async:false` only when the parent must
54
66
  block. Final reviews, validation gates, oracle checks, and publication checks
55
67
  stay async.
@@ -71,6 +83,8 @@ that runner explicitly supports the option.
71
83
 
72
84
  ## Read the reference for the branch
73
85
 
86
+ For exact API fields and worked examples, call `subagent({action:"guide",topic:"tool-reference"})` or `topic:"workflows"`. The compact tool definition is not the recipe catalog; use `topic:"missions"` for mission updates and schedules.
87
+
74
88
  | Branch | Read |
75
89
  | --- | --- |
76
90
  | Delegate or choose roles, prompts, models, or slash commands | `references/prompting-and-roles.md` |
@@ -83,10 +83,10 @@ lanes, or a fanout that the parent will consume together.
83
83
  ```js
84
84
  subagent({
85
85
  workflowScript: `
86
- const scan = await runs.run("scan", { agent: "scout", task: "Map the target" });
86
+ const scan = await runs.run("scan", { label: "Map target behavior", agent: "scout", task: "Map the target" });
87
87
  const reviews = await runs.all([
88
- { key: "correctness", agent: "reviewer", task: "Review correctness: " + scan.output },
89
- { key: "tests", agent: "reviewer", task: "Review tests: " + scan.output }
88
+ { key: "correctness", label: "Review target correctness", agent: "reviewer", task: "Review correctness: " + scan.output },
89
+ { key: "tests", label: "Review target test coverage", agent: "reviewer", task: "Review tests: " + scan.output }
90
90
  ]);
91
91
  return reviews.map(result => result.output);
92
92
  `
@@ -109,6 +109,7 @@ Terminal async workflows also persist `workflow-receipt.json` beside `status.jso
109
109
 
110
110
  ```js
111
111
  return runs.run("cross-oracle", {
112
+ label: "Challenge proposed direction",
112
113
  resume: { workflowRunId: "<pass-1-workflow-id>", key: "advisor-oracle", latest: true },
113
114
  task: "Review the focused challenge packet."
114
115
  });
@@ -120,7 +121,8 @@ Keyed resume reads that one exact receipt and revalidates the retained run at la
120
121
 
121
122
  For a broad plan with a known set of narrow, visible stages per lane, use
122
123
  `runs.lanes(...)` inside a `workflowScript`; it is a nested helper, not a
123
- top-level `subagent` mode. Give each lane and stage a stable key. The first
124
+ top-level `subagent` mode. Give each lane and stage a stable key; give stage
125
+ items a short verb + behavior `label`, preserving explicit user labels. The first
124
126
  stage from every lane is launched together, then later stages sequence per lane.
125
127
  `resume: "previous"` requires the retained predecessor, and a failed or blocked
126
128
  stage blocks only that lane. The returned board exposes lane/stage results for
@@ -338,7 +340,7 @@ subagent({ action: "steer", id: "abc123", mode: "follow_up", message: "After thi
338
340
  subagent({ action: "steer", id: "abc123", mode: "auto", message: "Switch to the failing test now." })
339
341
  ```
340
342
 
341
- Direct input acceptance returns `delivered`, not proof of model compliance. A live follow-up acknowledgment reports `queued`, meaning Pi accepted it into its follow-up queue, not that it was delivered. The runtime does not provide a later correlated live queued-to-delivered receipt.
343
+ For async runs, `delivered` records that the child consumed the correlated user input; foreground `delivered` records in-process transport acceptance. Neither is proof of model compliance. A live foreground follow-up acknowledgment reports `queued`, meaning Pi accepted it into its follow-up queue, not that it was delivered. The foreground transport does not provide a later correlated queued-to-delivered receipt.
342
344
 
343
345
  ## Watchdog
344
346
 
@@ -63,7 +63,7 @@ Council advisors are read-only. User or project `council-*` profiles choose allo
63
63
 
64
64
  ### Parallel review technique
65
65
 
66
- Use this when the user wants adversarial review of a diff, plan, issue, file, or implemented work. Launch fresh-context `reviewer` agents with distinct angles generated from the actual target. Common angles are correctness/regressions, tests/validation, and simplicity/maintainability; adapt for TypeScript, UI, security, docs, or large structural changes. Reviewers should inspect files and diffs directly, return concise evidence-backed findings with file/line references, and avoid edits unless the user explicitly asks for a writer pass. Filter on evidence, not severity: report only concrete current issues caused or made reachable by the target diff, with source proof, a test or repro, or a contract contradiction. Label findings P0/P1/P2 and end with `Merge verdict: BLOCK`, `Merge verdict: OK`, or `Merge verdict: OK with notes`. Use `blockers only` only for final pre-merge re-checks after P1/P2 findings are already captured, or for explicit emergency hotfix lanes where non-blocking findings are intentionally deferred. For targeted follow-up, ask only whether the named finding was resolved, whether the fix introduced a new defect in the fix blast radius, and whether prior P1/P2 notes still stand. For bot or PR-comment triage, classify each comment as VALID, STALE, INVALID, or OUT-OF-POLICY against current HEAD, then assign P0/P1/P2 only to VALID comments. The parent synthesizes fixes worth doing now, optional improvements, and feedback to ignore/defer before applying anything.
66
+ Use this when the user wants adversarial review of a diff, plan, issue, file, or implemented work. Launch fresh-context `reviewer` agents with distinct angles generated from the actual target. Common angles are correctness/regressions, tests/validation, and simplicity/maintainability; adapt for TypeScript, UI, security, docs, or large structural changes. Reviewers should inspect files and diffs directly, return concise evidence-backed findings with file/line references, and avoid edits unless the user explicitly asks for a writer pass. Filter on evidence, not severity: report concrete current issues within the named review target, with source proof, a test or repro, or a contract contradiction. For a diff review, require that the issue is caused or made reachable by that diff. Label findings P0/P1/P2 and end with `Merge verdict: BLOCK`, `Merge verdict: OK`, or `Merge verdict: OK with notes`. Use `blockers only` only for final pre-merge re-checks after P1/P2 findings are already captured, or for explicit emergency hotfix lanes where non-blocking findings are intentionally deferred. For targeted follow-up, ask only whether the named finding was resolved, whether the fix introduced a new defect in the fix blast radius, and whether prior P1/P2 notes still stand. For bot or PR-comment triage, classify each comment as VALID, STALE, INVALID, or OUT-OF-POLICY against current HEAD, then assign P0/P1/P2 only to VALID comments. The parent synthesizes fixes worth doing now, optional improvements, and feedback to ignore/defer before applying anything.
67
67
 
68
68
  ### Proactive skill-specialist technique
69
69
 
@@ -283,7 +283,7 @@ Keep the parent/orchestrator on the ordinary strong default model because omissi
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
 
286
- Use `fallbackModels` when a tier has provider quota or availability risk. Prefer fresh context for cross-provider children when inherited provider-specific reasoning blocks would force thinking off.
286
+ Use `fallbackModels` when a tier has provider quota or availability risk. Forked children keep their requested thinking level even when provider-specific reasoning blocks are stripped from the inherited transcript.
287
287
 
288
288
  If a provider rejects model IDs with thinking suffixes, use
289
289
  `subagents.disableThinking: true` in user or project settings to clear bundled
@@ -57,7 +57,38 @@ export function buildAdvertisedAgentPrompt(
57
57
  return render(entries);
58
58
  }
59
59
 
60
- export function appendAdvertisedAgentPrompt(systemPrompt: string, advertisedPrompt: string | undefined): string {
61
- const base = systemPrompt.replace(ADVERTISED_AGENTS_BLOCK, "");
62
- return advertisedPrompt ? `${base.trimEnd()}\n\n${advertisedPrompt}` : base;
60
+ export function appendAdvertisedAgentPrompt(systemPrompt: string, advertisedPrompt: string | undefined): string;
61
+ export function appendAdvertisedAgentPrompt(systemPrompt: string[], advertisedPrompt: string | undefined): string[];
62
+ export function appendAdvertisedAgentPrompt(systemPrompt: undefined, advertisedPrompt: string | undefined): string | undefined;
63
+ export function appendAdvertisedAgentPrompt(
64
+ systemPrompt: string | string[] | undefined,
65
+ advertisedPrompt: string | undefined,
66
+ ): string | string[] | undefined;
67
+ export function appendAdvertisedAgentPrompt(
68
+ systemPrompt: string | string[] | undefined,
69
+ advertisedPrompt: string | undefined,
70
+ ): string | string[] | undefined {
71
+ if (Array.isArray(systemPrompt)) {
72
+ let changed = false;
73
+ const cleaned = systemPrompt
74
+ .map((part) => {
75
+ if (typeof part !== "string") return part;
76
+ const stripped = part.replace(ADVERTISED_AGENTS_BLOCK, "");
77
+ if (stripped !== part) changed = true;
78
+ return stripped;
79
+ })
80
+ .filter((b) => typeof b === "string" && b.length > 0);
81
+
82
+ if (advertisedPrompt) {
83
+ return [...cleaned, advertisedPrompt];
84
+ }
85
+ return changed ? cleaned : systemPrompt;
86
+ }
87
+
88
+ if (typeof systemPrompt === "string") {
89
+ const base = systemPrompt.replace(ADVERTISED_AGENTS_BLOCK, "");
90
+ return advertisedPrompt ? (base.trim() ? `${base.trimEnd()}\n\n${advertisedPrompt}` : advertisedPrompt) : base;
91
+ }
92
+
93
+ return advertisedPrompt;
63
94
  }
@@ -181,6 +181,12 @@ export interface AgentConfig {
181
181
  override?: BuiltinAgentOverrideInfo;
182
182
  modelSource?: AgentModelSourceInfo;
183
183
  maxThinking?: ThinkingLevel;
184
+ /**
185
+ * Digest of the parsed definition, set when a runtime overlay such as the
186
+ * Intercom bridge rewrites launch-affecting fields. Launch identity reads
187
+ * this instead of re-hashing the overlaid copy.
188
+ */
189
+ definitionDigest?: string;
184
190
  }
185
191
 
186
192
  type ProjectRootResolution = "nearest" | "git-root";
@@ -7,6 +7,7 @@ export const BUILTIN_AGENT_NAMES = [
7
7
  "cursor-agent",
8
8
  "cursor-agent-writer",
9
9
  "delegate",
10
+ "evidence-auditor",
10
11
  "oracle",
11
12
  "researcher",
12
13
  "reviewer",
@@ -1,3 +1,5 @@
1
+ import type { IntercomBridgeConfig } from "../shared/types.ts";
2
+
1
3
  // This is the established extension-to-extension transport. The structured
2
4
  // delegation API intentionally reuses it instead of adding a second event
3
5
  // protocol. Unstructured legacy direct payloads are rejected.
@@ -35,6 +37,8 @@ export interface SubagentDelegationRequest {
35
37
  toolBudget?: SubagentDelegationToolBudget;
36
38
  skill?: string | string[] | boolean;
37
39
  artifacts?: boolean;
40
+ /** Per-launch bridge config; replaces the global `intercomBridge` config. Pass the same value to preflight to compare digests. */
41
+ intercomBridge?: IntercomBridgeConfig;
38
42
  result: SubagentDelegationResultRequest;
39
43
  }
40
44