@narumitw/pi-subagents 0.42.0 → 0.43.1
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.md +142 -32
- package/package.json +1 -1
- package/src/agents.ts +49 -8
- package/src/config-ui.ts +223 -28
- package/src/consult-policy.ts +15 -0
- package/src/consult-render.ts +194 -0
- package/src/consult.ts +815 -0
- package/src/cwd-policy.ts +183 -0
- package/src/execution.ts +135 -66
- package/src/in-process-transport.ts +3 -3
- package/src/inspect-render.ts +234 -0
- package/src/inspect.ts +453 -0
- package/src/limits.ts +1 -0
- package/src/params.ts +2 -0
- package/src/persistence.ts +29 -0
- package/src/registry.ts +87 -0
- package/src/render-common.ts +252 -0
- package/src/render.ts +134 -99
- package/src/runner.ts +162 -22
- package/src/safe-text.ts +67 -0
- package/src/settings.ts +199 -12
- package/src/stateful-guidance.ts +35 -0
- package/src/stateful-lifecycle.ts +31 -0
- package/src/stateful-render.ts +249 -0
- package/src/stateful-safety.ts +91 -0
- package/src/stateful.ts +254 -225
- package/src/subagents.ts +100 -19
- package/src/subprocess-transport.ts +19 -2
package/README.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-subagents) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
`@narumitw/pi-subagents` is a native [Pi coding agent](https://pi.dev) extension for delegating work to specialized agents. By default,
|
|
5
|
+
`@narumitw/pi-subagents` is a native [Pi coding agent](https://pi.dev) extension for delegating work to specialized agents. By default, it exposes seven capability-specific tools: blocking batches, four detached lifecycle tools, side-effect-free inspection, and synchronous read-only consultation. Users can keep every delegation method, choose async-only delegation, retain only blocking delegation, or disable delegation while keeping inspection available.
|
|
6
6
|
|
|
7
7
|
Use it to split independent research, planning, implementation, and review work across focused workers. Under the default next-turn delivery policy, background delegation is for work the current response does not depend on. Opt-in auto-resume also supports final-answer-dependent background work by requesting a synthesis turn after completion.
|
|
8
8
|
|
|
9
9
|
## ✨ Features
|
|
10
10
|
|
|
11
|
-
- Offers all delegation methods by default, with goal-oriented presets for async-only
|
|
11
|
+
- Offers all delegation methods by default, with goal-oriented presets for async-only, blocking-only, or disabled delegation.
|
|
12
|
+
- Adds `subagent_inspect` for bounded metadata without child launch, mailbox-content access, acknowledgement, or mutation.
|
|
13
|
+
- Adds `subagent_consult` for one synchronous ephemeral child constrained to built-in `read`, `grep`, `find`, and `ls` tools (or a narrower agent allow-list).
|
|
12
14
|
- Keeps batch workers isolated in `pi --mode json -p --no-session` subprocesses.
|
|
13
15
|
- Registers detached stateful lifecycle tools by default; completion can stay queued for the next turn or opt into an idle root synthesis turn.
|
|
14
16
|
- Supports an opt-in public-SDK `in-process` stateful transport with one reusable child `AgentSession` per `agentId`.
|
|
@@ -16,7 +18,8 @@ Use it to split independent research, planning, implementation, and review work
|
|
|
16
18
|
- Loads custom user agents from `~/.pi/agent/agents/*.md`.
|
|
17
19
|
- Optionally loads project agents from `.pi/agents/*.md` with confirmation.
|
|
18
20
|
- Provides a current-session-first `/subagents` manager, direct `settings|status|help` routes, and compatibility aliases for agent tools and retained agents.
|
|
19
|
-
- Supports per-task `cwd
|
|
21
|
+
- Supports trust-aware per-task `cwd` policies, hard subprocess `timeoutMs`, task-selected `thinkingLevel`, abort propagation, and streaming progress.
|
|
22
|
+
- Renders all seven tools with Pi-native compact/expanded transcript rows; long-running blocking and consultation calls show bounded live activity.
|
|
20
23
|
- Bounds JSON lines, captured messages, stderr, final output, chain substitution, and fan-in context.
|
|
21
24
|
- Enforces a recursion-depth guard and deterministic process-group termination.
|
|
22
25
|
- Provides addressable stateful agents with follow-up, consolidated mailbox/management actions, context selection, and persistence.
|
|
@@ -43,13 +46,14 @@ pi -e ./extensions/pi-subagents
|
|
|
43
46
|
|
|
44
47
|
## 🛠️ Pi tool
|
|
45
48
|
|
|
46
|
-
`pi-subagents` registers
|
|
49
|
+
`pi-subagents` registers seven tools by default. Run `/subagents`, choose **Change delegation**, review the concrete tool changes, then select **Save and reload** to apply one of these workflows:
|
|
47
50
|
|
|
48
51
|
| Workflow | Registered tools |
|
|
49
52
|
| --- | --- |
|
|
50
|
-
| **All delegation methods** (default) |
|
|
51
|
-
| **Async only** |
|
|
52
|
-
| **Blocking only** |
|
|
53
|
+
| **All delegation methods** (default) | Existing five delegation/lifecycle tools, `subagent_inspect`, and `subagent_consult` |
|
|
54
|
+
| **Async only** | Four detached lifecycle tools plus `subagent_inspect`; blocking `subagent` and `subagent_consult` are omitted |
|
|
55
|
+
| **Blocking only** | `subagent`, `subagent_consult`, and `subagent_inspect` |
|
|
56
|
+
| **Disabled** | `subagent_inspect` only; delegation is disabled |
|
|
53
57
|
|
|
54
58
|
The preview compares the selection with the tools registered in the current session, even when a manual settings edit is pending, and remains read-only until confirmation. Escape or **Cancel** leaves settings unchanged. Tool removal requires an extension reload because Pi does not expose extension tool unregistration. To avoid aborting work or removing isolated worktrees during `session_shutdown`, workflow changes are blocked while detached agents are retained; finish or clear them through **Current agents** first. Pi owns reload-error reporting and does not return a success result to extensions, so the save notification also tells users to run `/reload` if the tool surface does not refresh.
|
|
55
59
|
|
|
@@ -57,12 +61,28 @@ The available tools are:
|
|
|
57
61
|
|
|
58
62
|
- `subagent` — delegate blocking single, parallel, fan-in, or chained batch work. The main agent cannot process queued steering until the call returns.
|
|
59
63
|
- `subagent_spawn` and related lifecycle tools — when enabled, start reusable detached work, return immediately, and receive bounded completion messages automatically.
|
|
64
|
+
- `subagent_inspect` — inspect agent/model/run/runtime metadata without launching work or changing state.
|
|
65
|
+
- `subagent_consult` — run one ephemeral read-only consultation and wait for its answer.
|
|
60
66
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
### Interactive tool rows
|
|
68
|
+
|
|
69
|
+
In Pi's interactive TUI, every registered tool uses Pi's native tool shell and theme. Call rows identify the action, agent or retained id, scope, and a bounded task/message preview. Result rows use explicit `Starting`, `Running`, `Completed`, `Failed`, `Cancelled`, `Interrupted`, or `Closed` text in addition to icons and color.
|
|
70
|
+
|
|
71
|
+
Collapsed rows stay scan-friendly: consultation and blocking calls show recent activity while running, completed answers show up to three lines, and list actions show up to five items. Use Pi's configured `app.tools.expand` keybinding (Ctrl+O by default) for the additional bounded task, policy, activity, answer, usage, inspection, or mailbox details available to that tool. The hint follows the user's keybinding rather than assuming Ctrl+O.
|
|
72
|
+
|
|
73
|
+
`subagent_consult` emits an initial starting update before launching its child and then reports the actual provider/model, thinking request, usage, and a safe projection of recent `read`, `grep`, `find`, and `ls` activity. Progress never includes full child messages, prompts, credentials, headers, or environment values. Tool-row previews remove terminal controls and redact private text.
|
|
74
|
+
|
|
75
|
+
`subagent_spawn` remains deliberately detached and non-polling: its tool row ends after returning the new `agentId` and initial retained state. It does not pretend to stream the background child after the tool call has completed; the existing completion message and configured delivery policy report eventual completion.
|
|
76
|
+
|
|
77
|
+
Custom transcript rendering is TUI presentation only. Tool names, parameter schemas, model-facing final content/details, errors, completion delivery, and print/JSON/RPC final output remain unchanged; JSON/RPC observers may see additive bounded consultation partial-progress details.
|
|
78
|
+
|
|
79
|
+
After each session starts, the descriptions of the registered `subagent`, `subagent_spawn`, and
|
|
80
|
+
`subagent_consult` tools include the same bounded parent-facing catalog of the agents available in
|
|
81
|
+
that session. Entries show the source (`built-in`, `user`, or `project`) and the `agentScope` needed to
|
|
82
|
+
invoke them; the `agent` parameters remain unconstrained strings for cwd and scope flexibility. The
|
|
83
|
+
catalog is rebuilt on
|
|
84
|
+
`/reload` or the next session start, and omitted entries are reported explicitly when the catalog
|
|
85
|
+
exceeds its metadata bounds.
|
|
66
86
|
|
|
67
87
|
Choose the API by lifecycle:
|
|
68
88
|
|
|
@@ -72,6 +92,8 @@ Choose the API by lifecycle:
|
|
|
72
92
|
| Broad research/review the current response does not depend on | Prefer one `subagent_spawn` covering related branches, when lifecycle tools are enabled |
|
|
73
93
|
| Final-answer-dependent broad work with `completionDelivery: "auto-resume"` | Prefer one `subagent_spawn`; completion requests a synthesis turn |
|
|
74
94
|
| Reusable history, follow-ups, or mailboxes | `subagent_spawn` and lifecycle tools, when enabled |
|
|
95
|
+
| Side-effect-free agent/model/run diagnostics | `subagent_inspect` |
|
|
96
|
+
| Synchronous reconnaissance, planning, or review that must not write | `subagent_consult`, when blocking delegation is enabled |
|
|
75
97
|
| One simple or critical-path action the root can perform directly | No subagent |
|
|
76
98
|
|
|
77
99
|
Execution modes:
|
|
@@ -83,22 +105,40 @@ Execution modes:
|
|
|
83
105
|
|
|
84
106
|
Common controls:
|
|
85
107
|
|
|
86
|
-
- `cwd` —
|
|
108
|
+
- `cwd` — choose a launch directory subject to the user-owned trust-aware target policy described below.
|
|
87
109
|
- `timeoutMs` — set a hard subprocess timeout.
|
|
88
110
|
- `thinkingLevel` — request `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` thinking for the spawned Pi process or in-process child.
|
|
89
111
|
|
|
90
112
|
For `subagent_spawn`, the root agent selects the lowest thinking level sufficient for the delegated task. This is a tool-argument decision made from the task already in context; `pi-subagents` does not run a string heuristic or an extra classifier model call.
|
|
91
113
|
|
|
114
|
+
## 🔐 Working-directory trust policy
|
|
115
|
+
|
|
116
|
+
Pi records saved project trust in `~/.pi/agent/trust.json`. The closest saved decision for the canonical target or one of its parents wins, so trusting a worktree parent covers worktrees below it while a nearer `false` overrides a trusted parent. `pi-subagents` reads this through Pi's public `ProjectTrustStore`; it never parses, writes, or migrates the file. Open Pi in a folder and use `/trust` to manage trust, then restart Pi before expecting retained-runtime behavior to change.
|
|
117
|
+
|
|
118
|
+
The default target policies are:
|
|
119
|
+
|
|
120
|
+
| Setting | Values | Default behavior |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| `cwdPolicy.consultation` | `"anywhere"`, `"current-workspace"` | `"anywhere"`: consultation may start in any existing directory, but a target without effective trust is forced to `resources: "none"` |
|
|
123
|
+
| `cwdPolicy.delegation` | `"trusted-targets"`, `"current-workspace"`, `"anywhere"` | `"trusted-targets"`: blocking and detached delegation may target the current workspace or an external folder covered by a saved `true` decision |
|
|
124
|
+
|
|
125
|
+
All paths are resolved relative to the current session workspace and canonicalized before containment and trust checks. Missing paths, non-directories, sibling paths, and symlink escapes cannot bypass the policy. Blocking parallel, chain, and fan-in calls preflight every target before any child starts. A generated `workspaceMode: "worktree"` inherits the resolved trust of its approved base cwd.
|
|
126
|
+
|
|
127
|
+
`"anywhere"` for general delegation restores the previous external-target flexibility. An external target without effective trust starts with `projectTrusted: false`, so Pi-protected project settings, packages, extensions, skills, prompts, and system resources stay disabled. General agents still have their configured tools and ordinary Pi/OS permissions, and Pi may still load `AGENTS.md` or `CLAUDE.md` because those context files are not protected by project trust. Resource-free consultation is stricter: it also passes `--no-context-files`, `--no-skills`, `--no-prompt-templates`, `--no-approve`, and `--no-extensions`.
|
|
128
|
+
|
|
129
|
+
These controls govern child starting directories and automatically loaded resources. They do **not** restrict absolute paths, shell commands, custom tools, network access, extension code, or filesystem access available to the Pi process. For real isolation, run Pi in a container, VM, micro-VM, or OS sandbox with only the required paths and credentials mounted.
|
|
130
|
+
|
|
92
131
|
## 🧭 Proactive use
|
|
93
132
|
|
|
94
133
|
When registered, the blocking `subagent` tool advertises only blocking guidance. When stateful lifecycle tools
|
|
95
134
|
are registered, `subagent_spawn` adds detached guidance for the active completion-delivery policy.
|
|
96
135
|
Changing the policy through `/subagents settings` refreshes that guidance immediately.
|
|
97
136
|
|
|
98
|
-
The
|
|
99
|
-
needed. Built-ins and user agents appear under the
|
|
100
|
-
agents appear separately and explicitly require
|
|
101
|
-
names and descriptions are not read into
|
|
137
|
+
The `subagent`, `subagent_spawn`, and `subagent_consult` descriptions advertise the current agent
|
|
138
|
+
catalog automatically; no preliminary list call is needed. Built-ins and user agents appear under the
|
|
139
|
+
default `agentScope: "user"`. Trusted project agents appear separately and explicitly require
|
|
140
|
+
`agentScope: "project"` or `"both"`; project-authored names and descriptions are not read into
|
|
141
|
+
metadata for untrusted projects. If a project definition
|
|
102
142
|
shares a name with a user or built-in definition, the user version is the default and the project
|
|
103
143
|
version is used only for `"project"`/`"both"`. A user override of a built-in also shows the
|
|
104
144
|
built-in fallback available with `agentScope: "project"`; `"both"` keeps the user definition. The
|
|
@@ -169,6 +209,60 @@ A blocking fan-out is reserved for output that must be synthesized before the ro
|
|
|
169
209
|
}
|
|
170
210
|
```
|
|
171
211
|
|
|
212
|
+
## 🔎 Read-only inspection
|
|
213
|
+
|
|
214
|
+
`subagent_inspect` is registered in every workflow, including disabled delegation. It never starts a child, sends or acknowledges mailbox messages, interrupts or closes a run, changes settings, refreshes providers, resolves credentials, or modifies files.
|
|
215
|
+
|
|
216
|
+
| Action | Parameters | Result |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| `list_agents` | Optional `agentScope` (default `user`) and `limit` (default 32, maximum 100) | Bounded agent metadata and omission counts |
|
|
219
|
+
| `get_agent` | Required `agent`; optional `agentScope` | One resolved definition, safe source path, configured tools, and consultation-effective tools; never the system prompt |
|
|
220
|
+
| `list_runs` | Optional `includeClosed` and `limit` (default 50, maximum 100) | Metadata-only retained-run summaries and unread counts |
|
|
221
|
+
| `get_run` | Required `agentId` | Safe `cwd`, current-task/error summaries, thinking level, policy, history count, and unread count |
|
|
222
|
+
| `list_models` | Optional `limit` (default 50, maximum 100) | Session-scoped models, or the already-loaded available snapshot |
|
|
223
|
+
| `status` | No additional fields | Effective workflow, runtime counts/transport, completion delivery, consultation resources, and configured/runtime cwd policies with per-field sources |
|
|
224
|
+
| `diagnose` | No additional fields | Structured `pass`, `warning`, and `fail` checks; failed checks are report data rather than a tool error |
|
|
225
|
+
|
|
226
|
+
The schema rejects fields that do not belong to the selected action. Explicit `project` or `both` scope fails before project-agent discovery unless Pi already trusts the project. Run inspection never returns history output, stored context, or mailbox content; unread counts come from a metadata-only snapshot and do not acknowledge messages. Paths beneath the Pi agent directory use `~`, project paths are workspace-relative, model objects are projected through an allow-list, and model-facing text is bounded to 50 KiB or 2,000 lines.
|
|
227
|
+
|
|
228
|
+
Compatibility: `subagent_manage({ "action": "list" })` remains supported with its existing behavior. Prefer `subagent_inspect` when a whole tool must be safe to activate on a read-only surface.
|
|
229
|
+
|
|
230
|
+
## 📖 Read-only consultation
|
|
231
|
+
|
|
232
|
+
`subagent_consult` is registered whenever blocking delegation is enabled. It runs exactly one synchronous, non-retained child with `--no-session`, `--no-extensions`, and only the effective intersection of the agent tools with `read`, `grep`, `find`, and `ls`. A missing tool list receives those four defaults; an explicit `tools: []` receives `--no-tools`; write, shell, lifecycle, custom, and extension tools cannot enter the child allow-list. The executor policy remains authoritative even when the task or agent prompt asks for implementation.
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"agent": "reviewer",
|
|
237
|
+
"task": "Inspect the authentication changes and report correctness and security findings with paths.",
|
|
238
|
+
"thinkingLevel": "high"
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The actionless schema requires `agent` and `task` and accepts optional `agentScope`,
|
|
243
|
+
`confirmProjectAgents`, `cwd`, `timeoutMs`, and `thinkingLevel`. Any agent resolved from that scope may
|
|
244
|
+
be selected; consultation always intersects its configured tools with the enforced read-only
|
|
245
|
+
allow-list rather than defining a separate read-only agent category. An unknown name fails before
|
|
246
|
+
launch with a bounded name/source list for the requested scope. Project scope is rejected before
|
|
247
|
+
discovery when the project is untrusted. A trusted project agent still asks for confirmation by
|
|
248
|
+
default; non-interactive calls fail closed unless they explicitly send
|
|
249
|
+
`confirmProjectAgents: false`. Declining an interactive confirmation returns a normal cancelled result
|
|
250
|
+
without launching or charging a child.
|
|
251
|
+
|
|
252
|
+
`consult.resources` controls automatically inherited instruction resources:
|
|
253
|
+
|
|
254
|
+
| Value | Behavior |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| `"project-context"` (default) | Keep ordinary user context/system files and trusted project `AGENTS.md`, `CLAUDE.md`, and `SYSTEM.md`; disable skills and prompt templates |
|
|
257
|
+
| `"none"` | Use only the package consultation base, selected agent prompt, and enforced read-only instruction |
|
|
258
|
+
| `"all"` | Keep ordinarily discoverable trusted context/system/append-system files, skills, and prompt templates |
|
|
259
|
+
|
|
260
|
+
Extensions remain disabled for all three values. A current target uses the session's effective project trust, including session-only or CLI overrides. An external target uses the nearest saved trust decision. For an untrusted, explicitly denied, unsaved, or trust-error target, consultation remains available when `cwdPolicy.consultation` permits it but automatically downgrades to `resources: "none"`. This also disables context files because Pi does not protect `AGENTS.md` and `CLAUDE.md` with project trust alone. A saved-trusted external target uses the configured resource policy and discovers `SYSTEM.md`, `APPEND_SYSTEM.md`, and ordinary child context from that target rather than the parent workspace.
|
|
261
|
+
|
|
262
|
+
Both settings are user-owned in `~/.pi/agent/pi-subagents.json`; projects cannot override them. `cwdPolicy.consultation: "current-workspace"` rejects every canonical external target before agent discovery or launch even when that target is saved-trusted. This is not a path sandbox: read-only tools can still read an explicitly requested accessible absolute path.
|
|
263
|
+
|
|
264
|
+
Result details report the canonical safe cwd, current/external boundary, bounded target-trust decision/source/warning, requested and effective tools/resources, downgrade reason, agent/model/thinking/timeout metadata, and the facts that extensions, session persistence, and retained-agent state are disabled. They never dump prompt contents or the full trust store. Nested model usage is returned through Pi's usage field, so footer, `/session`, and RPC totals include consultation cost. Validation, disallowed targets, and launch failures throw. Failures after model launch preserve bounded partial evidence and usage while the finalized Pi tool result is marked as an error. Abort, timeout, session replacement, and shutdown use the existing process-tree termination and temporary-file cleanup path.
|
|
265
|
+
|
|
172
266
|
## 🚀 Blocking batch examples
|
|
173
267
|
|
|
174
268
|
Every example in this section calls `subagent` and keeps the main agent unavailable until the batch
|
|
@@ -258,14 +352,12 @@ Auto-resume is best-effort because Pi's custom-message API is fire-and-forget. S
|
|
|
258
352
|
The default `subprocess` transport preserves compatibility: each turn starts a fresh isolated `pi --mode json -p --no-session` child and receives sanitized, bounded history. Set `transport` to `in-process` to retain one public Pi SDK `AgentSession` per stateful `agentId`, avoiding repeated process startup while preserving native child history in memory.
|
|
259
353
|
|
|
260
354
|
Run `/subagents` in TUI mode to open the standard primary manager. It leads with the current
|
|
261
|
-
delegation workflow, human-readable async completion behavior, and active/retained counts. **Change
|
|
262
|
-
delegation**, **Current agents**, and **Completion behavior** cover the common workflows; agent
|
|
263
|
-
permissions, transport/runtime details, source, and settings path remain under **Advanced settings**.
|
|
355
|
+
delegation workflow, human-readable async completion behavior, consultation/delegation target policies, consultation-resource policy, and active/retained counts. **Change delegation**, **Current agents**, and **Settings** cover the common workflows; agent permissions, transport/runtime details, source, and settings path remain under **Advanced settings**.
|
|
264
356
|
Escape returns from a nested screen to a newly refreshed manager; Ctrl+C closes the full flow.
|
|
265
357
|
Exact workflow/reload and project-agent safety confirmations remain extension-owned because they
|
|
266
358
|
guard live agent and trust-boundary policy rather than ordinary navigation.
|
|
267
359
|
|
|
268
|
-
The direct routes remain predictable: `/subagents settings` changes
|
|
360
|
+
The direct routes remain predictable: `/subagents settings` changes both target policies, consultation resources, and completion delivery and applies them immediately, including refreshing model-facing tool guidance; `/subagents status` reports current-session runtime values separately from configured values, per-field sources, and path; `/subagents help` summarizes the single-command interface and the non-sandbox limitation. In RPC mode, bare `/subagents` emits the same bounded status through Pi's notification protocol instead of opening a custom TUI. JSON and print modes do not emit ad hoc command output. Manual edits use `~/.pi/agent/pi-subagents.json` and take effect after reloading Pi:
|
|
269
361
|
|
|
270
362
|
```json
|
|
271
363
|
{
|
|
@@ -285,11 +377,18 @@ The direct routes remain predictable: `/subagents settings` changes user complet
|
|
|
285
377
|
"idleTtlMs": 3600000,
|
|
286
378
|
"retentionDays": 30,
|
|
287
379
|
"maxStoredAgents": 50
|
|
380
|
+
},
|
|
381
|
+
"cwdPolicy": {
|
|
382
|
+
"consultation": "anywhere",
|
|
383
|
+
"delegation": "trusted-targets"
|
|
384
|
+
},
|
|
385
|
+
"consult": {
|
|
386
|
+
"resources": "project-context"
|
|
288
387
|
}
|
|
289
388
|
}
|
|
290
389
|
```
|
|
291
390
|
|
|
292
|
-
The settings UI patches the raw JSON atomically and preserves unknown fields; it refuses to overwrite malformed or invalid settings. Supported Pi writers serialize the latest-document read and same-directory temporary-file rename through `pi-subagents.json.mutation-lock`. Editors and older extension versions do not participate in that lock, so avoid manual edits while a settings save is in progress. `blocking.enabled` defaults to `true`; set it to `false` for async-only delegation. `stateful.enabled` also defaults to `true`; its existing `false` value remains the blocking-only workflow. When stateful tools are enabled, their membership stays fixed across spawn, completion, interrupt, close, and mailbox transitions. This avoids lifecycle-driven tool-schema churn and preserves a stable provider prompt prefix for KV caching.
|
|
391
|
+
The settings UI patches the raw JSON atomically and preserves unknown fields; it refuses to overwrite malformed or invalid settings. Supported Pi writers serialize the latest-document read and same-directory temporary-file rename through `pi-subagents.json.mutation-lock`. Editors and older extension versions do not participate in that lock, so avoid manual edits while a settings save is in progress. `blocking.enabled` defaults to `true`; set it to `false` for async-only delegation. `stateful.enabled` also defaults to `true`; its existing `false` value remains the blocking-only workflow. `cwdPolicy.consultation` defaults to `"anywhere"`, `cwdPolicy.delegation` defaults to `"trusted-targets"`, and `consult.resources` defaults to `"project-context"`. The Settings UI applies a saved change immediately to subsequent launches and refreshes the affected tool descriptions; manual edits take effect on session start or `/reload`. The UI explicitly states that target/trust settings are not filesystem sandboxing and directs trust changes to Pi `/trust`. When stateful tools are enabled, their membership stays fixed across spawn, completion, interrupt, close, and mailbox transitions. This avoids lifecycle-driven tool-schema churn and preserves a stable provider prompt prefix for KV caching.
|
|
293
392
|
|
|
294
393
|
| Tool | Purpose |
|
|
295
394
|
| --- | --- |
|
|
@@ -318,7 +417,7 @@ The action schemas are flat for provider compatibility and reject parameters tha
|
|
|
318
417
|
|
|
319
418
|
Use the **Current agents** action in `/subagents` to inspect the indented agent tree, lifecycle state, unread count, and available actions, or to confirm clearing retained agents. Active turns are FIFO-limited by `maxActiveTurns`; excess retained work remains in `starting` state until a slot is available. `maxAgents` separately bounds running, queued, and idle records. `parentId` creates a bounded child relationship; subtree interrupt and close operate child-first.
|
|
320
419
|
|
|
321
|
-
### Migrating from the seven-tool lifecycle surface
|
|
420
|
+
### Migrating from the previous seven-tool lifecycle surface
|
|
322
421
|
|
|
323
422
|
The five replaced names are intentionally not registered as aliases. Update explicit prompts and integrations as follows:
|
|
324
423
|
|
|
@@ -359,7 +458,7 @@ Stateful execution uses a transport boundary:
|
|
|
359
458
|
|
|
360
459
|
- `subprocess` is the default compatibility and rollback path.
|
|
361
460
|
- `in-process` uses only public Pi SDK APIs: `createAgentSession()`, `SessionManager.inMemory()`, `DefaultResourceLoader`, and normal session lifecycle methods. It isolates conversation/tool selection, not memory or crashes; child failures share the parent Node.js process.
|
|
362
|
-
- Child resource loading sets `noExtensions: true`, preventing recursive `pi-subagents` loading and duplicate extension side effects while retaining
|
|
461
|
+
- Child resource loading sets `noExtensions: true`, preventing recursive `pi-subagents` loading and duplicate extension side effects while retaining trust-eligible context/skill resources and the selected agent prompt. Both transports receive the same resolved target-trust boolean: subprocess children get explicit `--approve`/`--no-approve`, and in-process children set the same `SettingsManager.projectTrusted` value.
|
|
363
462
|
- Agent model, thinking level, and built-in tool allow-list overrides are applied when the child is created. Parent model/thinking changes are snapshotted for subsequently created children; an existing child keeps its own session configuration.
|
|
364
463
|
- Extension/custom tool names are rejected in-process with an actionable recommendation to use `subprocess`; permissions are never silently widened.
|
|
365
464
|
- Timeout, parent abort, close, expiry, and session shutdown abort/dispose owned child sessions. A child that does not settle after abort grace is discarded rather than reused.
|
|
@@ -369,11 +468,11 @@ No private Pi imports, runtime casts, or `ExtensionAPI` monkey-patching are used
|
|
|
369
468
|
|
|
370
469
|
Write-capable agents share the workspace by default. Concurrent write-capable starts in the same cwd are rejected unless `allowConcurrentWrites` is explicitly set. Classification is intentionally conservative: an agent with `bash`, `write`, or `edit` is write-capable even when its task prompt says “read only,” because prompt wording is not a filesystem sandbox. Prefer one detached agent when asynchronous work can be combined. If concurrent work is genuinely required, use the blocking batch only when synchronous outputs justify making the root unavailable, explicitly accept safe detached overlap with `allowConcurrentWrites`, or use isolated worktrees when repository isolation is needed.
|
|
371
470
|
|
|
372
|
-
Set `workspaceMode: "worktree"` to opt into a disposable detached Git worktree; this requires a clean repository and the worktree is removed on close or session shutdown.
|
|
471
|
+
Set `workspaceMode: "worktree"` to opt into a disposable detached Git worktree; this requires a clean repository and the worktree is removed on close or session shutdown. The generated path inherits the approved base cwd's trust snapshot. Retained records mark disposable worktrees explicitly, so they are never restored even if cleanup could not remove the generated directory. Shared-workspace retained records store an additive bounded target-trust snapshot for transport and inspection parity; session restore canonicalizes the retained cwd and re-resolves current/saved trust rather than blindly trusting the persisted value. Older records without either field remain readable.
|
|
373
472
|
|
|
374
473
|
## 📜 Compatibility and failure contract
|
|
375
474
|
|
|
376
|
-
Existing `subagent`
|
|
475
|
+
Existing `subagent` input schemas remain unchanged. The intentional compatibility change is that an external target without saved trust is rejected by the new default `cwdPolicy.delegation: "trusted-targets"`; set the user-owned policy to `"anywhere"` to restore the preceding target flexibility.
|
|
377
476
|
|
|
378
477
|
| Mode | Ordering | Failure behavior |
|
|
379
478
|
| --- | --- | --- |
|
|
@@ -385,7 +484,7 @@ Existing `subagent` requests remain unchanged:
|
|
|
385
484
|
An aggregator whose `agent` or `task` is empty or whitespace-only is treated as absent, so successful
|
|
386
485
|
parallel outputs remain available instead of being replaced by a malformed fan-in failure.
|
|
387
486
|
|
|
388
|
-
Timeout precedence remains: task/step/aggregator → call → agent setting → `PI_SUBAGENT_TIMEOUT_MS` → 600000 ms. Blocking thinking precedence remains: task/step/aggregator → call → agent setting → child default. Stateful spawn thinking precedence is: `subagent_spawn.thinkingLevel` → agent setting → transport fallback. Project-agent resolution and confirmation behavior is unchanged.
|
|
487
|
+
Timeout precedence remains: task/step/aggregator → call → agent setting → `PI_SUBAGENT_TIMEOUT_MS` → 600000 ms. Blocking thinking precedence remains: task/step/aggregator → call → agent setting → child default. Stateful spawn thinking precedence is: `subagent_spawn.thinkingLevel` → agent setting → transport fallback. Project-agent resolution and confirmation behavior is unchanged after target preflight. Blocking and retained result/inspection details add bounded target boundary and effective trust metadata.
|
|
389
488
|
|
|
390
489
|
## 🤖 Built-in agents
|
|
391
490
|
|
|
@@ -418,7 +517,7 @@ Compatibility: a valid legacy `pi-subagents-config.json` remains readable with a
|
|
|
418
517
|
- Choose **Save changes** to write the draft, choose **Discard draft** to abandon it, or press Esc to
|
|
419
518
|
return to agent selection without writing.
|
|
420
519
|
- Save the default selection to remove a custom override and use the agent defaults again.
|
|
421
|
-
- Deselect every tool and save to run that agent with no tools.
|
|
520
|
+
- Deselect every tool and save to run that agent with no tools. An explicit empty list remains distinct from an absent list; blank `tools:` or `tools: []` in agent frontmatter also means no tools.
|
|
422
521
|
|
|
423
522
|
Configured tool names that are not currently registered are preserved, so settings for tools from
|
|
424
523
|
other extension sessions are not silently dropped.
|
|
@@ -445,6 +544,8 @@ You are an API review subagent. Do not edit files. Check compatibility,
|
|
|
445
544
|
test coverage, and migration risks. Report PASS/FAIL/PARTIAL with evidence.
|
|
446
545
|
```
|
|
447
546
|
|
|
547
|
+
`tools` accepts either the comma-separated form above or a YAML string array such as `tools: [read, grep]`. An omitted field keeps the agent's default tools; blank, `null`, or `[]` explicitly selects no tools.
|
|
548
|
+
|
|
448
549
|
`agentScope` is a top-level tool argument supplied per invocation. It is not a setting in
|
|
449
550
|
`~/.pi/agent/pi-subagents.json` and does not belong in agent frontmatter. The parent-facing tool
|
|
450
551
|
metadata discovers these definitions after session start and labels their source and required scope.
|
|
@@ -491,6 +592,7 @@ Each subprocess has a hard timeout to avoid runaway workers.
|
|
|
491
592
|
|
|
492
593
|
- Set `timeoutMs` on the top-level call to apply a default for all jobs.
|
|
493
594
|
- Set `timeoutMs` on a task, chain step, or aggregator to override it locally.
|
|
595
|
+
- Valid timeout values range from 1 to 2,147,483,647 milliseconds, matching the runtime timer limit.
|
|
494
596
|
- If omitted, the default is `PI_SUBAGENT_TIMEOUT_MS`, or `600000` milliseconds (10 minutes) when unset.
|
|
495
597
|
|
|
496
598
|
Set `thinkingLevel` to request one of Pi's supported levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max`. Blocking subprocess calls pass the resolved value through `--thinking <level>`.
|
|
@@ -520,7 +622,7 @@ The child event protocol limits each JSON line to 256 KiB. Captured output uses
|
|
|
520
622
|
- stderr: 16 KiB;
|
|
521
623
|
- captured messages: 200.
|
|
522
624
|
|
|
523
|
-
Truncated text includes a `truncated by pi-subagents` marker and details expose `truncated: true`. `PI_SUBAGENT_MAX_DEPTH` controls nested delegation depth and defaults to 1; child processes receive `PI_SUBAGENT_DEPTH` automatically.
|
|
625
|
+
Truncated text includes a `truncated by pi-subagents` marker and details expose `truncated: true`. Inspection and consultation model-facing content also stops at 2,000 lines, whichever limit is reached first. `PI_SUBAGENT_MAX_DEPTH` controls nested delegation depth and defaults to 1; child processes receive `PI_SUBAGENT_DEPTH` automatically.
|
|
524
626
|
|
|
525
627
|
## 📡 Runtime status
|
|
526
628
|
|
|
@@ -528,7 +630,7 @@ While the `subagent` tool is running, `pi-subagents` publishes compact activity
|
|
|
528
630
|
|
|
529
631
|
## 🔒 Safety notes
|
|
530
632
|
|
|
531
|
-
Subagents have separate processes and context windows, but they are **not security sandboxes**. They run as the same OS user, share the host filesystem and network access, and may conflict if they edit the same files. Tool allow-lists reduce available Pi tools but do not reduce operating-system permissions.
|
|
633
|
+
Subagents have separate processes and context windows, but they are **not security sandboxes**. They run as the same OS user, share the host filesystem and network access, and may conflict if they edit the same files. Tool allow-lists reduce available Pi tools but do not reduce operating-system permissions. `subagent_consult` prevents writes through its Pi tool surface and disables extensions, but it can read accessible paths, call the configured model over the network, and incur cost; its instruction-resource policy is not a filesystem or confidentiality boundary.
|
|
532
634
|
|
|
533
635
|
The runner explicitly reports policy continuity in result details:
|
|
534
636
|
|
|
@@ -547,16 +649,24 @@ extensions/pi-subagents/
|
|
|
547
649
|
├── src/
|
|
548
650
|
│ ├── index.ts # Pi package entrypoint
|
|
549
651
|
│ ├── subagents.ts # Extension registration and blocking tool schema
|
|
652
|
+
│ ├── inspect.ts # Side-effect-free metadata inspection tool
|
|
653
|
+
│ ├── consult.ts # Synchronous read-only consultation tool
|
|
654
|
+
│ ├── consult-policy.ts # Enforced read-only tool intersection
|
|
655
|
+
│ ├── cwd-policy.ts # Canonical target and saved-trust resolution
|
|
656
|
+
│ ├── safe-text.ts # Shared byte/line/path sanitization
|
|
550
657
|
│ ├── stateful.ts # Detached lifecycle registration and dispatch
|
|
658
|
+
│ ├── stateful-guidance.ts # Detached model-facing workflow guidance
|
|
659
|
+
│ ├── stateful-lifecycle.ts # Runtime disposal and spawn ownership guards
|
|
660
|
+
│ ├── stateful-safety.ts # Project-agent and shared-write safety checks
|
|
551
661
|
│ ├── stateful-tool-params.ts # Consolidated action schemas and validation
|
|
552
|
-
│ └── *.ts # Package-local discovery, execution, rendering, and
|
|
662
|
+
│ └── *.ts # Package-local discovery, execution, rendering, and settings modules
|
|
553
663
|
├── README.md
|
|
554
664
|
├── LICENSE
|
|
555
665
|
├── tsconfig.json
|
|
556
666
|
└── package.json
|
|
557
667
|
```
|
|
558
668
|
|
|
559
|
-
`index.ts` is the Pi entrypoint and forwards to `subagents.ts`; the other source modules are internal. Workflow settings remain backward compatible: older files without `blocking.enabled`
|
|
669
|
+
`index.ts` is the Pi entrypoint and forwards to `subagents.ts`; the other source modules are internal. Workflow settings remain backward compatible: older files without `blocking.enabled` receive the seven-tool default, existing `stateful.enabled: false` files expose blocking delegation plus inspection/consultation, and older package releases ignore and preserve the optional `consult` and `cwdPolicy` objects. The package exposes its Pi extension through `package.json`:
|
|
560
670
|
|
|
561
671
|
```json
|
|
562
672
|
{
|
package/package.json
CHANGED
package/src/agents.ts
CHANGED
|
@@ -41,6 +41,29 @@ export type SubagentTransportKind = "subprocess" | "in-process";
|
|
|
41
41
|
|
|
42
42
|
export type CompletionDelivery = "next-turn" | "auto-resume";
|
|
43
43
|
|
|
44
|
+
export const CONSULT_RESOURCE_POLICIES = ["project-context", "none", "all"] as const;
|
|
45
|
+
|
|
46
|
+
export type ConsultResourcePolicy = (typeof CONSULT_RESOURCE_POLICIES)[number];
|
|
47
|
+
|
|
48
|
+
export interface SubagentConsultSettings {
|
|
49
|
+
resources?: ConsultResourcePolicy;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const CONSULTATION_CWD_POLICIES = ["anywhere", "current-workspace"] as const;
|
|
53
|
+
export type ConsultationCwdPolicy = (typeof CONSULTATION_CWD_POLICIES)[number];
|
|
54
|
+
|
|
55
|
+
export const DELEGATION_CWD_POLICIES = [
|
|
56
|
+
"trusted-targets",
|
|
57
|
+
"current-workspace",
|
|
58
|
+
"anywhere",
|
|
59
|
+
] as const;
|
|
60
|
+
export type DelegationCwdPolicy = (typeof DELEGATION_CWD_POLICIES)[number];
|
|
61
|
+
|
|
62
|
+
export interface SubagentCwdPolicySettings {
|
|
63
|
+
consultation?: ConsultationCwdPolicy;
|
|
64
|
+
delegation?: DelegationCwdPolicy;
|
|
65
|
+
}
|
|
66
|
+
|
|
44
67
|
export interface SubagentBlockingSettings {
|
|
45
68
|
enabled?: boolean;
|
|
46
69
|
}
|
|
@@ -64,6 +87,8 @@ export interface SubagentSettings {
|
|
|
64
87
|
agents?: Record<string, SubagentAgentConfig>;
|
|
65
88
|
blocking?: SubagentBlockingSettings;
|
|
66
89
|
stateful?: SubagentRuntimeSettings;
|
|
90
|
+
consult?: SubagentConsultSettings;
|
|
91
|
+
cwdPolicy?: SubagentCwdPolicySettings;
|
|
67
92
|
}
|
|
68
93
|
|
|
69
94
|
const BUILT_IN_AGENTS: AgentConfig[] = [
|
|
@@ -238,20 +263,36 @@ function loadAgentsFromDir(
|
|
|
238
263
|
continue;
|
|
239
264
|
}
|
|
240
265
|
|
|
241
|
-
const { frontmatter, body } = parseFrontmatter<Record<string,
|
|
266
|
+
const { frontmatter, body } = parseFrontmatter<Record<string, unknown>>(loaded.content);
|
|
242
267
|
|
|
243
|
-
if (
|
|
268
|
+
if (typeof frontmatter.name !== "string" || typeof frontmatter.description !== "string") {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
244
271
|
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
272
|
+
const hasTools = hasOwn(frontmatter, "tools");
|
|
273
|
+
const rawTools = frontmatter.tools;
|
|
274
|
+
let tools: string[] | undefined;
|
|
275
|
+
if (hasTools) {
|
|
276
|
+
if (rawTools === null) {
|
|
277
|
+
tools = [];
|
|
278
|
+
} else if (Array.isArray(rawTools)) {
|
|
279
|
+
if (!rawTools.every((tool): tool is string => typeof tool === "string")) continue;
|
|
280
|
+
tools = rawTools.map((tool) => tool.trim()).filter(Boolean);
|
|
281
|
+
} else if (typeof rawTools === "string") {
|
|
282
|
+
tools = rawTools
|
|
283
|
+
.split(",")
|
|
284
|
+
.map((tool) => tool.trim())
|
|
285
|
+
.filter(Boolean);
|
|
286
|
+
} else {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
249
290
|
|
|
250
291
|
agents.push({
|
|
251
292
|
name: frontmatter.name,
|
|
252
293
|
description: frontmatter.description,
|
|
253
|
-
|
|
254
|
-
model: frontmatter.model,
|
|
294
|
+
...(hasTools ? { tools: tools ?? [] } : {}),
|
|
295
|
+
model: typeof frontmatter.model === "string" ? frontmatter.model : undefined,
|
|
255
296
|
thinkingLevel: isThinkingLevel(frontmatter.thinkingLevel)
|
|
256
297
|
? frontmatter.thinkingLevel
|
|
257
298
|
: undefined,
|