@wolido/async-subagent-isolation 1.5.1 → 1.6.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/ADVANCED.en.md +96 -5
- package/ADVANCED.md +96 -5
- package/README.en.md +181 -112
- package/README.md +183 -114
- package/examples/README.en.md +22 -0
- package/examples/README.md +22 -0
- package/examples/pi/agent/master.md +2 -0
- package/examples/pi/agent/subagent-isolation.json +11 -0
- package/package.json +12 -3
- package/src/index.ts +1227 -7
package/README.en.md
CHANGED
|
@@ -13,47 +13,98 @@
|
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
**async-subagent-isolation** is an extension for [Pi Agent](https://github.com/earendil-works/pi) and the **async evolution** of [subagent-isolation](https://github.com/Wolido/subagent-isolation) (the synchronous version).
|
|
16
|
+
Does your AI agent start "forgetting" after long sessions — output quality dropping, files changed that you never asked for? These are classic symptoms of context explosion, context rot, and context pollution. **async-subagent-isolation** is an extension for [Pi Agent](https://github.com/earendil-works/pi) and the **async evolution** of [subagent-isolation](https://github.com/Wolido/subagent-isolation) (the synchronous version), fixing them by isolating every subagent in its own process.
|
|
17
17
|
|
|
18
|
-
The core constraint is unchanged: **the main agent can't touch code**. No `write`, no `edit`, no `bash` — only the four read-only tools `read`, `grep`, `find`, `ls`, plus a `subagent` tool for delegation
|
|
18
|
+
The core constraint is unchanged: **the main agent can't touch code**. No `write`, no `edit`, no `bash` — only the four read-only tools `read`, `grep`, `find`, `ls`, plus a `subagent` tool for delegation; all file changes, shell commands, and execution logic go to subagents. Two selling points follow. First, **skill-level prompt isolation**: every subagent runs in its own `pi` process with its own agent definition file (e.g. `coder.md`) and a skill whitelist, inheriting neither the main agent's prompt nor its skills — not a single one of the main agent's skills gets in. Second, **a division-of-labor model**: the main agent only splits, dispatches, and reviews; `coder` writes code, `writer` writes docs, `reviewer` reviews, and each subagent receives only the slice of context in its own domain. The key difference is **async**: in TUI mode, dispatch returns an **immediate receipt** (`已派出 <agent>. taskId: <taskId>`), the subagent runs in the background, and the result arrives as a **[subagent-result] system notification**; the main agent never blocks and can dispatch multiple tasks in parallel while it keeps working.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Is your agent showing these symptoms
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
All five symptoms trace back to structural root causes, and each has a structural fix:
|
|
25
|
+
|
|
26
|
+
| Symptom | Root cause | How this project fixes it |
|
|
27
|
+
|---------|------------|---------------------------|
|
|
28
|
+
| Output quality drops after long sessions; early agreements get forgotten | Context rot (also called context degradation): the context balloons over the session and early details get buried | Context partitioning: the main agent keeps only "what to do" and "what came back"; execution trails stay in the subagent's process |
|
|
29
|
+
| The context fills up with irrelevant tool output | Context pollution: verbose subtask output flows back into the main agent | Context isolation: a subagent receives only the delegated task, never sees the main agent's execution trail, and sends back just the result |
|
|
30
|
+
| The agent modifies files or runs unauthorized commands | The main agent holds write/edit/bash, too much power in one place | Least privilege: the main agent loses write/edit/bash and keeps only four read-only tools plus delegation |
|
|
31
|
+
| Multiple subtasks interfere with each other | No process isolation: subagents reuse the main agent's prompt and skills | Process isolation: every subagent runs in its own pi process, with its own prompt, skills, and execution ability |
|
|
32
|
+
| The main agent blocks while waiting on subtasks, with no parallelism | Synchronous delegation semantics: every call blocks until the subagent finishes | Async subagent delegation: dispatch returns a receipt immediately; the subagent runs in the background and reports back via notification |
|
|
23
33
|
|
|
24
34
|
---
|
|
25
35
|
|
|
26
|
-
##
|
|
36
|
+
## Why common workarounds fall short
|
|
27
37
|
|
|
28
|
-
|
|
38
|
+
The usual responses to context rot take three routes: compaction, retrieval, and longer windows. All three buy time; none changes the mechanism by which rot sets in.
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
| Result delivery | Inlined in the tool return value | Arrives as a `[subagent-result]` system notification |
|
|
34
|
-
| Parallelism | Each call blocks — serial only | Multiple tasks can be dispatched in parallel |
|
|
35
|
-
| Waiting period | Main agent's turn is occupied | Main agent continues other work |
|
|
36
|
-
| Result blocks the turn | Yes | No |
|
|
40
|
+
- **`/compact`-style compaction is after-the-fact repair.** You compress once the context has already degraded, and compression itself loses information: early agreements and the reasoning behind decisions are often exactly what you need later. After compacting, the context swells again and the next round loses more. The rhythm of rot is unchanged — the clock just restarts from the last compaction point.
|
|
41
|
+
- **RAG / retrieval memory turns the problem into tuning.** Storing history in a vector database and fetching on demand is a reasonable idea, but "what to fetch, how much, and when" becomes a new tuning burden. Fetching the wrong fragment is worse than fetching nothing: context that looks relevant but isn't will derail the main agent's judgment more easily than a clean context.
|
|
42
|
+
- **A longer context window only moves the wall.** Double the window and filling it is a matter of time; every turn sends the entire history to the model, so cost climbs with length first. Nor does a bigger window cure rot: Chroma's Context Rot study measured this — performance starts degrading well before the window is full.
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
All three routes share one default premise: a single agent carries the entire context. With that premise fixed, every solution amounts to giving the agent more: a longer window, a bigger memory, more tools. async-subagent-isolation replaces the premise itself — cut the context into slices, let each subagent handle its own, and let the main agent keep only "what to do" and "what came back".
|
|
39
45
|
|
|
40
46
|
---
|
|
41
47
|
|
|
42
|
-
##
|
|
48
|
+
## Who this is for
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
This project fits if any of these describe you:
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
- Indie developers who live in long agent sessions, and want to prevent context rot and context bloat so the main agent stays clear-headed over the long run
|
|
53
|
+
- Heavy users running many subtasks in parallel, who need subagent context isolation so verbose subtask output never becomes context pollution
|
|
54
|
+
- Tech leads who hold the line on permission discipline, and want the main agent under least privilege (no write/edit/bash) so touching files or running commands is structurally impossible
|
|
55
|
+
- Architects building multi-agent systems, who need agent process isolation for reliable workflows
|
|
56
|
+
- Throughput-minded developers who want async subagent delegation without synchronous blocking
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
---
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
## Prerequisites: install Pi Agent
|
|
51
61
|
|
|
52
|
-
|
|
62
|
+
Install Pi Agent first (Node.js >= 20 required):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -fsSL https://pi.dev/install.sh | sh
|
|
66
|
+
# or via npm:
|
|
67
|
+
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
### 1. Install the extension
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pi install npm:@wolido/async-subagent-isolation
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2. Copy the example agents and skills
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cp examples/pi/agent/agents/*.md ~/.pi/agent/agents/
|
|
84
|
+
cp examples/pi/agent/master.md ~/.pi/agent/master.md
|
|
85
|
+
cp -r examples/pi/agent/skills/* ~/.pi/agent/skills/
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Start the main agent
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pi --tools read,grep,find,ls,subagent \
|
|
92
|
+
--no-skills \
|
|
93
|
+
--append-system-prompt ~/.pi/agent/master.md \
|
|
94
|
+
--skill ~/.pi/agent/skills/brainstorming/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This restricts the main agent to read-only tools plus `subagent` delegation (no `write`/`edit`/`bash`), and loads the main agent prompt and brainstorming skill. For daily use, add an alias:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
alias pp='pi --tools read,grep,find,ls,subagent --no-skills --append-system-prompt ~/.pi/agent/master.md --skill ~/.pi/agent/skills/brainstorming/'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then just say what you need — for example, "Refactor the auth middleware to use async/await." The main agent dispatches the `coder` subagent automatically. Subagents (`coder`, `writer`) load their own skills via the `skills:` frontmatter field — no CLI flag needed. For project-scoped agents, place them in `.pi/agents/`.
|
|
53
104
|
|
|
54
105
|
---
|
|
55
106
|
|
|
56
|
-
## How this differs from plain subagents
|
|
107
|
+
## How this differs from plain subagents: why context isolation goes deeper than prompt isolation
|
|
57
108
|
|
|
58
109
|
Many subagent implementations are just "spawn a tool call inside the main agent": the subagent still reuses the main agent's prompt and skills, and the main agent keeps write and shell access — isolation is optional and partial.
|
|
59
110
|
|
|
@@ -62,24 +113,50 @@ async-subagent-isolation enforces complete isolation:
|
|
|
62
113
|
- **Process isolation**: every subagent starts in its own `pi` process.
|
|
63
114
|
- **Prompt isolation**: each subagent has its own agent definition file (e.g. `coder.md`), not the main agent's `master.md`.
|
|
64
115
|
- **Skill isolation**: the main agent and each subagent load only their own skills, with no cross-contamination.
|
|
65
|
-
- **Execution isolation**: the main agent loses `write`, `edit`, and `bash`; it can only delegate.
|
|
116
|
+
- **Execution isolation (least privilege)**: the main agent loses `write`, `edit`, and `bash`; it can only delegate.
|
|
66
117
|
- **Independent configuration**: each agent defines its own `tools` and `skills`, controlling exactly what it can and cannot do.
|
|
67
118
|
|
|
68
119
|
Beyond that, a subagent sees only the one task it was delegated — not the main agent's execution trail (context isolation) — and cannot delegate further (recursion depth capped at 1).
|
|
69
120
|
|
|
121
|
+
Two mutually reinforcing design decisions make this isolation the default behavior.
|
|
122
|
+
|
|
123
|
+
**Async by default.** Dispatch delivers a task: the call returns a receipt immediately, the task runs in an independent process in the background, and the result is pushed back as a `[subagent-result]` system notification. Async is the default semantics with no optional switch — the main agent never blocks, can dispatch in parallel and keep planning, and the user always faces the dispatcher alone.
|
|
124
|
+
|
|
125
|
+
**Exclusive skill isolation.** A subagent's skills load from a whitelist: everything is off by default, and only individually listed skills can enter its context. Isolation happens at the process level: each subagent is its own `pi` process, and none of the main agent's skills can get in. Isolation is therefore a structural fact: a subagent knows only what it is allowed to know, and its domain of focus is precisely controllable.
|
|
126
|
+
|
|
127
|
+
**Why it matters: context partitioning.** The main agent keeps only "what to do" and "what came back"; the subagent's long execution trail stays in its own process and session, never flowing back to the main agent. Context is cut into small slices, each handled by its own agent — the main agent stays clear-headed over the long run, and planning and review are never drowned in detail. Async and isolation are both defaults, so the division of labor does not depend on discipline.
|
|
128
|
+
|
|
70
129
|
Plain subagents split work. async-subagent-isolation splits everything.
|
|
71
130
|
|
|
72
131
|
---
|
|
73
132
|
|
|
74
|
-
##
|
|
133
|
+
## Sync vs async
|
|
75
134
|
|
|
76
|
-
This project is
|
|
135
|
+
This project is the async evolution of [subagent-isolation](https://github.com/Wolido/subagent-isolation). Both share the same goal — strip execution from the main agent and run it in isolated `pi` processes. The only difference is delegation semantics:
|
|
77
136
|
|
|
78
|
-
|
|
137
|
+
| | Sync (original) | Async (this project) |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| After dispatch | Blocks until the subagent finishes | **Returns a receipt immediately** (with `taskId`) |
|
|
140
|
+
| Result delivery | Inlined in the tool return value | Arrives as a `[subagent-result]` system notification |
|
|
141
|
+
| Parallelism | Each call blocks — serial only | Multiple tasks can be dispatched in parallel |
|
|
142
|
+
| Waiting period | Main agent's turn is occupied | Main agent continues other work |
|
|
143
|
+
| Result blocks the turn | Yes | No |
|
|
144
|
+
|
|
145
|
+
**The original project continues to be maintained as the synchronous version.** Use the original for synchronous, blocking semantics (results returned in place); use this project for async parallelism, background execution, and dispatch-and-return.
|
|
79
146
|
|
|
80
|
-
|
|
147
|
+
---
|
|
81
148
|
|
|
82
|
-
|
|
149
|
+
## Face the dispatcher, not the cluster
|
|
150
|
+
|
|
151
|
+
In the sync version, every delegation blocks, so the experience feels like facing a "swarm of agents": the main agent dispatches and goes silent until the subagent finishes, leaving you with stretches of relayed execution. The async version flips this — **your conversation is always with the main agent alone**.
|
|
152
|
+
|
|
153
|
+
The main agent is the dispatcher: it understands the request, splits it into tasks, dispatches them, and summarizes the results. Subagents are behind-the-scenes workers, each running in its own background process and reporting back through a `[subagent-result]` notification. You never talk to a subagent directly, and you shouldn't need to: read results with `/subagent-result`, cancel with `/subagent-cancel`, and leave everything in between to the dispatcher.
|
|
154
|
+
|
|
155
|
+
More important is **the freedom after dispatch**. While a task runs in the background, you keep talking to the main agent — refine the requirements, adjust the plan, discuss next steps, or raise a new task. The main agent doesn't wait idle; it can keep planning and even dispatch more tasks in parallel. Foreground conversation and background work move forward together.
|
|
156
|
+
|
|
157
|
+
Finally, **review when the result returns**. The subagent finishes, the notification arrives, and the main agent processes it and reports back. While you wait, you can check the progress widget, but you never have to watch.
|
|
158
|
+
|
|
159
|
+
In one line: sync traps you in the "swarm execution" block; async keeps you facing a single dispatcher while background work runs alongside your own pace.
|
|
83
160
|
|
|
84
161
|
---
|
|
85
162
|
|
|
@@ -158,141 +235,133 @@ User runs /subagent-result <taskId> to read the full output
|
|
|
158
235
|
| `/subagent-cancel <taskId>` | Cancel one running background task (no argument opens an interactive picker of running tasks; Enter cancels the selection) |
|
|
159
236
|
| `/subagent-cancel-all` | Cancel all running background tasks at once |
|
|
160
237
|
| `/subagent-result <taskId>` | Read a task's full result in a full-screen viewer (no argument opens an interactive picker of the 5 most recent finished tasks) |
|
|
238
|
+
| `/subagent-config [agent]` | The single interactive config entry: the agent picker annotates each agent's effective model/thinking; edit the six fields description/tools/skills/body/model/thinking (name is read-only) and manage the available model list (with an argument, jumps straight to that agent) |
|
|
161
239
|
|
|
162
240
|
---
|
|
163
241
|
|
|
164
|
-
##
|
|
165
|
-
|
|
166
|
-
The `[subagent-result]` notification is **self-contained** — it carries everything the main agent needs to process the result in one message:
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
## [subagent-result] coder 成功 (taskId: 01912345-6789-7abc-8def-0123456789ab)
|
|
242
|
+
## Example agents
|
|
170
243
|
|
|
171
|
-
|
|
244
|
+
The GitHub repo ships three ready-to-reference agents in [`examples/pi/agent/agents/`](https://github.com/Wolido/subagent-isolation/tree/main/examples/pi/agent/agents):
|
|
172
245
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
246
|
+
| Agent | Purpose | Tools | Skill |
|
|
247
|
+
|-------|---------|-------|-------|
|
|
248
|
+
| [`coder`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/coder.md) | Write, modify, and validate code | `read, write, edit, bash, grep, find, ls` | `systematic-debugging` |
|
|
249
|
+
| [`reviewer`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/reviewer.md) | Read-only review with actionable feedback | `read, grep, find, ls` | _(none)_ |
|
|
250
|
+
| [`writer`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/writer.md) | Write docs, READMEs, commit messages | `read, write, edit, grep, find, ls` | `writing-clearly-and-concisely` |
|
|
177
251
|
|
|
178
|
-
|
|
179
|
-
- 01912345-aaaa-7bbb-8ccc-0123456789ab (writer): 更新 README。
|
|
252
|
+
Copy the ones you need into `~/.pi/agent/agents/` (user-scoped) or `.pi/agents/` (project-scoped; project overrides user on name collisions). Feel free to modify them or create your own. After modifying or adding agent files, run `/reload` to refresh the subagent roster injected into the main agent's prompt (see "Configuration management").
|
|
180
253
|
|
|
181
254
|
---
|
|
182
|
-
<full subagent output>
|
|
183
|
-
```
|
|
184
255
|
|
|
185
|
-
|
|
186
|
-
- **Status**: `成功` (success) / `失败` (failure) / `超时` (timeout) / `已取消` (cancelled).
|
|
187
|
-
- **Duration**: the subagent's real run time (process start to finish; `MM:SS`, or `H:MM:SS` at 1h+), shown for all four states. For cancellations or internal errors with no result, it is measured from dispatch time.
|
|
188
|
-
- **In-flight block**: a build-time snapshot anchored to this task's end event (excluding itself), listing the other background tasks still running when this task ended; it may be stale by delivery time — when it conflicts with dispatch records issued this turn, the dispatch records prevail. The main agent learns how many are outstanding — while the count is non-zero, do not report "all done" to the user.
|
|
189
|
-
- **Full result**: the body enters the LLM context in full, untruncated.
|
|
256
|
+
## Per-subagent model configuration
|
|
190
257
|
|
|
191
|
-
|
|
258
|
+
Model configuration has three sources: the `model:` / `thinking:` fields in an agent file's frontmatter, `subagent-isolation.json` (user/project level), and process memory-level temporary overrides (effective in the current pi window only). Of the first two, the JSON file is the recommended one: all model settings live in one file instead of scattered across agent files, `/subagent-config` edits and writes it back interactively, and JSON overrides take precedence over frontmatter — a field set in JSON shadows the same frontmatter field, so a frontmatter value stops applying silently once an override exists. The process memory layer sits at the top of the priority chain, for temporary per-window adjustments when multiple windows share one config file (see below).
|
|
192
259
|
|
|
193
|
-
|
|
260
|
+
Use `subagent-isolation.json` to assign a model and thinking level per subagent (the file name is retained from the sync original, so both projects can share the same config):
|
|
194
261
|
|
|
195
|
-
|
|
262
|
+
```json
|
|
263
|
+
{
|
|
264
|
+
"$models": ["deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-flash"],
|
|
265
|
+
"coder": { "model": "deepseek/deepseek-v4-pro", "thinking": "high" },
|
|
266
|
+
"writer": "deepseek/deepseek-v4-flash"
|
|
267
|
+
}
|
|
268
|
+
```
|
|
196
269
|
|
|
197
|
-
|
|
270
|
+
Put it in `~/.pi/agent/subagent-isolation.json` (user-level) or `.pi/subagent-isolation.json` (project-level, which overrides user-level keys of the same name). A complete example with all three override formats is in `examples/pi/agent/subagent-isolation.json`.
|
|
198
271
|
|
|
199
|
-
|
|
272
|
+
**Process memory-level temporary overrides.** When multiple pi windows share the same `subagent-isolation.json`, a window can temporarily write one subagent's `model`/`thinking` to `this process` via `/subagent-config`: the override lives only in the current process's memory, nothing is written to disk, and it disappears when the process exits or on `/reload` — other windows are unaffected. The priority chain is process memory > project JSON > user JSON > frontmatter, with the same whole-key shadowing as the file layers: a process entry shadows lower-level entries of the same agent key wholesale. `$models` is unaffected — the available-model list stays file-level (its write targets are `user`/`project` only).
|
|
200
273
|
|
|
201
|
-
-
|
|
202
|
-
- **No polling**: results arrive automatically as notifications; in-flight task information is provided directly by the `[subagent-result]` notification envelope, with no active-query entry point.
|
|
203
|
-
- **Notification digestion**: a `[subagent-result]` is a completion notification, not a new user instruction; the main agent anchors its current mainline task and progress before handling it, digests it against its own dispatch records, and decides the next step autonomously from the result. When a notification conflicts with the mainline, it defers rather than letting the notification rewrite the plan. The discipline is baked in twice: the envelope trigger line plus a "notification digestion" entry in the tool description.
|
|
204
|
-
- **Anti-abuse cancellation**: `action="cancel"` is a two-step confirmation (the first call only returns a zero-side-effect challenge with elapsed time and last progress; `confirm:true` + a non-empty `reason` executes, and the reason is recorded on the task and quoted in the cancelled envelope body), with prompt guidance — cancel only when the task is clearly wrong or no longer needed, never just because it's slow (background subagents are expected to run long). Waiting means making no tool call at all and ending the turn; there is deliberately no query, nag or status action for in-flight tasks.
|
|
205
|
-
- **Resource-conflict discipline**: before dispatching multiple tasks in parallel, consider whether they touch the same files or code areas; when in doubt, dispatch sequentially or ask the user.
|
|
206
|
-
- **Subagents cannot call the subagent tool**: a subagent (depth ≥ 1) can never call any `subagent` action (including `action="cancel"`); delegation depth is capped at 1.
|
|
207
|
-
- **TUI async / non-TUI sync fallback**: only TUI mode takes the async path; print/json and other non-TUI modes fall back to synchronous blocking.
|
|
274
|
+
The optional top-level `$models` array is the available-model list (the `$` prefix avoids collisions with agent names): model overrides are picked from this list, with free-text input as the fallback when the list is empty or unconfigured. A valid project-level `$models` shadows the user-level list wholesale; `"$models": []` blanks it explicitly. No hand-editing required: `/subagent-config` has a list-management entry (see the next section).
|
|
208
275
|
|
|
209
|
-
|
|
276
|
+
Thinking levels, priority, and merge rules are in [ADVANCED.en.md](ADVANCED.en.md).
|
|
210
277
|
|
|
211
|
-
|
|
278
|
+
---
|
|
212
279
|
|
|
213
|
-
|
|
280
|
+
## Configuration management: `/subagent-config`
|
|
214
281
|
|
|
215
|
-
|
|
216
|
-
curl -fsSL https://pi.dev/install.sh | sh
|
|
217
|
-
# or via npm:
|
|
218
|
-
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
|
219
|
-
```
|
|
282
|
+
In TUI mode, `/subagent-config` manages all subagent configuration interactively, with no manual file editing:
|
|
220
283
|
|
|
221
|
-
|
|
284
|
+
1. Pick an agent: each entry carries a `(user)` / `(project)` source marker plus its effective model/thinking annotation (`<name> (<source>) — <model> (<thinking>)`, `(未配置)` when unset; effective values follow the whole-key merge — a process-memory entry shadows the project/user entries of the same key, a project-level entry shadows the user-level entry of the same key, with unset fields falling back to frontmatter, identical to dispatch); the fixed last entry `Manage available model list ($models)` opens the available-model list management (view the current list with its source, add, remove, and choose user/project as the write target). With zero agents the picker degrades to just this entry, and `$models` stays manageable.
|
|
285
|
+
2. Pick a field to edit: selecting an agent goes straight to the field select, whose options carry the current-value annotations (no detail notice — information comes from the menu annotations). Six fields: `description`, `tools`, `skills`, `body`, `model`, `thinking`; `name` is a read-only identity and is not among them.
|
|
222
286
|
|
|
223
|
-
|
|
287
|
+
How each field is edited:
|
|
224
288
|
|
|
225
|
-
|
|
289
|
+
| Field | How it is edited |
|
|
290
|
+
|-------|------------------|
|
|
291
|
+
| `description` | Single-line input prefilled with the current value; a successful edit asks for `/reload` to rebuild the injected roster |
|
|
292
|
+
| `tools` / `skills` | Comma-separated input; an empty input removes the key from the frontmatter |
|
|
293
|
+
| `body` | Opens in an external editor (`$EDITOR`, falling back to `$VISUAL`, then `vi`); cancel, unchanged, or whitespace-only results write nothing |
|
|
294
|
+
| `model` / `thinking` | Write target is one of three: `this process` (in-memory, nothing written to disk, gone on process exit or `/reload`) / `user` / `project`; `thinking` is picked from pi's official 7 levels, `model` is picked from `$models` when the list is non-empty and free-typed otherwise (prefilled with the current effective value); `clear model (reset to frontmatter)` / `clear thinking (reset to frontmatter)` options remove the override — clearing the memory layer drops that agent's in-memory override, and the result notice recomputes the effective value under the whole-key merge (with dual-level config it falls back to the other level's JSON or stays unchanged) |
|
|
226
295
|
|
|
227
|
-
|
|
228
|
-
pi install npm:@wolido/async-subagent-isolation
|
|
229
|
-
```
|
|
296
|
+
`name` is a read-only identity and cannot be edited.
|
|
230
297
|
|
|
231
|
-
|
|
298
|
+
When edits take effect (reload semantics): `description` edits require `/reload` to rebuild the injected roster, because the subagent roster injected into the main agent's system prompt is built and cached at startup (see "Security and permission discipline"); `tools` / `skills` / `body` / `model` / `thinking` take effect immediately, since every dispatch re-discovers agents and re-reads the config.
|
|
232
299
|
|
|
233
|
-
|
|
234
|
-
cp examples/pi/agent/agents/*.md ~/.pi/agent/agents/
|
|
235
|
-
cp examples/pi/agent/master.md ~/.pi/agent/master.md
|
|
236
|
-
cp -r examples/pi/agent/skills/* ~/.pi/agent/skills/
|
|
237
|
-
```
|
|
300
|
+
`/subagent-config <name>` with an argument skips the agent picker and jumps straight to that agent's config; an unknown name is an error. In non-TUI mode the command only prints a usage notice and opens no dialogs.
|
|
238
301
|
|
|
239
|
-
|
|
302
|
+
The flow supports ESC at every level: edit → field select → agent picker → exit, with only the top level exiting; in the model/thinking subflow the field-level ESC returns to the parent flow's field select. Every back-off path writes nothing.
|
|
240
303
|
|
|
241
|
-
|
|
242
|
-
pi --tools read,grep,find,ls,subagent \
|
|
243
|
-
--no-skills \
|
|
244
|
-
--append-system-prompt ~/.pi/agent/master.md \
|
|
245
|
-
--skill ~/.pi/agent/skills/brainstorming/
|
|
246
|
-
```
|
|
304
|
+
`/subagent-config` is the only interactive config entry — model/thinking overrides are edited in the same flow as every other field, with no separate shortcut command.
|
|
247
305
|
|
|
248
|
-
|
|
306
|
+
---
|
|
249
307
|
|
|
250
|
-
|
|
251
|
-
alias pp='pi --tools read,grep,find,ls,subagent --no-skills --append-system-prompt ~/.pi/agent/master.md --skill ~/.pi/agent/skills/brainstorming/'
|
|
252
|
-
```
|
|
308
|
+
## Example skills
|
|
253
309
|
|
|
254
|
-
|
|
310
|
+
`examples/pi/agent/skills/` ships three skills: `brainstorming` (main-agent planning), `systematic-debugging` (coder), and `writing-clearly-and-concisely` (writer). Copy them into `~/.pi/agent/skills/` (user scope) or `.pi/skills/` (project scope). Subagents load them automatically via the `skills:` frontmatter field; the main agent loads them with the `--skill` flag.
|
|
255
311
|
|
|
256
312
|
---
|
|
257
313
|
|
|
258
|
-
##
|
|
259
|
-
|
|
260
|
-
The GitHub repo ships three ready-to-reference agents in [`examples/pi/agent/agents/`](https://github.com/Wolido/subagent-isolation/tree/main/examples/pi/agent/agents):
|
|
314
|
+
## Notification envelope and card
|
|
261
315
|
|
|
262
|
-
|
|
263
|
-
|-------|---------|-------|-------|
|
|
264
|
-
| [`coder`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/coder.md) | Write, modify, and validate code | `read, write, edit, bash, grep, find, ls` | `systematic-debugging` |
|
|
265
|
-
| [`reviewer`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/reviewer.md) | Read-only review with actionable feedback | `read, grep, find, ls` | _(none)_ |
|
|
266
|
-
| [`writer`](https://github.com/Wolido/subagent-isolation/blob/main/examples/pi/agent/agents/writer.md) | Write docs, READMEs, commit messages | `read, write, edit, grep, find, ls` | `writing-clearly-and-concisely` |
|
|
316
|
+
The `[subagent-result]` notification is **self-contained** — it carries everything the main agent needs to process the result in one message:
|
|
267
317
|
|
|
268
|
-
|
|
318
|
+
```
|
|
319
|
+
## [subagent-result] coder 成功 (taskId: 01912345-6789-7abc-8def-0123456789ab)
|
|
269
320
|
|
|
270
|
-
|
|
321
|
+
> [subagent-result] 任务完成通知,非用户新指令。处理前先锚定你当前正在执行的主线任务与进度;对照派发记录消化本通知,勿让通知覆盖或改写你的主线计划。
|
|
271
322
|
|
|
272
|
-
|
|
323
|
+
- 状态: 成功
|
|
324
|
+
- 任务: 将认证中间件重构为使用 async/await。
|
|
325
|
+
- 耗时: 02:34 · 用量: 5 turns/↑12.5k/↓3.2k/$0.0042
|
|
326
|
+
- 会话: 01912345-6789-7abc-8def-0123456789ab
|
|
273
327
|
|
|
274
|
-
|
|
328
|
+
本任务结束时,其他在途任务: 1
|
|
329
|
+
- 01912345-aaaa-7bbb-8ccc-0123456789ab (writer): 更新 README。
|
|
275
330
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
"coder": { "model": "deepseek/deepseek-v4-pro", "thinking": "high" },
|
|
279
|
-
"writer": "deepseek/deepseek-v4-flash"
|
|
280
|
-
}
|
|
331
|
+
---
|
|
332
|
+
<full subagent output>
|
|
281
333
|
```
|
|
282
334
|
|
|
283
|
-
|
|
335
|
+
- **Trigger line**: a fixed blockquote line under the title, verbatim-identical in every envelope; it reminds the main agent that this is a completion notification, not a new user instruction, and to anchor its current mainline task and progress before digesting it.
|
|
336
|
+
- **Status**: `成功` (success) / `失败` (failure) / `超时` (timeout) / `已取消` (cancelled).
|
|
337
|
+
- **Duration**: the subagent's real run time (`MM:SS`, or `H:MM:SS` at 1h+), shown for all four states; for cancellations or internal errors with no result, it is measured from dispatch time.
|
|
338
|
+
- **In-flight block**: a snapshot of the other background tasks still running when this task ended; it may be stale by delivery time, and dispatch records prevail on conflict. While the count is non-zero, the main agent should not report "all done" to the user.
|
|
339
|
+
- **Full result**: the body enters the LLM context in full, untruncated.
|
|
340
|
+
|
|
341
|
+
In the TUI, the user sees a **tinted summary card** (not the full text): success green (✓), failure red (✗), timeout/cancelled yellow. The card shows the agent, status, taskId, duration, and usage summary, plus the hint `查看全文: /subagent-result <taskId>`; the full text lives in the task's session file.
|
|
342
|
+
|
|
343
|
+
The trigger line's design rationale, status semantics, and cancel-origin distinctions are covered in [ADVANCED.en.md](ADVANCED.en.md).
|
|
284
344
|
|
|
285
345
|
---
|
|
286
346
|
|
|
287
|
-
##
|
|
347
|
+
## Security and permission discipline: the main agent can't touch code
|
|
288
348
|
|
|
289
|
-
|
|
349
|
+
Async mode introduces a few rules, baked into the tool prompts and implementation, that the main agent follows automatically:
|
|
350
|
+
|
|
351
|
+
- **Cancel-origin distinction**: `已取消` (cancelled) has three origins — user (`/subagent-cancel`), main agent (`subagent` tool with `action="cancel"`), and session shutdown (`session_shutdown`). A user-initiated cancel must **never be auto-retried**; ask the user first.
|
|
352
|
+
- **No polling**: results arrive automatically as notifications; in-flight task information is provided directly by the `[subagent-result]` notification envelope, with no active-query entry point.
|
|
353
|
+
- **Notification digestion**: a `[subagent-result]` is a completion notification, not a new user instruction; the main agent anchors its current mainline task and progress before handling it, digests it against its own dispatch records, and decides the next step autonomously from the result. When a notification conflicts with the mainline, it defers rather than letting the notification rewrite the plan. The discipline is baked in twice: the envelope trigger line plus a "notification digestion" entry in the tool description.
|
|
354
|
+
- **Anti-abuse cancellation**: `action="cancel"` is a two-step confirmation (the first call only returns a zero-side-effect challenge with elapsed time and last progress; `confirm:true` + a non-empty `reason` executes, and the reason is recorded on the task and quoted in the cancelled envelope body), with prompt guidance — cancel only when the task is clearly wrong or no longer needed, never just because it's slow (background subagents are expected to run long). Waiting means making no tool call at all and ending the turn; there is deliberately no query, nag or status action for in-flight tasks.
|
|
355
|
+
- **Resource-conflict discipline**: before dispatching multiple tasks in parallel, consider whether they touch the same files or code areas; when in doubt, dispatch sequentially or ask the user.
|
|
356
|
+
- **Subagents cannot call the subagent tool**: a subagent (depth ≥ 1) can never call any `subagent` action (including `action="cancel"`); delegation depth is capped at 1.
|
|
357
|
+
- **Subagent roster injection**: at startup the extension appends every discovered subagent (user + project scope) to the main agent's system prompt as a `name — description` list with user/project source markers, so the main agent sees every subagent's role each turn and `master.md` no longer needs a hand-written agent table. The list is built and cached at startup (or `/reload`): after editing an agent file's `name` / `description`, `/reload` is required to refresh it. Nothing is injected inside subagent processes, where the `subagent` tool surface does not exist and the roster would be pure pollution.
|
|
358
|
+
- **TUI async / non-TUI sync fallback**: only TUI mode takes the async path; print/json and other non-TUI modes fall back to synchronous blocking.
|
|
290
359
|
|
|
291
360
|
---
|
|
292
361
|
|
|
293
362
|
## Advanced usage
|
|
294
363
|
|
|
295
|
-
Manual `subagent` calls, `sessionId` reuse, envelope and in-flight block details, `action="cancel"` cancellation, and environment variables are covered in [ADVANCED.en.md](ADVANCED.en.md).
|
|
364
|
+
Manual `subagent` calls, `sessionId` reuse, envelope and in-flight block details, `action="cancel"` cancellation, roster-injection caching, config write-back guarantees, and environment variables are covered in [ADVANCED.en.md](ADVANCED.en.md).
|
|
296
365
|
|
|
297
366
|
---
|
|
298
367
|
|