pi-subagents 0.37.0 → 0.37.2
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 +29 -0
- package/README.md +18 -8
- package/agents/planner.md +2 -1
- package/package.json +3 -3
- package/skills/pi-subagents/SKILL.md +18 -989
- package/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
- package/skills/pi-subagents/references/execution-controls.md +411 -0
- package/skills/pi-subagents/references/management-authoring-rpc.md +140 -0
- package/skills/pi-subagents/references/prompting-and-roles.md +268 -0
- package/src/agents/skills.ts +14 -12
- package/src/api/delegation.ts +3 -0
- package/src/extension/index.ts +14 -7
- package/src/extension/rpc.ts +25 -2
- package/src/extension/schemas.ts +2 -2
- package/src/extension/tool-description.ts +2 -2
- package/src/intercom/intercom-bridge.ts +5 -2
- package/src/runs/background/async-job-tracker.ts +19 -12
- package/src/runs/background/async-resume.ts +6 -5
- package/src/runs/background/notify.ts +3 -0
- package/src/runs/background/result-watcher.ts +9 -3
- package/src/runs/foreground/subagent-executor.ts +111 -46
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
- package/src/runs/shared/model-fallback.ts +8 -0
- package/src/runs/shared/pi-args.ts +3 -0
- package/src/runs/shared/task-intent.ts +1 -1
- package/src/shared/types.ts +14 -1
- package/src/slash/delegation-adapters.ts +5 -0
- package/src/tui/fleet-status.ts +62 -16
- package/src/tui/fleet.ts +1 -1
- package/src/tui/render.ts +23 -26
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# Pi Subagents: Execution Controls
|
|
2
|
+
|
|
3
|
+
This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
|
|
4
|
+
|
|
5
|
+
## Discovery and Scope Rules
|
|
6
|
+
|
|
7
|
+
Agent files can live in:
|
|
8
|
+
- `~/.pi/agent/agents/**/*.md` — user scope
|
|
9
|
+
- `.pi/agents/**/*.md` — canonical project scope
|
|
10
|
+
- legacy `.agents/**/*.md` — still read for compatibility, but `.pi/agents/` wins on conflicts
|
|
11
|
+
|
|
12
|
+
Chains live in:
|
|
13
|
+
- `~/.pi/agent/chains/**/*.chain.md` and `~/.pi/agent/chains/**/*.chain.json` — user scope
|
|
14
|
+
- `.pi/chains/**/*.chain.md` and `.pi/chains/**/*.chain.json` — project scope
|
|
15
|
+
|
|
16
|
+
Discovery is recursive. `.chain.md` files do not define agents. Use `.chain.md` for simple saved chains and `.chain.json` for dynamic fanout or inline schema objects. Agents and chains can set optional frontmatter/package metadata; `name: scout` plus `package: code-analysis` registers as runtime name `code-analysis.scout` while serialization keeps `name` and `package` separate.
|
|
17
|
+
|
|
18
|
+
Precedence is by parsed runtime name:
|
|
19
|
+
1. project scope
|
|
20
|
+
2. user scope
|
|
21
|
+
3. builtin agents
|
|
22
|
+
|
|
23
|
+
## Running Subagents
|
|
24
|
+
|
|
25
|
+
### Single agent
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
subagent({
|
|
29
|
+
agent: "oracle",
|
|
30
|
+
task: "Review my current direction and challenge assumptions."
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Forked context
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
subagent({
|
|
38
|
+
agent: "oracle",
|
|
39
|
+
task: "Review my current direction and challenge assumptions.",
|
|
40
|
+
context: "fork"
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`context: "fork"` creates a branched child session from the current persisted
|
|
45
|
+
parent session. It does **not** create a fresh minimal review context or filter
|
|
46
|
+
history down to only the relevant parts. Use it when you want a separate review
|
|
47
|
+
or execution thread that can still reference the parent session history.
|
|
48
|
+
|
|
49
|
+
Foreground results, async status, fleet, and widget surfaces label each child with
|
|
50
|
+
its resolved launch context as `[fresh]` or `[fork]`. Aggregate headers show
|
|
51
|
+
`[mixed]` when a run uses both modes.
|
|
52
|
+
|
|
53
|
+
### Parallel execution
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
subagent({
|
|
57
|
+
tasks: [
|
|
58
|
+
{ agent: "scout", task: "Explore the auth module" },
|
|
59
|
+
{ agent: "reviewer", task: "Review the API client" }
|
|
60
|
+
]
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Top-level parallel tasks can override per-task behavior:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
subagent({
|
|
68
|
+
tasks: [
|
|
69
|
+
{ agent: "scout", task: "Map auth", output: "auth-context.md", progress: true },
|
|
70
|
+
{ agent: "researcher", task: "Research OAuth best practices", output: "oauth-research.md" },
|
|
71
|
+
{ agent: "reviewer", task: "Review auth tests", model: "anthropic/claude-sonnet-4" }
|
|
72
|
+
],
|
|
73
|
+
concurrency: 3
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Repeat one parallel task N times with the same settings via `count` (useful for identical scouts or review angles without hand-duplicating entries):
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
subagent({
|
|
81
|
+
tasks: [
|
|
82
|
+
{ agent: "scout", task: "Map a distinct slice of the auth surface and return compressed context.", count: 3 }
|
|
83
|
+
],
|
|
84
|
+
concurrency: 3,
|
|
85
|
+
context: "fresh"
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Avoid duplicate output paths in parallel tasks. Concurrent children should not write to the same file. For large saved outputs, set `outputMode: "file-only"` together with an `output` path. The parent result then contains only a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` instead of the full saved content. Do not use `output: false` for this; `output: false` means no file output. In chains, relative `output` paths are chain-artifact paths under `{chain_dir}`, not project CWD paths; use an absolute `output` path or a persistent `chainDir` when a saved artifact must outlive the temp chain directory. Read-only children return the complete artifact in their final response and the runtime persists it, so missing write tools are not a supervisor blocker. Mutation-capable children still receive direct-write instructions. Failed runs and save errors still return inline details for debugging.
|
|
90
|
+
|
|
91
|
+
### Chain execution
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
subagent({
|
|
95
|
+
chain: [
|
|
96
|
+
{ agent: "scout", task: "Map the auth flow and summarize key files" },
|
|
97
|
+
{ agent: "planner", task: "Create an implementation plan from {previous}" },
|
|
98
|
+
{ agent: "worker", task: "Implement the approved plan based on {previous}" }
|
|
99
|
+
]
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Chain steps can use templated variables such as `{task}`, `{previous}`,
|
|
104
|
+
`{chain_dir}`, and `{outputs.name}`. Use `as: "name"` on a successful step or
|
|
105
|
+
parallel task to make that output available to later steps. Prefer named outputs
|
|
106
|
+
when a later step needs one specific result; keep `{previous}` for simple linear
|
|
107
|
+
handoffs or full fan-in summaries. Use `phase` and `label` for status readability.
|
|
108
|
+
Use `outputSchema` when later steps need reliable structured data; the child must
|
|
109
|
+
call `structured_output` with schema-valid JSON, or the step fails.
|
|
110
|
+
|
|
111
|
+
Use `agentContract: { version: 1 }` when a caller needs generic result projections
|
|
112
|
+
instead of acceptance or mutation effects rewriting execution success. V1 adds
|
|
113
|
+
`execution`, `acceptance`, `review`, and `effects`; omitted acceptance means no
|
|
114
|
+
acceptance request. Chain steps advance on execution by default under v1. Set
|
|
115
|
+
`gateOn: "acceptance"` only when a rejected explicit acceptance report should stop
|
|
116
|
+
the chain.
|
|
117
|
+
|
|
118
|
+
### Async/background
|
|
119
|
+
|
|
120
|
+
Prefer async mode for every subagent launch. Set `async: true` no matter the task unless there is a specific reason to opt into a foreground/blocking run. This applies to scouts, researchers, workers, reviewers, validators, oracle checks, one-off delegates, chains, and parallel groups. Keep the write path single-threaded even when the run is async.
|
|
121
|
+
|
|
122
|
+
Async does not mean parallel writes. Do not edit the same active worktree while an async worker is changing it. Parent-side overlap should be reading, validation prep, synthesis, command planning, or review of unaffected context unless the writer is isolated in a separate worktree.
|
|
123
|
+
|
|
124
|
+
Do not end your turn immediately after launching an async child if you promised to keep working. Continue the local inspection, synthesis, or validation prep, then check the async run when its result is needed.
|
|
125
|
+
|
|
126
|
+
In an interactive chat, normally return control when ready to yield and let Pi wake the session on completion; do not call `subagent_wait()` merely to wait. Override that default and call it when the current request is run-to-completion — for example, the user asked you to report results back before continuing or a skill cannot return before its background work finishes. Headless sessions auto-drain exact current-session work at `agent_end`; call `subagent_wait()` when this turn must receive results before it ends. Never substitute sleep or status-polling loops.
|
|
127
|
+
|
|
128
|
+
`subagent_wait()` returns when the next initially active async run or registered provider item finishes or a subagent needs attention. Use `subagent_wait({ all: true })` for all work active at call time, `subagent_wait({ id: "..." })` for one async or remembered detached foreground run, and `subagent_wait({ timeoutMs })` to cap the block. If a foreground child detaches for supervisor coordination, reply first, then wait on its id; do not resume or launch a replacement while it remains detached. Headless sessions also auto-drain exact current-session work at `agent_end` as a final safeguard.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
subagent({
|
|
132
|
+
agent: "worker",
|
|
133
|
+
task: "Run the full test suite",
|
|
134
|
+
async: true
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
File-only output mode also works for async single runs, top-level parallel task items, sequential chain steps, and chain parallel task items. In chains, `{previous}` receives the compact saved-file reference when the prior step used file-only mode. Relative chain output paths are resolved under `{chain_dir}`; pass a persistent `chainDir` or an absolute `output` path when a later human or process needs a stable path outside the temp chain run.
|
|
139
|
+
|
|
140
|
+
For review fanout where the parent continues a local audit:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const run = subagent({
|
|
144
|
+
agent: "reviewer",
|
|
145
|
+
task: "Review the current diff for correctness issues. Do not edit files.",
|
|
146
|
+
async: true,
|
|
147
|
+
context: "fresh"
|
|
148
|
+
})
|
|
149
|
+
// Continue local inspection, then later call status with the returned id.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Inspect async runs with `subagent({ action: "status", id: "..." })` or `subagent({ action: "status" })` for active runs. Use `subagent({ action: "status", view: "fleet" })` when supervising several active foreground/background runs and `subagent({ action: "status", id: "...", view: "transcript", index: 0 })` when you need the latest child output without digging through artifacts. If a delegated fanout child launches nested runs, the parent status view shows them as a tree and you can target a nested run directly with its nested id.
|
|
153
|
+
|
|
154
|
+
Stop a current-session top-level async run with `stop` (or `/subagents-stop`). Stopped runs finish as `stopped`/cancelled and are not resumable. Append one more step to the tail of a still-running async chain with `append-step` (`chain` must contain exactly one step):
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
subagent({ action: "stop", id: "run-id" })
|
|
158
|
+
subagent({
|
|
159
|
+
action: "append-step",
|
|
160
|
+
id: "run-id",
|
|
161
|
+
chain: [{ agent: "reviewer", task: "Re-check the worker diff after the fix pass. Do not modify files." }]
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Use `steer` for top-level live async guidance and `resume` after a delegated run pauses or finishes. Routed nested runs retain their existing non-destructive live follow-up path:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
subagent({ action: "steer", id: "run-id", message: "Focus on the failing test." })
|
|
169
|
+
subagent({ action: "resume", id: "run-id", message: "Follow up on this point." })
|
|
170
|
+
subagent({ action: "resume", id: "run-id", index: 1, message: "Continue reviewer 2." })
|
|
171
|
+
subagent({ action: "resume", id: "nested-run-id", message: "Continue this nested reviewer." })
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Resume behavior:
|
|
175
|
+
- `resume` revives paused, completed, or failed async/foreground children from persisted session files; stopped runs remain non-resumable, and it does not interrupt live top-level async children.
|
|
176
|
+
- Use `steer` for acknowledged guidance to a live top-level async child.
|
|
177
|
+
- A live nested run can still receive a non-destructive `resume` follow-up through its owner route.
|
|
178
|
+
- If an async child has completed, `resume` revives it by starting a new async child from the persisted child session file.
|
|
179
|
+
- Multi-child async runs require `index` unless only one running child is selectable.
|
|
180
|
+
- Completed foreground single, parallel, and chain runs can also be revived by `index` while their run metadata remains in extension state.
|
|
181
|
+
- Nested runs can be resumed by nested id when a live route or persisted nested session metadata is available.
|
|
182
|
+
- Revive starts a new child process from the old session context; it does not restart the same OS process.
|
|
183
|
+
- Direct revival holds an exclusive cross-process lease on the canonical child session file until the new child finishes. Concurrent attempts fail before Pi starts and identify the owning revived run; stale ownership is reclaimed only when the recorded process is demonstrably gone or reused.
|
|
184
|
+
- If the chosen child has no persisted `.jsonl` session file, resume fails and reports that directly.
|
|
185
|
+
|
|
186
|
+
Use diagnostics when setup or child startup looks wrong:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
subagent({ action: "doctor" })
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Scheduled subagent runs
|
|
193
|
+
|
|
194
|
+
Scheduled runs defer a subagent launch until a future time. They are opt-in and require `{ "scheduledRuns": { "enabled": true } }` in `~/.pi/agent/extensions/subagent/config.json`. Only schedule explicit delayed runs the user asked for; do not schedule runs speculatively.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Launch a reviewer in 30 minutes
|
|
198
|
+
subagent({ action: "schedule", agent: "reviewer", task: "Review the diff for correctness issues.", schedule: "+30m", scheduleName: "evening review" })
|
|
199
|
+
|
|
200
|
+
// Schedule a parallel fanout
|
|
201
|
+
subagent({ action: "schedule", tasks: [{ agent: "scout", task: "Map the auth module" }, { agent: "scout", task: "Map the billing module" }], schedule: "+1h" })
|
|
202
|
+
|
|
203
|
+
// Inspect, list, and cancel
|
|
204
|
+
subagent({ action: "schedule-list" })
|
|
205
|
+
subagent({ action: "schedule-status", id: "ab12" })
|
|
206
|
+
subagent({ action: "schedule-cancel", id: "ab12" })
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`schedule` accepts the same execution fields as a normal async run (`agent`/`tasks`/`chain`, `cwd`, `model`, `output`, `reads`, `progress`, `acceptance`, `timeoutMs` / `maxRuntimeMs`) plus `schedule` (a relative delay like `+10m`/`+2h`/`+1d` or a future ISO timestamp with a timezone such as `2030-01-01T09:00:00Z`) and an optional `scheduleName`. Scheduled runs always launch async with fresh context; `context: "fork"`, `async: false`, and `clarify: true` are rejected. Once the timer fires, the run becomes a normal tracked async run: it appears in the async widget, is inspectable with `subagent({ action: "status" })`, can be awaited with `subagent_wait()`, and delivers the normal completion notification.
|
|
210
|
+
|
|
211
|
+
Schedules are persisted per session and restored after a Pi restart. A job whose scheduled time passed by more than `scheduledRuns.maxLatenessMs` (default 5 minutes) while Pi was unavailable is marked `missed` instead of firing late. `scheduledRuns.maxPending` (default 20) caps pending or running scheduled jobs per session.
|
|
212
|
+
|
|
213
|
+
Humans can use `/subagents-doctor` for the same read-only report. It checks runtime paths, discovery counts, async support, current session context, and intercom bridge state.
|
|
214
|
+
|
|
215
|
+
### Subagent control
|
|
216
|
+
|
|
217
|
+
Subagent control is the runtime visibility and intervention layer for delegated runs. It is separate from lifecycle status. Lifecycle status says whether a child is `queued`, `running`, `paused`, `complete`, `stopped`, or `failed`. Activity reporting is factual: it tracks the last observed activity time and the current tool when known. It does not pretend to know that a child is truly stuck. Manual top-level async cancellation uses `stop` / `/subagents-stop`; a live async chain can gain one more tail step via `append-step`.
|
|
218
|
+
|
|
219
|
+
Default behavior is intentionally conservative. When no activity has been observed past the configured threshold, the run emits a `needs_attention` control event. Foreground runs can push this as a `subagent:control-event` event, and async runs persist it to `events.jsonl` so the parent tracker can surface it without constant manual polling. Notification-worthy control events are also inserted into the visible transcript so both the user and the parent agent can see them, with a proactive hint plus concrete `nudge`, `status`, and `interrupt` options. Visible notifications fire once per child run and attention state.
|
|
220
|
+
|
|
221
|
+
Use soft interrupt when a child is clearly blocked or drifting and the parent needs to regain control:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
subagent({ action: "interrupt" })
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Pass `id` when targeting a specific controllable run, including a nested run shown in the parent status tree:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
subagent({ action: "interrupt", id: "abc123" })
|
|
231
|
+
subagent({ action: "interrupt", id: "nested-run-id" })
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
A soft interrupt cancels the current child turn and leaves the run paused. It does not mean the delegated task succeeded or failed. Bare `interrupt` does not target hidden nested descendants; use the explicit nested id. After an interrupt, decide the next explicit action: resume with clearer instructions, replace the task, ask the user, or stop the workflow.
|
|
235
|
+
|
|
236
|
+
Per-run control thresholds can be overridden when a task legitimately runs without observable output for longer than usual:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
subagent({
|
|
240
|
+
agent: "worker",
|
|
241
|
+
task: "Run the slow migration test suite",
|
|
242
|
+
control: {
|
|
243
|
+
needsAttentionAfterMs: 300000,
|
|
244
|
+
notifyOn: ["needs_attention"]
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If the run already has an active intercom bridge target, needs-attention notifications can also prepare a compact intercom ping for the orchestrator. When a child route is available, the ping tells the orchestrator which agent needs attention and includes the exact `intercom({ action: "send", to: "..." })` target for a nudge. Do not invent a target or ask the child to self-report when no bridge exists.
|
|
250
|
+
|
|
251
|
+
Steering is acknowledged delivery, not a send attempt or model-compliance signal:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
subagent({ action: "steer", id: "abc123", message: "Focus on the failing test." })
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The action waits up to three seconds for the child Pi session to accept the correlated user input and returns a request id with `delivered`, `scheduled`, `pending`, `partial`, `recovered`, or `failed` plus per-child states. Indexed pending children return `scheduled` immediately. Only a top-level single-child run may automatically interrupt after a missed acknowledgment and recover after confirmed pause within a further 15 seconds. Recovery preserves the original child contract and only its remaining deadline, turn, and tool budgets. If the session is missing, a budget is exhausted, the pause cannot be confirmed, or replacement launch fails, the source remains paused when pausing succeeded and the action returns the exact failure. Chain, parallel, and nested runs never auto-interrupt; inspect their per-child outcomes and handle failures explicitly. A late acknowledgment is recorded and cannot cancel committed recovery.
|
|
258
|
+
|
|
259
|
+
## Watchdog
|
|
260
|
+
|
|
261
|
+
The subagent watchdog is an **opt-in** adversarial change reviewer. It is not the
|
|
262
|
+
`reviewer` subagent and is not configured by `subagents.defaultModel` or
|
|
263
|
+
`agentOverrides.reviewer`.
|
|
264
|
+
|
|
265
|
+
When enabled, it reviews actual repo edits at safe `agent_end` boundaries only if
|
|
266
|
+
the final worktree state changed during that turn. Unchanged or reverted diffs and
|
|
267
|
+
generated `.pi-subagents/` / temp artifacts do not trigger review. Writing children
|
|
268
|
+
can review their own worktree; the parent can still review the aggregate diff after
|
|
269
|
+
child changes land. Enabled watchdogs also run changed-file TypeScript/JavaScript
|
|
270
|
+
LSP diagnostics before the model pass when `typescript-language-server` is available.
|
|
271
|
+
|
|
272
|
+
Prefer a strong complementary model (for example Opus 4.8 high paired against a
|
|
273
|
+
GPT 5.5 main session, or the reverse). Recommendation and configuration:
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
/subagents-watchdog recommend-model
|
|
277
|
+
/subagents-watchdog session model recommended
|
|
278
|
+
/subagents-watchdog on
|
|
279
|
+
/subagents-watchdog status
|
|
280
|
+
/subagents-watchdog check
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
subagent({ action: "watchdog.status" })
|
|
285
|
+
subagent({ action: "watchdog.recommend-model" })
|
|
286
|
+
subagent({ action: "watchdog.configure", model: "recommended", scope: "session" })
|
|
287
|
+
subagent({ action: "watchdog.check" })
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`session` scope is temporary. Persistent `user`/`project` scopes write settings only
|
|
291
|
+
when the user asked. Use ordinary fresh-context `reviewer` fanout for planned review
|
|
292
|
+
waves; enable the watchdog when you want an automatic second pass on real edits.
|
|
293
|
+
|
|
294
|
+
## Clarify TUI
|
|
295
|
+
|
|
296
|
+
Single and parallel runs support a clarification TUI when you want to preview or
|
|
297
|
+
edit parameters before launch:
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
subagent({
|
|
301
|
+
agent: "worker",
|
|
302
|
+
task: "Implement feature X",
|
|
303
|
+
clarify: true
|
|
304
|
+
})
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Tool calls launch directly by default. Set `clarify: true` on single, parallel, or chain runs when you want the clarify UI. Clarify edits affect only the next run; use management actions, settings, or markdown files for persistent changes.
|
|
308
|
+
For programmatic background launches, use `async: true`. `clarify: true` keeps the run foreground for the clarify UI.
|
|
309
|
+
|
|
310
|
+
## Worktree Isolation
|
|
311
|
+
|
|
312
|
+
When multiple agents might write concurrently, use worktrees instead of letting
|
|
313
|
+
them share one filesystem view.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
subagent({
|
|
317
|
+
tasks: [
|
|
318
|
+
{ agent: "worker", task: "Implement feature A" },
|
|
319
|
+
{ agent: "worker", task: "Implement feature B" }
|
|
320
|
+
],
|
|
321
|
+
worktree: true
|
|
322
|
+
})
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`worktree: true` gives each parallel task its own git worktree branched from
|
|
326
|
+
HEAD. This requires a clean git state and is mainly for intentionally parallel
|
|
327
|
+
write workflows. On completion, use the versioned aggregate handoff at
|
|
328
|
+
`parallelHandoff.path` from foreground details or async status/results instead of scraping the combined
|
|
329
|
+
text. Its versioned manifest records child status and output references, full
|
|
330
|
+
patch paths and stats, and whether each temporary worktree and branch was
|
|
331
|
+
removed. If you want one writer thread and several advisory agents, prefer a
|
|
332
|
+
single-writer pattern instead.
|
|
333
|
+
|
|
334
|
+
## The Oracle Workflow
|
|
335
|
+
|
|
336
|
+
The intended oracle loop is:
|
|
337
|
+
1. the main agent forks to `oracle`
|
|
338
|
+
2. `oracle` reviews direction, drift, assumptions, and risks
|
|
339
|
+
3. `oracle` can coordinate back through `contact_supervisor` when the bridge injects it
|
|
340
|
+
4. the main agent decides what direction to approve
|
|
341
|
+
5. only then should `worker` implement
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// Advisory review in a branched thread. Oracle defaults to forked context.
|
|
345
|
+
subagent({
|
|
346
|
+
agent: "oracle",
|
|
347
|
+
task: "Review my current direction, challenge assumptions, and propose the best next move."
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
// Implementation only after explicit approval. Worker defaults to forked context.
|
|
351
|
+
subagent({
|
|
352
|
+
agent: "worker",
|
|
353
|
+
task: "Implement the approved approach: ..."
|
|
354
|
+
})
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
`oracle` is not a fresh-context reviewer in the Cognition article sense. It is
|
|
358
|
+
a forked advisory thread that inherits the parent session history and uses that
|
|
359
|
+
history as a baseline contract.
|
|
360
|
+
|
|
361
|
+
Use `oracle` as a smart-friend escalation when the parent needs help with trajectory rather than diff inspection: architectural boundaries, model capability routing, merge conflicts, reviewer disagreement, context drift after long work, a worker about to invent a pattern, or fixes that require product/scope tradeoffs. Ask broad questions when the right concern is unclear, and let `oracle` point out missing context or files the parent should inspect before asking again. Keep `oracle` advisory unless it has been explicitly assigned the single writer role.
|
|
362
|
+
|
|
363
|
+
## Subagent + Intercom Coordination
|
|
364
|
+
|
|
365
|
+
`pi-subagents` includes native supervisor coordination. Child agents can use `contact_supervisor` to ask the exact parent session that spawned them; messages are scoped by parent session id and should not appear in other Pi sessions.
|
|
366
|
+
|
|
367
|
+
Most agents should not call generic `intercom` directly unless bridge instructions provide a target and `contact_supervisor` is unavailable. Do not invent a target. Prefer the tool from the injected bridge instructions.
|
|
368
|
+
|
|
369
|
+
Use `contact_supervisor` with `reason: "need_decision"` when:
|
|
370
|
+
- a subagent is blocked on a decision
|
|
371
|
+
- a child needs clarification instead of guessing
|
|
372
|
+
- an approval, product, API, or scope choice is required before continuing safely
|
|
373
|
+
|
|
374
|
+
Use `contact_supervisor` with `reason: "interview_request"` when the child needs structured supervisor input rather than a freeform answer. The request waits for a parent reply, so the child should stay alive and continue only after the reply arrives.
|
|
375
|
+
|
|
376
|
+
Do not use `contact_supervisor` just to resolve review-only/no-project-edit versus progress-writing or output-artifact instructions. The child must not modify project/source files, but returning findings through its normal response or configured output artifact is allowed unless the parent explicitly set `output: false`.
|
|
377
|
+
|
|
378
|
+
Use `contact_supervisor` with `reason: "progress_update"` when:
|
|
379
|
+
- a child is explicitly asked for progress
|
|
380
|
+
- a meaningful discovery changes the plan
|
|
381
|
+
- a long-running child needs to report a blocked/progress checkpoint without waiting for normal tool return flow
|
|
382
|
+
|
|
383
|
+
Message conventions:
|
|
384
|
+
- `reason: "need_decision"` and `reason: "interview_request"` wait for the parent reply and return it to the child.
|
|
385
|
+
- `reason: "progress_update"` is non-blocking and should stay concise.
|
|
386
|
+
- Child-side routine completion handoffs are not expected. Native supervisor messages are for decisions, structured input, and meaningful progress updates while a child is still running.
|
|
387
|
+
|
|
388
|
+
If bridge instructions provide the child-facing tool, a child can ask:
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
contact_supervisor({
|
|
392
|
+
reason: "need_decision",
|
|
393
|
+
message: "Should I optimize for readability or performance here?"
|
|
394
|
+
})
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
The parent replies with the native supervisor tool:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
subagent_supervisor({ action: "reply", message: "Optimize for readability." })
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Or inspects unresolved asks first:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
subagent_supervisor({ action: "pending" })
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
If no external `pi-intercom` tool owns the `intercom` name, native supervisor coordination may also expose `intercom` as a compatibility fallback. Prefer `subagent_supervisor` for parent replies because it never overrides installed `pi-intercom`.
|
|
410
|
+
|
|
411
|
+
If intercom messages do not show up, run `subagent({ action: "doctor" })` or `/subagents-doctor`.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Pi Subagents: Management Authoring Rpc
|
|
2
|
+
|
|
3
|
+
This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
|
|
4
|
+
|
|
5
|
+
## Management Mode
|
|
6
|
+
|
|
7
|
+
The `subagent(...)` tool also supports management actions.
|
|
8
|
+
|
|
9
|
+
### List available agents and chains
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
subagent({ action: "list" })
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Create an agent
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
subagent({
|
|
19
|
+
action: "create",
|
|
20
|
+
config: {
|
|
21
|
+
name: "my-agent",
|
|
22
|
+
package: "code-analysis",
|
|
23
|
+
description: "Project-specific implementation helper",
|
|
24
|
+
systemPrompt: "Your system prompt here.",
|
|
25
|
+
systemPromptMode: "replace",
|
|
26
|
+
model: "openai-codex/gpt-5.4",
|
|
27
|
+
tools: "read,grep,find,ls,bash"
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Update an agent
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
subagent({
|
|
36
|
+
action: "update",
|
|
37
|
+
agent: "code-analysis.my-agent",
|
|
38
|
+
config: {
|
|
39
|
+
thinking: "high"
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Delete an agent
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
subagent({ action: "delete", agent: "code-analysis.my-agent" })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Eject, disable, enable, and reset
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// Copy a bundled builtin/package agent to user scope as an editable custom file.
|
|
54
|
+
subagent({ action: "eject", agent: "reviewer" })
|
|
55
|
+
subagent({ action: "eject", agent: "reviewer", agentScope: "project" })
|
|
56
|
+
|
|
57
|
+
// Hide an agent from runtime discovery without deleting it (reversible).
|
|
58
|
+
subagent({ action: "disable", agent: "reviewer" })
|
|
59
|
+
subagent({ action: "enable", agent: "reviewer", agentScope: "project" })
|
|
60
|
+
|
|
61
|
+
// Delete the scope's custom agent file and/or settings override, restoring the bundled default.
|
|
62
|
+
subagent({ action: "reset", agent: "reviewer" })
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`eject` copies a builtin or package agent verbatim into the user (default) or project agent dir so it can be customized without hunting package files; the copy shadows the original by runtime name. `disable` writes a reversible `agentOverrides.<name>.disabled: true` entry to the user or project settings file. `enable` removes that `disabled` field while keeping any other override fields. `reset` removes the scope's custom file and settings override to restore the bundled default, and refuses if no bundled default exists (use `delete` for purely custom agents). All four take optional `agentScope: "user" | "project"`; project overrides win over user ones, so target the project scope to undo a project-scope disable.
|
|
66
|
+
|
|
67
|
+
Use management actions when the system needs to create or edit subagents on
|
|
68
|
+
demand without dropping into raw file editing.
|
|
69
|
+
|
|
70
|
+
Management actions create or update user/project agent files. `config.name` is the local frontmatter name; optional `config.package` registers and looks up the runtime name as `{package}.{name}`. Use the dotted runtime name for `get`, `update`, `delete`, slash commands, and chain steps. For small builtin changes such as a model swap, prefer `subagents.agentOverrides` in settings.
|
|
71
|
+
|
|
72
|
+
## Creating and Editing Agents by File
|
|
73
|
+
|
|
74
|
+
A minimal agent file looks like this:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
---
|
|
78
|
+
name: my-agent
|
|
79
|
+
package: code-analysis
|
|
80
|
+
description: What this agent does
|
|
81
|
+
model: openai-codex/gpt-5.4
|
|
82
|
+
thinking: high
|
|
83
|
+
tools: read, grep, find, ls, bash
|
|
84
|
+
systemPromptMode: replace
|
|
85
|
+
inheritProjectContext: true
|
|
86
|
+
inheritSkills: false
|
|
87
|
+
skills: safe-bash, review-checklist
|
|
88
|
+
skillPath: ./skills, ../shared-skills
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
Your system prompt here.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
That is only a starting point. Omit `package` for the traditional unqualified runtime name. Common optional fields include:
|
|
95
|
+
- `defaultProgress`
|
|
96
|
+
- `defaultReads`
|
|
97
|
+
- `output`
|
|
98
|
+
- `fallbackModels`
|
|
99
|
+
- `subagentOnlyExtensions`
|
|
100
|
+
- `skills`
|
|
101
|
+
- `skillPath`
|
|
102
|
+
- `memory`
|
|
103
|
+
- `maxSubagentDepth`
|
|
104
|
+
- `acceptance`
|
|
105
|
+
- `acceptanceRole`
|
|
106
|
+
- `async` — single-agent default for background launch (`true`/`false`); explicit tool-call `async` wins
|
|
107
|
+
- `timeoutMs` — single-agent default run-level max runtime in ms; foreground calls use a 30-minute package default only when neither the call nor agent provides one (tool alias `maxRuntimeMs` is also accepted)
|
|
108
|
+
- `turnBudget` — single-agent default `{ maxTurns, graceTurns? }` JSON object
|
|
109
|
+
|
|
110
|
+
`acceptance` is a single-agent launch default. Use a scalar level such as `checked` or an inline/block YAML map such as `{ level: "none", reason: "lightweight lookup" }`. An explicit tool-call value wins; chain and parallel acceptance remains configured on the task or step. Management create/update accepts the same policy object, and `acceptance: ""` clears the frontmatter default (`false` remains the deprecated disabled-policy shorthand).
|
|
111
|
+
|
|
112
|
+
`acceptanceRole` is `read-only` or `writer` and controls automatic acceptance inference only. Explicit task mutation or no-edit intent wins; otherwise the role replaces agent-name guessing. Omission preserves the current name heuristics. The field does not grant or revoke tools. Management accepts `false` or an empty string to clear it.
|
|
113
|
+
|
|
114
|
+
`tools` is a strict child allowlist, not an extension loader. For a named extension tool, keep its registered name in `tools` and load its provider through normal Pi discovery, `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. For example, pair `tools: read, fixture_search` with `subagentOnlyExtensions: ./tools/fixture-search.ts` when the provider should exist only in that agent's child sessions. The child now fails with the unavailable names and provider-loading guidance instead of silently continuing when a requested tool is absent; internal `structured_output` is allowed automatically when an output schema requires it.
|
|
115
|
+
|
|
116
|
+
`skillPath` adds invocation-private skill files or discovery directories relative to the agent file; it does not select them, so list the desired names under `skills`. Local matches win, unresolved or unreadable matches use normal discovery, and local candidates never enter the parent/global catalog. Use `memory: { scope: "project" | "user", path: "<name>" }` for opt-in role-specific durable memory under the dedicated `agent-memory/` namespace; it is separate from parent/session project memory.
|
|
117
|
+
|
|
118
|
+
For many customizations, builtin overrides in settings are lower-friction than
|
|
119
|
+
copying a full builtin file.
|
|
120
|
+
|
|
121
|
+
## Prompt Template Integration
|
|
122
|
+
|
|
123
|
+
The package includes prompt shortcuts for common workflows: `/parallel-review`,
|
|
124
|
+
`/review-loop`, `/parallel-research`, `/parallel-context-build`,
|
|
125
|
+
`/parallel-handoff-plan`, `/gather-context-and-clarify`, and
|
|
126
|
+
`/parallel-cleanup`. Use them when the user wants repeatable review,
|
|
127
|
+
review/fix loops, research, context handoff, implementation handoff,
|
|
128
|
+
clarification, or cleanup-review patterns. `/parallel-review autofix` and
|
|
129
|
+
`/parallel-cleanup autofix` synthesize reviewer feedback and then apply only the
|
|
130
|
+
fixes worth doing now. Parent agents can also apply the same recipes directly
|
|
131
|
+
with `subagent(...)` when the user describes the workflow in natural language
|
|
132
|
+
instead of invoking a slash command.
|
|
133
|
+
|
|
134
|
+
Additional user prompt templates can delegate into `pi-subagents` through the native `/prompt-workflow` and `/chain-prompts` commands. This is useful when a slash command should always run through a particular agent or with forked context. Prompt frontmatter can set `subagent`, `model`, `skill`, `cwd`, `worktree`, `fresh`, `fork`, or `inheritContext` for the native adapter.
|
|
135
|
+
|
|
136
|
+
## Extension RPC
|
|
137
|
+
|
|
138
|
+
Other Pi extensions can call `pi-subagents` through the in-process event bus. The stable v1 channels are `subagents:rpc:v1:ready`, `subagents:rpc:v1:request`, and per-request replies at `subagents:rpc:v1:reply:<requestId>`. Envelopes use `{ version: 1, requestId, method, params }`, and replies use `{ version: 1, requestId, success, data | error }`. `ping` advertises the exact process-local async completion event as `events.asyncComplete` for RPC-spawn consumers.
|
|
139
|
+
|
|
140
|
+
Methods: `ping`, `status`, `spawn`, `steer`, `interrupt`, `resume`, and `stop`. `spawn` is async-only and rejects management actions, `async: false`, or `clarify: true`; it reuses the normal executor, so discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status are shared with the `subagent` tool. `status`, acknowledged async `steer`, and `interrupt` map to the normal control actions. RPC steer disables pause-and-revive recovery and advertises `capabilities.nonRecoveringSteer`, preserving the caller's authority over the exact spawned child. `resume` requires a target plus non-empty message and delegates to the package-owned revival path; it may set a caller-owned `file-only` output path but cannot override the persisted child model, tools, budgets, session ownership, or exclusive session lease. `stop` targets running async runs through the existing timeout control channel. `pi.events` is process-local, so separate Pi processes and child subagents need lifecycle artifact files or `pi-intercom` instead.
|