@wolido/async-subagent-isolation 1.5.0 → 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/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. All file changes, shell commands, and execution logic go to subagents, each running in its own `pi` process with its own system prompt and skills. No shared state between the main agent and subagents, or between subagents.
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
- The key difference is **async**: in TUI mode, the main agent dispatches a subagent and gets an **immediate receipt** (`已派出 <agent>. taskId: <taskId>`) without blocking. The subagent runs in a background process; when it finishes, the result arrives as a **[subagent-result] system notification**. If the main agent is idle the notification triggers processing right away; if busy, it queues. Meanwhile the main agent can dispatch multiple tasks in parallel and keep working.
20
+ ---
21
+
22
+ ## Is your agent showing these symptoms
21
23
 
22
- Subagents split an ever-growing context into pieces, each handling its own slice; async keeps the main agent's context down to "what to do" and "what came back", while the subagent's long execution trail stays in its own process.
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
- ## Sync vs async
36
+ ## Why common workarounds fall short
27
37
 
28
- 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:
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
- | | Sync (original) | Async (this project) |
31
- |---|---|---|
32
- | After dispatch | Blocks until the subagent finishes | **Returns a receipt immediately** (with `taskId`) |
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
- **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.
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
- ## Face the dispatcher, not the cluster
48
+ ## Who this is for
43
49
 
44
- 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**.
50
+ This project fits if any of these describe you:
45
51
 
46
- 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.
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
- 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.
58
+ ---
49
59
 
50
- 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.
60
+ ## Prerequisites: install Pi Agent
51
61
 
52
- 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.
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
+ ```
53
69
 
54
70
  ---
55
71
 
56
- ## How this differs from plain subagents
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/`.
104
+
105
+ ---
106
+
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
- ## Uniqueness and significance
133
+ ## Sync vs async
75
134
 
76
- This project is built on two design decisions that support each other, and its significance comes from the two together.
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
- **Async by default.** Dispatching is not handing over control — it's delivering 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, not an optional switch — the main agent never blocks, can dispatch in parallel and keep planning, and the user always faces the dispatcher alone.
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 |
79
144
 
80
- **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, not the prompt level — each subagent is its own `pi` process, and none of the main agent's skills can get in. Isolation is therefore not an instruction but a structural fact: a subagent knows only what it is allowed to know, and its domain of focus is precisely controllable.
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.
81
146
 
82
- **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. Reliable division of labor is thus structure, not discipline: async and isolation are both defaults.
147
+ ---
148
+
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
 
@@ -115,6 +192,7 @@ When the subagent finishes, its result is pushed as a **`[subagent-result]` syst
115
192
 
116
193
  - If the main agent is **idle**, the notification triggers a new turn immediately.
117
194
  - If the main agent is **busy**, it is queued and delivered with steer semantics — after the current assistant turn's tool calls finish, before the next LLM call — without waiting for the whole turn to end.
195
+ - Either way, the envelope carries a fixed **trigger line** right under the title, reminding the main agent that this is a completion notification rather than a new user instruction, and to anchor its current mainline task and progress before digesting it (see "Notification envelope and card" for the format).
118
196
 
119
197
  Results arrive automatically — **no polling**. In-flight task information is provided directly by the `[subagent-result]` notification envelope; `action="status"` was removed as a cleanup in v1.2.0.
120
198
 
@@ -157,137 +235,133 @@ User runs /subagent-result <taskId> to read the full output
157
235
  | `/subagent-cancel <taskId>` | Cancel one running background task (no argument opens an interactive picker of running tasks; Enter cancels the selection) |
158
236
  | `/subagent-cancel-all` | Cancel all running background tasks at once |
159
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) |
160
239
 
161
240
  ---
162
241
 
163
- ## Notification envelope and card
164
-
165
- The `[subagent-result]` notification is **self-contained** — it carries everything the main agent needs to process the result in one message:
242
+ ## Example agents
166
243
 
167
- ```
168
- ## [subagent-result] coder 成功 (taskId: 01912345-6789-7abc-8def-0123456789ab)
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):
169
245
 
170
- - 状态: 成功
171
- - 任务: 将认证中间件重构为使用 async/await。
172
- - 耗时: 02:34 · 用量: 5 turns/↑12.5k/↓3.2k/$0.0042
173
- - 会话: 01912345-6789-7abc-8def-0123456789ab
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` |
174
251
 
175
- 本任务结束时,其他在途任务: 1
176
- - 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").
177
253
 
178
254
  ---
179
- <full subagent output>
180
- ```
181
255
 
182
- - **Status**: `成功` (success) / `失败` (failure) / `超时` (timeout) / `已取消` (cancelled).
183
- - **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.
184
- - **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.
185
- - **Full result**: the body enters the LLM context in full, untruncated.
256
+ ## Per-subagent model configuration
186
257
 
187
- In the TUI, the user sees a **tinted summary card**, not the full result: success green (), failure red (✗), timeout/cancelled yellow. The card shows the agent, status, taskId, duration, and usage summary (duration included for all four states), plus the hint `查看全文: /subagent-result <taskId>`; the full text lives in the task's session file.
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).
188
259
 
189
- See [ADVANCED.en.md](ADVANCED.en.md) for the complete envelope format, status semantics, and cancel-origin distinctions.
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):
190
261
 
191
- ---
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
+ ```
192
269
 
193
- ## Design discipline
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`.
194
271
 
195
- Async mode introduces a few rules, baked into the tool prompts and implementation, that the main agent follows automatically:
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).
196
273
 
197
- - **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.
198
- - **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.
199
- - **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.
200
- - **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.
201
- - **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.
202
- - **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).
275
+
276
+ Thinking levels, priority, and merge rules are in [ADVANCED.en.md](ADVANCED.en.md).
203
277
 
204
278
  ---
205
279
 
206
- ## Prerequisites: install Pi Agent
280
+ ## Configuration management: `/subagent-config`
207
281
 
208
- Install Pi Agent first (Node.js >= 20 required):
282
+ In TUI mode, `/subagent-config` manages all subagent configuration interactively, with no manual file editing:
209
283
 
210
- ```bash
211
- curl -fsSL https://pi.dev/install.sh | sh
212
- # or via npm:
213
- npm install -g --ignore-scripts @earendil-works/pi-coding-agent
214
- ```
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.
215
286
 
216
- ---
287
+ How each field is edited:
217
288
 
218
- ## Quick start
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) |
219
295
 
220
- ### 1. Install the extension
296
+ `name` is a read-only identity and cannot be edited.
221
297
 
222
- ```bash
223
- pi install npm:@wolido/async-subagent-isolation
224
- ```
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.
225
299
 
226
- ### 2. Copy the example agents and skills
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.
227
301
 
228
- ```bash
229
- cp examples/pi/agent/agents/*.md ~/.pi/agent/agents/
230
- cp examples/pi/agent/master.md ~/.pi/agent/master.md
231
- cp -r examples/pi/agent/skills/* ~/.pi/agent/skills/
232
- ```
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.
233
303
 
234
- ### 3. Start the main agent
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.
235
305
 
236
- ```bash
237
- pi --tools read,grep,find,ls,subagent \
238
- --no-skills \
239
- --append-system-prompt ~/.pi/agent/master.md \
240
- --skill ~/.pi/agent/skills/brainstorming/
241
- ```
242
-
243
- 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:
306
+ ---
244
307
 
245
- ```bash
246
- alias pp='pi --tools read,grep,find,ls,subagent --no-skills --append-system-prompt ~/.pi/agent/master.md --skill ~/.pi/agent/skills/brainstorming/'
247
- ```
308
+ ## Example skills
248
309
 
249
- 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/`.
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.
250
311
 
251
312
  ---
252
313
 
253
- ## Example agents
254
-
255
- 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
256
315
 
257
- | Agent | Purpose | Tools | Skill |
258
- |-------|---------|-------|-------|
259
- | [`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` |
260
- | [`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)_ |
261
- | [`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:
262
317
 
263
- 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.
318
+ ```
319
+ ## [subagent-result] coder 成功 (taskId: 01912345-6789-7abc-8def-0123456789ab)
264
320
 
265
- ---
321
+ > [subagent-result] 任务完成通知,非用户新指令。处理前先锚定你当前正在执行的主线任务与进度;对照派发记录消化本通知,勿让通知覆盖或改写你的主线计划。
266
322
 
267
- ## Per-subagent model configuration
323
+ - 状态: 成功
324
+ - 任务: 将认证中间件重构为使用 async/await。
325
+ - 耗时: 02:34 · 用量: 5 turns/↑12.5k/↓3.2k/$0.0042
326
+ - 会话: 01912345-6789-7abc-8def-0123456789ab
268
327
 
269
- 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):
328
+ 本任务结束时,其他在途任务: 1
329
+ - 01912345-aaaa-7bbb-8ccc-0123456789ab (writer): 更新 README。
270
330
 
271
- ```json
272
- {
273
- "coder": { "model": "deepseek/deepseek-v4-pro", "thinking": "high" },
274
- "writer": "deepseek/deepseek-v4-flash"
275
- }
331
+ ---
332
+ <full subagent output>
276
333
  ```
277
334
 
278
- 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). Thinking levels, priority, and merge rules are in [ADVANCED.en.md](ADVANCED.en.md).
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).
279
344
 
280
345
  ---
281
346
 
282
- ## Example skills
347
+ ## Security and permission discipline: the main agent can't touch code
283
348
 
284
- `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.
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.
285
359
 
286
360
  ---
287
361
 
288
362
  ## Advanced usage
289
363
 
290
- 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).
291
365
 
292
366
  ---
293
367