pi-subagents 0.45.2 → 0.46.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 +24 -0
- package/README.md +2 -0
- package/docs/agents.md +342 -0
- package/docs/configuration.md +320 -0
- package/docs/extension-api.md +308 -0
- package/docs/missions.md +117 -0
- package/docs/models.md +190 -0
- package/docs/observability.md +174 -0
- package/docs/tool-reference.md +343 -0
- package/docs/watchdog.md +176 -0
- package/docs/workflows.md +163 -0
- package/package.json +4 -2
- package/skills/pi-subagents/references/execution-controls.md +2 -2
- package/src/agents/agents.ts +17 -8
- package/src/agents/frontmatter.ts +7 -3
- package/src/agents/skills.ts +2 -9
- package/src/api/project-panes.ts +30 -0
- package/src/extension/config.ts +15 -1
- package/src/extension/index.ts +36 -16
- package/src/extension/schemas.ts +3 -2
- package/src/extension/subagent-guide.ts +39 -0
- package/src/extension/tool-description.ts +4 -4
- package/src/inspectors/herdr/project-panes.ts +457 -62
- package/src/missions/actions.ts +25 -2
- package/src/missions/lifecycle.ts +21 -2
- package/src/missions/store.ts +77 -1
- package/src/missions/types.ts +33 -0
- package/src/runs/background/async-execution.ts +7 -1
- package/src/runs/background/completion-replay.ts +267 -0
- package/src/runs/background/result-watcher.ts +12 -4
- package/src/runs/background/wait-completions.ts +39 -5
- package/src/runs/background/wait-subscriptions.ts +18 -3
- package/src/runs/foreground/execution.ts +4 -0
- package/src/runs/foreground/foreground-history.ts +137 -0
- package/src/runs/foreground/subagent-executor.ts +310 -44
- package/src/shared/fork-context.ts +13 -0
- package/src/shared/prompt-resources.ts +51 -0
- package/src/shared/types.ts +30 -1
- package/src/shared/utf8.ts +11 -0
- package/src/slash/prompt-workflows.ts +2 -15
- package/src/slash/slash-commands.ts +19 -1
- package/src/tui/fleet-status.ts +8 -2
- package/src/tui/fleet.ts +135 -25
- package/src/tui/render.ts +120 -7
- package/src/workflows/scripted-workflow.ts +167 -10
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
`pi-subagents` reads optional JSON config from `~/.pi/agent/extensions/subagent/config.json`. This page lists every key, plus the environment variables and the settings-file keys that affect config resolution.
|
|
4
|
+
|
|
5
|
+
Settings-level keys (`subagents.defaultModel`, `defaultThinking`, `defaultExtensions`, `agentOverrides`, `modelScope`, `disableThinking`, `disableBuiltins`, watchdog settings) live in Pi settings files, not this config file. See [models.md](models.md), [agents.md](agents.md), and [watchdog.md](watchdog.md).
|
|
6
|
+
|
|
7
|
+
## Project root resolution (settings)
|
|
8
|
+
|
|
9
|
+
By default, project settings resolve from the nearest parent directory that contains `.pi` or `.agents`, preserving existing nested-project behavior. In monorepos or git worktrees where an incidental nested `.pi` directory should not shadow the repository-level config, set this in the repository root `.pi/settings.json`:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"subagents": {
|
|
14
|
+
"projectRootResolution": "git-root"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`"git-root"` keeps package discovery, project agents, chains, and `agentOverrides` anchored to the git worktree root when that root also has Pi project config. A nested project can still opt back into nearest-root behavior by setting `"projectRootResolution": "nearest"` in its own `.pi/settings.json`.
|
|
20
|
+
|
|
21
|
+
## `toolDescriptionMode`
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{ "toolDescriptionMode": "compact" }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Controls the parent-facing `subagent` tool description registered at startup. `full` is the default. `compact` keeps the execution modes, async/`subagent_wait` guidance, child-safety boundary, management/action split, one-writer review guidance, and artifact/status essentials with less prompt bloat.
|
|
28
|
+
|
|
29
|
+
`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.
|
|
30
|
+
|
|
31
|
+
## `inlineToolDisplay`
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{ "inlineToolDisplay": "summary" }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Controls the `subagent` tool result shown inline in chat. The default, `"rich"`, shows live child activity and expands to detailed output. `"summary"` keeps the inline result at one stable row for running, completed, failed, stopped, and paused runs; it does not animate, show elapsed time, preview child output, or change when Pi's expand key is pressed. FleetView remains available for live progress and detailed inspection.
|
|
38
|
+
|
|
39
|
+
## `asyncByDefault`
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{ "asyncByDefault": false }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
WorkflowScript calls use background execution when the request omits `async`. Set `asyncByDefault` to `false` to restore foreground-by-default behavior for tool launches that still use the internal single-run primitive. Callers can still force foreground with `async: false` unless `forceTopLevelAsync` is enabled.
|
|
46
|
+
|
|
47
|
+
## `fleetView`
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{ "fleetView": false }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Controls the persistent, navigable FleetView. The default is `true`. Set it to `false` to hide FleetView without disabling status tracking, completion notifications, `/subagents-fleet`, or lifecycle events.
|
|
54
|
+
|
|
55
|
+
## `fleetViewPlacement`
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{ "fleetViewPlacement": "aboveEditor" }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Places the persistent FleetView either `"belowEditor"` or `"aboveEditor"`. The default is `"belowEditor"`; invalid values fall back to `"belowEditor"`.
|
|
62
|
+
|
|
63
|
+
## `fleetKeybindings`
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"fleetKeybindings": {
|
|
68
|
+
"pageUp": ["u"],
|
|
69
|
+
"pageDown": ["d"],
|
|
70
|
+
"selectFirst": ["g"],
|
|
71
|
+
"selectLast": ["G"]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Customizes only the full Fleet inspector opened by `/subagents-fleet` or FleetView inspection. It does not change Pi's global keybindings or the compact persistent FleetView.
|
|
77
|
+
|
|
78
|
+
Each action accepts a non-empty array of key strings. Configured actions replace their defaults. Unset actions keep the defaults: `selectUp` is `up`/`k`, `selectDown` is `down`/`j`, `scrollUp` is `K`, `scrollDown` is `J`, `pageUp` is `pageUp`, `pageDown` is `pageDown`, `selectFirst` is `home`, `selectLast` is `end`, `toggleTools` is `x`/`X`/`ctrl+o`, `refresh` is `r`/`R`, `steer` is `s`, `stop` is `D`, `inspect` is `H`, and `close` is `escape`/`ctrl+c`/`q`.
|
|
79
|
+
|
|
80
|
+
Prompt modes keep their fixed keys. For example, `Esc` still cancels steer text or stop confirmation even when the Fleet-level close binding is changed.
|
|
81
|
+
|
|
82
|
+
## `asyncWidget`
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{ "asyncWidget": true }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Controls the under-editor widget for active background runs. It defaults to `true`, including when FleetView is enabled, so active work remains visible after reload. Set it to `false` to hide this widget while keeping FleetView available.
|
|
89
|
+
|
|
90
|
+
## `waitTool`
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{ "waitTool": { "enabled": false } }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Keeps the `subagent_wait` tool registered but makes direct calls return immediately instead of blocking on active subagent or provider work. The default is enabled. You can also set `"waitTool": false`; set `PI_SUBAGENT_WAIT_TOOL_ENABLED=false` (or `0`, `off`, `disabled`) to override config for one process. The effective value is passed explicitly to child runtimes. Headless `agent_end` auto-drain remains a lifecycle safeguard even when direct wait calls are disabled. Invalid config or environment values fail instead of being coerced.
|
|
97
|
+
|
|
98
|
+
Blocking `subagent_wait({ id: "..." })` keeps the current tool call open until that run changes. In a long-lived interactive parent session, `subagent_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. Armed subscriptions appear in ordinary `subagent({ action: "status" })` output and are not counted as active child work.
|
|
99
|
+
|
|
100
|
+
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.
|
|
101
|
+
|
|
102
|
+
## `forceTopLevelAsync`
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{ "forceTopLevelAsync": true }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Forces depth-0 internal single, parallel, and chain runs into background mode and bypasses launch UI by forcing `clarify: false`. Nested calls keep their own inherited settings.
|
|
109
|
+
|
|
110
|
+
## `globalConcurrencyLimit`
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{ "globalConcurrencyLimit": 20 }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Caps simultaneously running children inside existing durable legacy multi-child runs. New orchestration uses `workflowScript` and `runs.all`.
|
|
117
|
+
|
|
118
|
+
## `maxSubagentSpawnsPerSession`
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{ "maxSubagentSpawnsPerSession": 100 }
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Optionally caps the total number of child subagent launches during one parent session, including completed and failed children, parallel task counts, static chain steps, and bounded dynamic fanout children. Sessions are unlimited by default. Set this value to `0` to disable a configured cap. `PI_SUBAGENT_MAX_SPAWNS_PER_SESSION` overrides the config for a process and follows the same positive-cap/zero-unlimited semantics.
|
|
125
|
+
|
|
126
|
+
`subagent({ action: "status" })`, fleet status, and `subagent({ action: "doctor" })` expose used, effective limit, remaining capacity, grants, and the remaining grant allowance. Static chains and parallel calls fail before creating run artifacts or starting partial work when their declared capacity cannot fit. Later retries or unbounded dynamic work are not guaranteed by that preflight.
|
|
127
|
+
|
|
128
|
+
A user may explicitly call `subagent({ action: "grant-spawn-budget", additional: 10 })` from the root interactive parent after all children settle and confirm the native prompt. Grants are additive: they never erase cumulative usage, are rejected for unlimited sessions and child/headless callers, and total granted capacity cannot exceed the original configured cap. Compaction remains part of the same logical parent session and does not reset usage or grants; starting a new parent session does.
|
|
129
|
+
|
|
130
|
+
## `scheduledRuns`
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{ "scheduledRuns": { "enabled": false, "maxPending": 20 } }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Durable schedules are enabled by default and stored per project under `.pi-subagents/schedules/<id>/`. See [missions.md](missions.md#schedules) for usage.
|
|
137
|
+
|
|
138
|
+
Set `storeRoot` to keep durable schedules outside project repositories. It must be an absolute path or a `~/` path, which expands from the user home directory. Each project is stored under a hash of its resolved working directory, so projects do not share schedules.
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{ "scheduledRuns": { "storeRoot": "~/.local/share/pi-subagents/schedules" } }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
When `storeRoot` is omitted, schedules remain at `<cwd>/.pi-subagents/schedules`.
|
|
145
|
+
|
|
146
|
+
## `parallel`
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"parallel": {
|
|
151
|
+
"maxTasks": 12,
|
|
152
|
+
"concurrency": 6
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`maxTasks` defaults to `8`; `concurrency` defaults to `4`. Per-call `concurrency` takes precedence.
|
|
158
|
+
|
|
159
|
+
## `defaultSessionDir`
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{ "defaultSessionDir": "~/.pi/agent/sessions/subagent/" }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Session directory precedence is: `params.sessionDir`, then `config.defaultSessionDir`, then a directory derived from the parent session. Sessions are always enabled.
|
|
166
|
+
|
|
167
|
+
## `singleRunOutputBaseDir`
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{ "singleRunOutputBaseDir": "~/.pi/subagent-outputs" }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Routes relative `output` paths for single-agent `/run` calls under this directory. Absolute per-call or agent output paths are still used as-is. When unset, relative single-run outputs go under the run's output artifact directory instead of the project root.
|
|
174
|
+
|
|
175
|
+
## `maxSubagentDepth`
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{ "maxSubagentDepth": 1 }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent's child runs, but cannot relax an inherited stricter limit. This applies even to children that explicitly declare `tools: subagent`; at the cap, execution fanout is blocked instead of silently hiding nested work.
|
|
182
|
+
|
|
183
|
+
## `PI_SUBAGENT_PI_BINARY`
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
export PI_SUBAGENT_PI_BINARY=/path/to/pi-or-wrapper
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Overrides the command used to launch child Pi processes. Package wrappers can set this to their own `pi`/agent binary so subagents inherit wrapper flags, environment setup, and bundled resources without relying on `PATH` ordering. Empty or whitespace-only values are ignored.
|
|
190
|
+
|
|
191
|
+
## `intercomBridge`
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"intercomBridge": {
|
|
196
|
+
"mode": "always",
|
|
197
|
+
"instructionFile": "./intercom-bridge.md",
|
|
198
|
+
"resultDelivery": true
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Controls whether subagents receive runtime intercom coordination instructions and whether `intercom` and `contact_supervisor` are auto-added to their tool allowlist when needed.
|
|
204
|
+
|
|
205
|
+
Fields:
|
|
206
|
+
|
|
207
|
+
- `mode`: default `always`; use `fork-only` to inject only for forked runs, or `off` to disable the bridge.
|
|
208
|
+
- `instructionFile`: optional Markdown template replacing the default bridge instructions. `{orchestratorTarget}` is interpolated. Relative paths resolve from `~/.pi/agent/extensions/subagent/`.
|
|
209
|
+
- `resultDelivery`: default `false`; set `true` only when an external listener consumes `subagent:result-intercom` and acknowledges the grouped completion payload. This is optional external result delivery, not native supervisor messaging. Enabled delivery waits for acknowledgement and reports acknowledgement failures. It does not change supervisor asks or progress updates.
|
|
210
|
+
|
|
211
|
+
Bridge activation requires a targetable current parent session id, which `pi-subagents` passes to children automatically. Native supervisor messaging does not require an external `pi-intercom` installation or per-agent extension allowlists: children use `contact_supervisor`, and parents use `subagent_supervisor` to inspect or reply. The external `intercom` tool is fallback plumbing when present.
|
|
212
|
+
|
|
213
|
+
The default injected guidance tells children to use `contact_supervisor` with `reason: "need_decision"` when blocked or needing a decision, `reason: "progress_update"` only for meaningful blocked/progress updates, generic `intercom` as fallback plumbing, and avoid routine completion handoffs.
|
|
214
|
+
|
|
215
|
+
## `worktreeBaseDir`
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{ "worktreeBaseDir": "/Users/matt/code/.worktrees/pi-subagents" }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Sets the base directory for `worktree: true` runs. Relative paths resolve from the repository root, `~/...` expands to your home directory, and `PI_SUBAGENTS_WORKTREE_DIR` is used when config is unset. The default remains the system temp directory.
|
|
222
|
+
|
|
223
|
+
## `worktreeSetupHook`
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"worktreeSetupHook": "./scripts/setup-worktree.mjs",
|
|
228
|
+
"worktreeSetupHookTimeoutMs": 45000
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The hook runs once per created worktree. Paths must be absolute, `~/...`, or repo-relative; bare command names are rejected.
|
|
233
|
+
|
|
234
|
+
stdin is a JSON object with `repoRoot`, `worktreePath`, `agentCwd`, `branch`, `index`, `runId`, and `baseCommit`. stdout must be one JSON object, for example:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{ "syntheticPaths": [".venv", ".env.local"] }
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`syntheticPaths` must be relative to the worktree root. They are removed before diff capture so helper files do not pollute patches. Tracked files are never excluded; marking a tracked path as synthetic fails setup. Default timeout is `30000` ms.
|
|
241
|
+
|
|
242
|
+
## `missions`
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"missions": {
|
|
247
|
+
"enabled": true,
|
|
248
|
+
"directory": ".pi-subagents/missions",
|
|
249
|
+
"globalIndex": true,
|
|
250
|
+
"retainTerminal": 200
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Automatic missions are enabled by default for ordinary launches with a task. Use per-launch `mission: false` for intentionally ephemeral work, or set `enabled: false` to disable automatic creation globally; explicit mission actions and `missionId`/`mission` launch fields still work.
|
|
256
|
+
|
|
257
|
+
- `directory` may be absolute, `~/...`, or project-relative.
|
|
258
|
+
- `retainTerminal` is a positive count (default `200`); pruning removes only the oldest completed, failed, or cancelled records and their pointers, never planned, active, waiting, needs-decision, or corrupt records.
|
|
259
|
+
- The user-global index contains pointers only; missing-record pointers self-heal when globally listed. Set `globalIndex: false` to disable writes or `globalIndexDir` to redirect it.
|
|
260
|
+
|
|
261
|
+
## `authorityPolicy`
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"authorityPolicy": {
|
|
266
|
+
"discardWorktree": "confirm",
|
|
267
|
+
"destructiveCleanup": "confirm",
|
|
268
|
+
"spawnBudgetGrant": "confirm",
|
|
269
|
+
"scheduleCreate": "auto",
|
|
270
|
+
"stopRun": "auto",
|
|
271
|
+
"steerRun": "auto"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Each fixed action resolves to `"auto"`, `"confirm"`, or `"forbid"`. This is intentionally a small action map, not a generic policy language. Confirm-required control actions fail closed without an interactive UI.
|
|
277
|
+
|
|
278
|
+
## `artifactDir`
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{ "artifactDir": "session" }
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Controls where subagent artifact files (inputs, outputs, transcripts, metadata) are stored:
|
|
285
|
+
|
|
286
|
+
- `"project"` (default): writes to `<cwd>/.pi-subagents/artifacts/`.
|
|
287
|
+
- `"session"`: stores artifacts under pi's session directory (`~/.pi/agent/sessions/<session>/subagent-artifacts/`), keeping the working directory clean.
|
|
288
|
+
- `"temp"`: uses the OS temp directory.
|
|
289
|
+
|
|
290
|
+
This preference also controls the default chain scratch directory. `"project"` uses `<cwd>/.pi-subagents/chain-runs/`, while `"session"` and `"temp"` use the user-scoped temp chain directory.
|
|
291
|
+
|
|
292
|
+
The `"session"` option uses the same directory that `cleanupAllArtifactDirs` already scans for age-based cleanup, so artifacts are still cleaned up automatically. Temporary chain directories are cleaned up separately after 24 hours.
|
|
293
|
+
|
|
294
|
+
When a project-scoped launch runs from an npm package directory, pi-subagents warns if package settings can include `.pi-subagents/` in the published package. Add `.pi-subagents/` to `.npmignore` (or `.gitignore` when no `.npmignore` exists), use a `files` allowlist that does not include `.pi-subagents/`, or select `"session"` or `"temp"`.
|
|
295
|
+
|
|
296
|
+
## `completionBatch`
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"completionBatch": {
|
|
301
|
+
"enabled": true,
|
|
302
|
+
"debounceMs": 150,
|
|
303
|
+
"maxWaitMs": 1000,
|
|
304
|
+
"stragglerDebounceMs": 75,
|
|
305
|
+
"stragglerMaxWaitMs": 400,
|
|
306
|
+
"stragglerWindowMs": 2000
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Controls smart batching of async-completion notifications. When several background subagents finish within a short window, their successful completions are held briefly and delivered as a single quiet grouped completion instead of separate completions.
|
|
312
|
+
|
|
313
|
+
- A hard `maxWaitMs` cap (measured from the first completion in a group) guarantees nothing is held indefinitely.
|
|
314
|
+
- Late-finishing siblings that arrive within `stragglerWindowMs` of a group emit join a shorter straggler group governed by `stragglerDebounceMs` and `stragglerMaxWaitMs`.
|
|
315
|
+
- Failed and paused completions bypass batching and fire immediately, flushing any held successes first, so failure and needs-attention signals are never delayed.
|
|
316
|
+
- Set `enabled` to `false` to restore the original one-notification-per-completion behavior. Changes apply on the next session start.
|
|
317
|
+
|
|
318
|
+
## `permissions`
|
|
319
|
+
|
|
320
|
+
Native child tool permission rules. See [watchdog.md](watchdog.md#native-child-tool-permissions).
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Extension and integration APIs
|
|
2
|
+
|
|
3
|
+
Public seams for other Pi extensions and host integrations: the in-process RPC, the structured delegation API, launch preflight, capability ceilings, the background-work provider contract, and the Herdr integration.
|
|
4
|
+
|
|
5
|
+
## In-process event-bus RPC
|
|
6
|
+
|
|
7
|
+
Other Pi extensions can use the in-process event-bus RPC instead of scraping slash output or calling internal modules. Listen for `subagents:rpc:v1:ready`, send requests on `subagents:rpc:v1:request`, and read replies from `subagents:rpc:v1:reply:<requestId>`.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
const requestId = crypto.randomUUID();
|
|
11
|
+
pi.events.on(`subagents:rpc:v1:reply:${requestId}`, (reply) => {
|
|
12
|
+
// { version: 1, requestId, success: true, data } or
|
|
13
|
+
// { version: 1, requestId, success: false, error: { code, message } }
|
|
14
|
+
});
|
|
15
|
+
pi.events.emit("subagents:rpc:v1:request", {
|
|
16
|
+
version: 1,
|
|
17
|
+
requestId,
|
|
18
|
+
method: "spawn",
|
|
19
|
+
params: {
|
|
20
|
+
workflowScript: `return runs.run("main", { agent: "reviewer", task: "Review the current diff" })`,
|
|
21
|
+
context: "fresh"
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The RPC methods are `ping`, `status`, `spawn`, `steer`, `interrupt`, `stop`, and `resume`. `status`, `steer`, `interrupt`, and `resume` reuse the normal package-owned actions.
|
|
27
|
+
|
|
28
|
+
Method notes:
|
|
29
|
+
|
|
30
|
+
- `spawn` requires `workflowScript` and is async-only: omit `async` or set `async: true`, omit `clarify`, and do not pass management `action` values. It goes through the same executor as the `subagent` tool, so agent discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status all behave the same.
|
|
31
|
+
- `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.
|
|
32
|
+
- `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.
|
|
33
|
+
- `stop` targets current-session top-level async runs through the stop control channel and records a `stopped` lifecycle instead of reporting a timeout.
|
|
34
|
+
|
|
35
|
+
Capability advertisements on `ping`:
|
|
36
|
+
|
|
37
|
+
- `events.asyncComplete` — exact process-local completion correlation after RPC `spawn`.
|
|
38
|
+
- `launchResolvedExtensions` — the optional launch-resolved extension projection in status details.
|
|
39
|
+
- `runtimeAcknowledgedExtensions` — the optional child-runtime acknowledgement projection and event name.
|
|
40
|
+
- `processTerminalProof` — the process-terminal proof status (see [observability.md](observability.md#process-terminal-proof)).
|
|
41
|
+
- `nonRecoveringSteer` — RPC steering never pauses-and-revives.
|
|
42
|
+
- `resume` — the revival seam described above.
|
|
43
|
+
- `fleetStatus: { version: 1 }` — successful `status` replies additionally include `data.fleet`.
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
### Fleet status DTO
|
|
48
|
+
|
|
49
|
+
When `ping.capabilities.fleetStatus` is `{ version: 1 }`, successful `status` replies include `data.fleet`: `{ version: 1, entries, totalActive, omitted }`.
|
|
50
|
+
|
|
51
|
+
Entries are bounded, current-session public display records with an opaque reconciliation `key`, resolved `agent`, optional `role`, `model`, `effort`, caller-facing `goal`, safe `startedAt`, and `{ input, output, total }` tokens. `totalActive` and `omitted` preserve overflow information beyond the bounded entry window.
|
|
52
|
+
|
|
53
|
+
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.
|
|
54
|
+
|
|
55
|
+
### Scope
|
|
56
|
+
|
|
57
|
+
`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.
|
|
58
|
+
|
|
59
|
+
## Launch contract preflight
|
|
60
|
+
|
|
61
|
+
Use `pi-subagents/preflight` when an extension needs to inspect the resolved child launch contract before deciding whether to run anything:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { resolveSubagentLaunchContract } from "pi-subagents/preflight";
|
|
65
|
+
|
|
66
|
+
const result = await resolveSubagentLaunchContract({
|
|
67
|
+
agent: "reviewer",
|
|
68
|
+
task: "Review the current diff.",
|
|
69
|
+
context: "fresh",
|
|
70
|
+
cwd: ctx.cwd,
|
|
71
|
+
sessionRoot: "/tmp/my-extension-preflight-session-root",
|
|
72
|
+
availableModels: ctx.modelRegistry.getAvailable(),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!result.ok) {
|
|
76
|
+
// missing_agent, ambiguous_agent, missing_skill, denied_required_tool,
|
|
77
|
+
// invalid_artifact_dir, invalid_cwd, or unsupported_mode
|
|
78
|
+
throw new Error(result.message);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(result.contract.digest, result.contract.tools.effectiveAllowlist);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Preflight covers ordinary single-agent launch resolution:
|
|
85
|
+
|
|
86
|
+
- Selected agent identity and shadowed candidates.
|
|
87
|
+
- A parsed-definition digest, including system prompt and launch-affecting model, tool, skill, extension, output, and memory fields.
|
|
88
|
+
- Fresh/fork context, effective model and thinking, skill and tool resolution, direct MCP selections, runtime/configured extensions.
|
|
89
|
+
- Artifact/session paths, async lifecycle/status/result/event/process-terminal paths, package/lifecycle versions, capability-ceiling audit data, and stable digests.
|
|
90
|
+
|
|
91
|
+
`launchContractDigest` is the canonical digest of the caller task, effective system prompt (including the resolved `turnBudget` prompt augmentation when supplied), model candidates, effective tools/extensions/MCP (including inherited capability ceilings), output binding, and structured-output schema that ordinary foreground and async execution report in results/status/events and metadata.
|
|
92
|
+
|
|
93
|
+
Boundaries:
|
|
94
|
+
|
|
95
|
+
- Runtime acceptance prose and output-task annotations are intentionally excluded because side-effect-free preflight does not resolve those host/runtime augmentations; the launch and task digests make that boundary explicit.
|
|
96
|
+
- Raw prompts are not exposed in public contract output.
|
|
97
|
+
- It is side-effect-free for launch state: it does not create child sessions, temp prompt files, structured-output runtimes, tool-diagnostic files, or run artifacts.
|
|
98
|
+
- Some host-owned facts, such as exact fork snapshots, nested async roots, and live model registries, can only be proven by the Pi host; those appear as `host_required` diagnostics instead of silently pretending to be exact.
|
|
99
|
+
|
|
100
|
+
## Structured delegation API
|
|
101
|
+
|
|
102
|
+
Other Pi extensions can ask `pi-subagents` to run one configured foreground leaf agent through the structured delegation API. It uses the established `prompt-template:subagent:*` event family and the same executor as the `subagent` tool; it does not add another launcher.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import {
|
|
106
|
+
SUBAGENT_DELEGATION_REQUEST_EVENT,
|
|
107
|
+
SUBAGENT_DELEGATION_RESPONSE_EVENT,
|
|
108
|
+
type SubagentDelegationRequest,
|
|
109
|
+
type SubagentDelegationResponse,
|
|
110
|
+
} from "pi-subagents/delegation";
|
|
111
|
+
|
|
112
|
+
const request: SubagentDelegationRequest = {
|
|
113
|
+
requestId: crypto.randomUUID(),
|
|
114
|
+
ownerRunId: workflowRunId,
|
|
115
|
+
nodeId: "review-accuracy",
|
|
116
|
+
agent: "reviewer",
|
|
117
|
+
task: "Review the supplied evidence.",
|
|
118
|
+
context: "fresh",
|
|
119
|
+
cwd: ctx.cwd,
|
|
120
|
+
thinking: "high",
|
|
121
|
+
result: {
|
|
122
|
+
kind: "structured",
|
|
123
|
+
schema: {
|
|
124
|
+
type: "object",
|
|
125
|
+
properties: { verdict: { type: "string" } },
|
|
126
|
+
required: ["verdict"],
|
|
127
|
+
additionalProperties: false,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const unsubscribe = pi.events.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => {
|
|
133
|
+
const response = payload as SubagentDelegationResponse;
|
|
134
|
+
if (response.requestId !== request.requestId) return;
|
|
135
|
+
if (response.ownerRunId !== request.ownerRunId || response.nodeId !== request.nodeId) return;
|
|
136
|
+
unsubscribe();
|
|
137
|
+
// Inspect response.status, response.result, response.usage, model, and thinking.
|
|
138
|
+
});
|
|
139
|
+
pi.events.emit(SUBAGENT_DELEGATION_REQUEST_EVENT, request);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Identity:
|
|
143
|
+
|
|
144
|
+
- `ownerRunId` plus `nodeId` is the active logical identity; `requestId` identifies one attempt.
|
|
145
|
+
- A second active attempt for the same logical node receives `duplicate_node` without disturbing the original.
|
|
146
|
+
- Started, update, response, and cancellation payloads carry the full tuple. Cancellation affects only an exact tuple, including cancel-before-start races.
|
|
147
|
+
- Each attempt emits at most one terminal response.
|
|
148
|
+
|
|
149
|
+
Results:
|
|
150
|
+
|
|
151
|
+
- Result mode is explicit. Text remains literal even when it looks like JSON. Structured mode returns the separately captured, schema-validated JSON value.
|
|
152
|
+
- Terminal usage reports input, output, cache-read, cache-write, cost, turns, tool calls, and duration alongside the effective model and thinking level when known.
|
|
153
|
+
|
|
154
|
+
Bounds:
|
|
155
|
+
|
|
156
|
+
- 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.
|
|
157
|
+
- Structured delegation accepts `toolBudget: { hard: 0, block: "*" }` to block the first tool call and run a zero-tool leaf; ordinary model-facing/configured budgets keep their existing minimum of one.
|
|
158
|
+
- The foreground bridge retains up to 8,192 exact pending-cancellation and settled-attempt identities per extension context. If either history fills, it fails closed with `unavailable_context` for later starts rather than evicting identity facts; lifecycle reset clears the bounded history.
|
|
159
|
+
|
|
160
|
+
Constraints:
|
|
161
|
+
|
|
162
|
+
- Delegation requires an active extension context. Emit requests from a supported event callback or queued application step, not by recursively invoking the `subagent` tool inside another tool's `tool_call` hook.
|
|
163
|
+
- The caller selects a configured agent, but agent discovery and effective tools remain package-owned. A request cannot grant arbitrary tools, and tool restrictions are not an operating-system sandbox.
|
|
164
|
+
- The detached RPC remains async-only; this API is foreground-only.
|
|
165
|
+
|
|
166
|
+
Unversioned prompt-template payloads with `requestId`, `agent`, `task`, `context`, `model`, and `cwd` are rejected as legacy direct delegation. New integrations must use the structured owned-leaf request above. `pi-subagents/delegation` is the canonical contract for extension integrations.
|
|
167
|
+
|
|
168
|
+
## Capability ceilings
|
|
169
|
+
|
|
170
|
+
Parent extensions can enforce an out-of-band, session-scoped capability ceiling without adding a model-visible field to `subagent`:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { registerSubagentCapabilityCeiling } from "pi-subagents/capability-ceiling";
|
|
174
|
+
|
|
175
|
+
const restriction = registerSubagentCapabilityCeiling({
|
|
176
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
177
|
+
source: "plan-mode",
|
|
178
|
+
ceiling: {
|
|
179
|
+
allowedAgents: ["plan-scout", "plan-researcher", "plan-reviewer"],
|
|
180
|
+
allowedTools: ["read", "grep", "find", "ls"],
|
|
181
|
+
denyExtensions: true,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
// restriction.update(...) replaces this provider's policy atomically.
|
|
185
|
+
// restriction.dispose() removes only this provider's registration.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Semantics:
|
|
189
|
+
|
|
190
|
+
- Active registrations intersect their `allowedTools` and `allowedAgents` sets and OR `denyExtensions`.
|
|
191
|
+
- An explicit empty list means no caller-facing tools or launchable agents for that field; an omitted list does not restrict names.
|
|
192
|
+
- `allowedAgents` entries are canonical agent names and are case-sensitive.
|
|
193
|
+
- Launching a non-allowlisted agent fails before spawn, and `{ action: "list" }` keeps restricted agents visible in a separate non-executable section instead of silently hiding them.
|
|
194
|
+
- The resolved snapshot is propagated monotonically to nested and async children and is retained for recovery.
|
|
195
|
+
- `structured_output` may remain as a package-owned internal protocol tool when an output schema requires it; it is not a caller capability.
|
|
196
|
+
- A denied lazy-skill `read` requirement fails before spawn rather than widening the ceiling.
|
|
197
|
+
|
|
198
|
+
`denyExtensions` suppresses ambient, configured, and MCP provider extensions while retaining the package runtime needed for child protocol enforcement. This is a same-process policy boundary, not a sandbox against malicious code already running in the parent process.
|
|
199
|
+
|
|
200
|
+
Schedules created while a ceiling is active are rejected until durable schedule persistence is available; unrestricted schedules remain subject to any policy active when they fire. Public status exposes bounded audit counts and sources, never full extension paths.
|
|
201
|
+
|
|
202
|
+
## Background-work provider API
|
|
203
|
+
|
|
204
|
+
Other Pi extensions can make their current-session jobs visible to `subagent_wait` through the process-local provider contract:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { registerBackgroundWorkProvider } from "pi-subagents/background-work";
|
|
208
|
+
|
|
209
|
+
const dispose = registerBackgroundWorkProvider({
|
|
210
|
+
name: "my-background-extension",
|
|
211
|
+
wakeChannels: ["my-extension:job-finished"],
|
|
212
|
+
listActiveWork: () => jobs
|
|
213
|
+
.filter((job) => job.status === "running")
|
|
214
|
+
.map((job) => ({ id: job.id, sessionId: job.ownerSessionId })),
|
|
215
|
+
reconcile: ({ sessionId, nowMs }) => reconcileJobs(sessionId, nowMs),
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Semantics:
|
|
220
|
+
|
|
221
|
+
- Each item needs a stable provider-local ID and the exact Pi session ID that owns it. `subagent_wait` captures those identities rather than a count, so one job finishing while another starts still satisfies first-completion waits without losing the replacement.
|
|
222
|
+
- 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.
|
|
223
|
+
- Wake channels only shorten polling; validated snapshots remain authoritative.
|
|
224
|
+
- Providers share a registry through `Symbol.for("pi-subagents.background-work.v1")`, allowing independently loaded extension modules to meet in one Pi process.
|
|
225
|
+
- 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.
|
|
226
|
+
|
|
227
|
+
Child processes do not gain provider tools or extensions automatically. Add `subagent_wait` to the child agent's `tools` allowlist and load each provider through `extensions` or `subagentOnlyExtensions`. The parent's effective `waitTool` setting is serialized through foreground, async, resume, chain, parallel, and fanout launch paths; `PI_SUBAGENT_WAIT_TOOL_ENABLED` keeps precedence.
|
|
228
|
+
|
|
229
|
+
## Herdr integration
|
|
230
|
+
|
|
231
|
+
When Pi runs inside [Herdr](https://herdr.dev), pi-subagents automatically reports active async-run counts through Herdr pane metadata.
|
|
232
|
+
|
|
233
|
+
- The bridge is enabled only when Herdr supplies `HERDR_ENV=1` and `HERDR_PANE_ID`; outside Herdr it registers no listeners or timers.
|
|
234
|
+
- It restores current-session active runs after `/reload` or `/resume`, refreshes metadata while work is active, and clears it on completion or shutdown.
|
|
235
|
+
- The bridge uses Herdr's existing `herdr:blocked` sibling event when an async child needs attention, and emits `herdr:busy` while async work remains. Herdr versions that support the sibling event keep the pane's semantic state `working`; older versions ignore it safely and still display the metadata label while the Pi integration remains the lifecycle authority.
|
|
236
|
+
|
|
237
|
+
To show the reported label in the expanded Agent sidebar, include `state_text` or `$summary` in its row layout:
|
|
238
|
+
|
|
239
|
+
```toml
|
|
240
|
+
[ui.sidebar.agents]
|
|
241
|
+
rows = [
|
|
242
|
+
["state_icon", "workspace", "tab"],
|
|
243
|
+
["agent", "state_text"],
|
|
244
|
+
]
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Inspector panes
|
|
248
|
+
|
|
249
|
+
Herdr 0.7.5+ can open an on-demand inspector for an existing async run:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
subagent({ action: "inspector.open", id: "<run-id>", index: 0, focus: true })
|
|
253
|
+
subagent({ action: "inspector.status", id: "<run-id>", index: 0 })
|
|
254
|
+
subagent({ action: "inspector.close", id: "<run-id>", index: 0 })
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The inspector is a raw dashboard pane, not the child process and not a literal attach. It reads lifecycle/status/output/mission artifacts and sends `steer` or `stop` through pi-subagents' existing control inbox. Closing it never stops the run.
|
|
258
|
+
|
|
259
|
+
Herdr remains optional. Ordinary launches stay headless, and missing/older Herdr versions affect only Herdr-specific inspector and project-pane actions. FleetView opens the selected active async child with `H`. Use `focus` only with `inspector.open`; Herdr 0.7.5 cannot focus an arbitrary existing raw pane id.
|
|
260
|
+
|
|
261
|
+
### Project panes
|
|
262
|
+
|
|
263
|
+
For substantial work in another codebase, Herdr 0.7.5+ can open a project-owned Pi pane rooted in that repository:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
subagent({ action: "project.open", cwd: "/path/to/repo", message: "Own the auth refresh mission for this project." })
|
|
267
|
+
subagent({ action: "project.status", cwd: "/path/to/repo" })
|
|
268
|
+
subagent({ action: "project.close", cwd: "/path/to/repo" })
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
A project pane runs its own Pi session in the target directory, so subagents launched from that pane use that project's config, agents, skills, files, git state, and missions. The parent session keeps coordination authority; existing headless runs are not moved into the pane. Pane bindings live under `<projectRoot>/.pi-subagents/project-panes/herdr.json` and are only a local pointer to the Herdr pane.
|
|
272
|
+
|
|
273
|
+
Other Pi extensions should use the versioned public TypeScript surface instead of invoking the model-facing tool or importing inspector internals:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import {
|
|
277
|
+
PROJECT_PANES_API_VERSION,
|
|
278
|
+
openProjectPane,
|
|
279
|
+
getProjectPaneStatus,
|
|
280
|
+
closeProjectPane,
|
|
281
|
+
} from "pi-subagents/project-panes";
|
|
282
|
+
|
|
283
|
+
const opened = await openProjectPane({ cwd: "/path/to/repo", focus: false });
|
|
284
|
+
const status = await getProjectPaneStatus({ cwd: "/path/to/repo" });
|
|
285
|
+
const closed = await closeProjectPane({ cwd: "/path/to/repo", requireIdle: true });
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The API returns discriminated structured results with canonical project root, binding path, pane identity, bounded Herdr runtime fields, and stable error codes. `requireIdle: true` fails closed unless Herdr explicitly reports `agent_status: "idle"`; use it when an owning extension must not close a working or blocked pane. The API deliberately reports `trust: "human-verification-required"`: it never bypasses or claims to attest Pi's project-trust prompt. `PROJECT_PANES_API_VERSION` is currently `1`.
|
|
289
|
+
|
|
290
|
+
## Runtime files
|
|
291
|
+
|
|
292
|
+
The main runtime files in this repository:
|
|
293
|
+
|
|
294
|
+
| File | Purpose |
|
|
295
|
+
|------|---------|
|
|
296
|
+
| `src/extension/index.ts` | Extension registration, tool registration, message/render wiring. |
|
|
297
|
+
| `src/agents/agents.ts` | Agent and chain discovery, frontmatter parsing. |
|
|
298
|
+
| `src/runs/foreground/subagent-executor.ts` | Main execution routing for single, parallel, chain, management, status, interrupt, and doctor actions. |
|
|
299
|
+
| `src/runs/foreground/execution.ts` | Core foreground `runSync` handling. |
|
|
300
|
+
| `src/runs/background/subagent-runner.ts` | Detached async runner. |
|
|
301
|
+
| `src/runs/background/async-execution.ts` | Background launch support. |
|
|
302
|
+
| `src/runs/background/async-status.ts` | Status discovery and formatting for async runs. |
|
|
303
|
+
| `src/runs/foreground/chain-execution.ts` / `src/agents/chain-serializer.ts` | Chain orchestration and `.chain.md` parsing. |
|
|
304
|
+
| `src/shared/settings.ts` | Chain behavior, instructions, and config helpers. |
|
|
305
|
+
| `src/runs/shared/worktree.ts` | Git worktree isolation. |
|
|
306
|
+
| `src/intercom/intercom-bridge.ts` | Runtime intercom bridge instructions and diagnostics. |
|
|
307
|
+
| `src/extension/schemas.ts` / `src/shared/types.ts` | Tool schemas, shared types, and event constants. |
|
|
308
|
+
| `test/unit/` / `test/integration/` / `test/e2e/` | Unit, loader-based integration, and real-session E2E tests. |
|