pi-neo-subagents 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0] — 2026-10-24
8
+
9
+ First public release. Covers the v1 delegation core and the v2 governance work.
10
+
11
+ ### Added — delegation core
12
+
13
+ - Named agent definitions as Markdown + frontmatter in `.pi/agents/` (project)
14
+ and `~/.pi/agent/agents/` (user), with project-over-user precedence.
15
+ - `task` tool for the main agent: isolated nested sessions, self-contained task
16
+ text only, final reply returned as the tool result.
17
+ - `/subagents` listing and detail views, and `/subagents run <name> [--to-context] <task>`
18
+ for user-invoked delegation whose result stays out of the model's context by
19
+ default.
20
+ - Definition enforcement: tool whitelists, model overrides, `systemPrompt: replace`.
21
+ - Result contract: 30,000-character truncation with the full result written to a
22
+ temp file, structured details, merged usage, coarse progress updates.
23
+ - Non-interactive output routing: stdout in print mode, stderr in JSON mode,
24
+ notifications in TUI and RPC.
25
+ - `create_subagent` tool and project-first placement, so a session with no
26
+ definitions is never a dead end.
27
+
28
+ ### Added — governance and scale (v2)
29
+
30
+ - Execution controls: `maxTurns`, `timeoutMs`, `maxTokens`, and `thinking` in a
31
+ definition or per call; cut-short work is reported as a budget stop, never as
32
+ a failure.
33
+ - Run ledger with `/subagents stats` and `stats reset`.
34
+ - Fan-out dispatch (`tasks`) with a configurable concurrency cap, submission
35
+ order results, per-task status, and cancellation of everything in flight.
36
+ - Chained dispatch (`chain`) with `{previous}` substitution and stop-at-first-
37
+ unfinished-step semantics.
38
+ - Ad-hoc delegation with inline `instructions`, no definition file, accounted as
39
+ `ad-hoc`.
40
+ - Live TUI widget listing in-flight delegations with turn and current tool.
41
+ - Strict definition validation: non-`replace` `systemPrompt`, unknown tools,
42
+ unresolvable models, and invalid budgets are errors.
43
+ - Discovery from nested working directories; listings show source file and
44
+ modification time.
45
+ - Managed definitions: `/subagents new`, `edit`, `rm`.
46
+ - Authorization: project-level agents require first-use consent, plus settings
47
+ `confirmProjectAgents`, `allowModelCreatedDefinitions`,
48
+ `allowUserScopeCreation`, and `maxDepth`.
49
+ - Controlled recursion: opt-in `allowSubagents`, depth-bounded, with depth
50
+ reported in results and the ledger.
51
+ - Hermetic test suite (112 tests) over a single session seam, plus an
52
+ environment-gated live-model smoke suite (`npm run test:live`).
53
+
54
+ ### Notes
55
+
56
+ - Delegation is serial per call unless `tasks` is used; nesting requires an
57
+ explicit opt-in.
58
+ - `@earendil-works/pi-ai` and `@earendil-works/pi-coding-agent` are host-provided
59
+ and declared as `peerDependencies` with a `*` range.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 灰木同学
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,332 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # pi-neo-subagents
2
+
3
+ Subagents for [Pi](https://github.com/earendil-works/pi): define named specialist
4
+ agents as Markdown files, then let the main agent delegate self-contained tasks
5
+ to them — or run them yourself. Each delegation runs in an isolated nested
6
+ session with its own conversation, so your main context stays small and focused.
7
+
8
+ ```bash
9
+ pi install npm:pi-neo-subagents
10
+ ```
11
+
12
+ - **Delegate**: a `task` tool the main agent calls, single / fan-out / chained,
13
+ with per-run budgets and a run ledger.
14
+ - **Define**: Markdown definitions with tool whitelists, model overrides, and an
15
+ opt-in for controlled recursion — project-first, reviewable in your repo.
16
+ - **Run**: `/subagents list|run|new|edit|rm|stats` for doing it yourself.
17
+
18
+ ## Install
19
+
20
+ From npm:
21
+
22
+ ```bash
23
+ pi install npm:pi-neo-subagents # user-level
24
+ pi install npm:pi-neo-subagents -l # project-level (needs project trust)
25
+ ```
26
+
27
+ From a directory or a single file (TypeScript, no build step):
28
+
29
+ ```bash
30
+ pi install /path/to/pi-neo-subagents
31
+ pi --extension /path/to/pi-neo-subagents/index.ts
32
+ ```
33
+
34
+ Project-level installs land in `.pi/settings.json`, which Pi only honours after
35
+ project trust is granted — start Pi with `--approve` (or trust the project
36
+ interactively) or the package will appear to be ignored. It can also live under
37
+ `~/.pi/agent/extensions/` or `<project>/.pi/extensions/` for discovery.
38
+
39
+ To publish to npm, remove `"private": true` from `package.json` and add the
40
+ `pi-package` keyword; the `pi.extensions` manifest is already declared.
41
+
42
+ ## Agent definitions
43
+
44
+ Definitions are Markdown files with YAML-style frontmatter in two resource
45
+ directories:
46
+
47
+ - project-level: `.pi/agents/*.md` (wins on a name collision, labelled in listings).
48
+ Discovery walks up from the working directory to the nearest `.pi/agents`, so
49
+ running Pi inside a subdirectory still finds the repository's agents.
50
+ - user-level: `~/.pi/agent/agents/*.md`
51
+
52
+ ```markdown
53
+ ---
54
+ description: Reviews code changes
55
+ tools: read, grep
56
+ model: anthropic/claude-sonnet-4-5
57
+ systemPrompt: replace
58
+ ---
59
+
60
+ You are a careful code reviewer. Always cite the file you reviewed.
61
+ ```
62
+
63
+ | Field | Meaning | Default |
64
+ |---|---|---|
65
+ | `name` | Canonical agent name | the file's stem |
66
+ | `description` | One-line description used for delegation discovery | required |
67
+ | `tools` | Whitelist of tool names for the subagent | all default tools |
68
+ | `model` | Model to run on (`provider/id` or bare id) | inherit the host session's model |
69
+ | `systemPrompt` | `replace` makes the body the entire system prompt | append to Pi's default prompt |
70
+ | `maxTurns` | Cap on assistant turns for one delegation | unbounded |
71
+ | `timeoutMs` | Wall-clock cap in milliseconds | unbounded |
72
+ | `maxTokens` | Cap on total tokens for one delegation | unbounded |
73
+ | `thinking` | Thinking level (`minimal`, `low`, `medium`, `high`, `xhigh`, `max`) | inherit |
74
+ | `allowSubagents` | `true` lets this agent delegate further with the `task` tool | `false` |
75
+
76
+ Frontmatter accepts both `tools: read, grep` and YAML block lists:
77
+
78
+ ```markdown
79
+ tools:
80
+ - read
81
+ - grep
82
+ ```
83
+
84
+ Quoted values and trailing `# comments` are handled. Definition mistakes fail
85
+ loudly instead of silently changing behaviour:
86
+
87
+ - `tools:` present but empty → error (it used to mean "all default tools")
88
+ - an unterminated quoted value → error
89
+ - a `systemPrompt` value other than `replace` → error (omitting it still means append)
90
+ - at creation time: an unregistered tool name, an unresolvable model, an
91
+ invalid budget, or the `task` tool (subagents never delegate further) → error
92
+ - two definitions with the same `name` in one directory → the later file is
93
+ rejected with a duplicate-name error
94
+
95
+ The Markdown body is the agent's specialization instructions.
96
+
97
+ ## Creating definitions
98
+
99
+ You can write definition files by hand, or let the agent do it. The
100
+ `create_subagent` tool takes `{ name, description, instructions, tools?, model?,
101
+ scope?, overwrite? }` and owns the file format and location:
102
+
103
+ - **`scope: "project"` (default)** → `<cwd>/.pi/agents/<name>.md`, so the
104
+ definition travels with the repository and can be reviewed and committed.
105
+ - `scope: "user"` → `~/.pi/agent/agents/<name>.md`, only when explicitly asked.
106
+ - Existing definitions are never replaced unless `overwrite: true`; names that
107
+ would escape the agents directory are rejected; the generated file is
108
+ validated before it is written.
109
+ - A newly created definition is delegable immediately in the same session.
110
+
111
+ Asking for "one subagent reviews the pending diff, one scans the repo for TODOs"
112
+ in a project with no definitions therefore produces `reviewer.md` and
113
+ `scout.md` **inside the project**, not in your global config.
114
+
115
+ ## Budgets
116
+
117
+ A delegation can be capped by turns, wall-clock time, and tokens — in the
118
+ definition, or per call (a per-call value wins):
119
+
120
+ ```jsonc
121
+ // task tool call
122
+ { "agent": "scout", "task": "…", "maxTurns": 3, "timeoutMs": 60000, "thinking": "low" }
123
+ ```
124
+
125
+ Hitting a cap is a first-class outcome, not a failure: the subagent's reply so
126
+ far comes back with a note naming the budget that tripped, for example
127
+ `[Budget stop: turns limit 1 reached (observed 1). Partial reply above.]`.
128
+ Cut-short work stays distinguishable from a failed delegation, and the usage
129
+ footer still reports what it cost.
130
+
131
+ ## Delegate from the main agent
132
+
133
+ The `task` tool lists every available agent in its description, names both
134
+ definition directories, and says project definitions are preferred. The main
135
+ agent delegates with a **self-contained** task description — the subagent sees the task
136
+ text only, never the host conversation. Its final reply comes back as the tool
137
+ result (oversized replies are truncated at 30,000 characters with the full
138
+ result written to a temp file).
139
+
140
+ ### Fan-out
141
+
142
+ One call can dispatch several tasks concurrently:
143
+
144
+ ```jsonc
145
+ { "tasks": [
146
+ { "agent": "reviewer", "task": "Review the diff of src/ for bugs" },
147
+ { "agent": "scout", "task": "Find every TODO under src/", "maxTurns": 4 }
148
+ ] }
149
+ ```
150
+
151
+ - Results come back **in submission order**, each as its own block with its
152
+ status (`ok`, `budget stop (…)`, `failed`) and details.
153
+ - One failing task does not cancel its siblings; the call is an error only when
154
+ every task failed.
155
+ - Concurrency is capped at 4 by default; set
156
+ `PI_NEO_SUBAGENTS_MAX_CONCURRENCY=<n>` to change it.
157
+ - Cancelling the call cancels every in-flight task.
158
+ - A single `{ agent, task }` call behaves exactly as before.
159
+ - In the TUI, a widget lists every in-flight delegation with its current turn
160
+ and tool, and clears when the dispatch settles. Other modes never show it.
161
+
162
+ ### One-off work, without a definition
163
+
164
+ For work you will not reuse, an entry can carry inline instructions instead of an
165
+ agent name:
166
+
167
+ ```jsonc
168
+ { "instructions": "You read one file and summarize it in three bullets.",
169
+ "tools": ["read"],
170
+ "task": "Summarize docs/specs/subagents.md" }
171
+ ```
172
+
173
+ - Nothing is written to disk and nothing appears in `/subagents`; the run is
174
+ still counted in `/subagents stats` under the fixed label `ad-hoc`.
175
+ - Inline entries accept the same `model`, budget, and `tools` options as a
176
+ definition, work in single, fan-out, and chain dispatch, and can never spawn
177
+ further subagents.
178
+
179
+ ### Controlled recursion
180
+
181
+ By default a subagent cannot delegate further. A definition can opt in:
182
+
183
+ ```markdown
184
+ ---
185
+ description: Plans work and delegates the parts
186
+ allowSubagents: true
187
+ tools: read, task
188
+ ---
189
+ ```
190
+
191
+ Opted-in agents receive the `task` tool in their nested session, and a depth
192
+ limit bounds the tree (`subagents.maxDepth`, default 2 — a top-level delegation
193
+ is depth 1). Exceeding it fails that call with the limit and the attempted
194
+ depth. Every result carries `details.depth`, and the ledger shows the deepest
195
+ level each agent ran at.
196
+
197
+ ### Chains
198
+
199
+ Steps can run in order, each able to consume the previous reply — a
200
+ review-then-fix pipeline, for example:
201
+
202
+ ```jsonc
203
+ { "chain": [
204
+ { "agent": "reviewer", "task": "Review src/runner.ts and list the problems" },
205
+ { "agent": "fixer", "task": "Fix exactly these problems, nothing else: {previous}" }
206
+ ] }
207
+ ```
208
+
209
+ - `{previous}` is replaced with the previous step's reply; using it in the first
210
+ step is rejected before anything runs.
211
+ - A chain stops at the first step that fails **or is cut short by a budget**;
212
+ remaining steps are reported as `skipped`, and the result names every step's
213
+ status.
214
+ - A chain is strictly sequential, so the fan-out cap does not apply.
215
+
216
+ Delegation is one level deep by default: the `task` tool is never available to
217
+ subagents themselves. Nested sessions also load no extensions, skills, prompt
218
+ templates, or themes, so a subagent's prompt is its definition plus the task —
219
+ never the host's skill index.
220
+
221
+ ## Run directly
222
+
223
+ ```
224
+ /subagents # list all definitions
225
+ /subagents <name> # show one definition
226
+ /subagents run <name> <task> # run one; result shown to you only
227
+ /subagents run --to-context <name> <task> # also send the result into the model's context
228
+ /subagents run "code review" <task> # quote names that contain spaces
229
+ /subagents run -- <name> <task> # anything after -- is taken literally
230
+ /subagents new <name> [description] [--force] # scaffold a definition in the resolved project dir
231
+ /subagents edit <name> # open the resolved file; invalid edits are not saved
232
+ /subagents rm <name> [--yes] # delete after confirmation (--yes for scripts)
233
+ /subagents stats # per-agent runs, turns, tokens, cost, average time
234
+ /subagents stats reset # clear this session's ledger
235
+ ```
236
+
237
+ The ledger is per session and accounts for every delegation — single, fan-out,
238
+ and chain steps — counting successes, failures, and budget stops separately:
239
+
240
+ ```
241
+ Delegation ledger (this session):
242
+ - reviewer: 1 run (1 ok, 0 failed, 0 budget stops) · 3 turns · tokens 647 in / 410 out · $0.000718 · avg 4616ms
243
+ - scout: 1 run (1 ok, 0 failed, 0 budget stops) · 2 turns · tokens 421 in / 221 out · $0.000411 · avg 2475ms
244
+ Total: 2 runs · $0.001130
245
+ ```
246
+
247
+ Options are parsed only before the name, so `--to-context` inside a task stays
248
+ part of the task text. Unknown options are rejected with the usage line.
249
+
250
+ Direct runs report a one-line usage summary (model, turns, tokens, cost). Long
251
+ results are shortened for display and the full text is written to a temp file
252
+ named in the notice.
253
+
254
+ ### Output channels
255
+
256
+ | Mode | Where command output goes |
257
+ |---|---|
258
+ | TUI | notification |
259
+ | RPC | `extension_ui_request` notification |
260
+ | `--print` | stdout |
261
+ | `--mode json` | stderr (stdout is the JSON event stream) |
262
+
263
+ Progress for a long direct run appears as a status line (`<agent> · turn N`) and
264
+ is cleared when the run finishes.
265
+
266
+ ## Windows / Git Bash
267
+
268
+ MSYS rewrites arguments that start with `/`, so passing a slash command on the
269
+ command line (`pi -p "/subagents"`) reaches Pi as
270
+ `D:/Program Files/Git/subagents`. Quote it differently or disable the rewrite for
271
+ that argument:
272
+
273
+ ```bash
274
+ MSYS2_ARG_CONV_EXCL='/subagents' pi -p "/subagents"
275
+ pi -p "//subagents" # MSYS strips one slash
276
+ ```
277
+
278
+ This does not affect typing commands inside the Pi TUI, RPC clients, cmd.exe, or
279
+ PowerShell.
280
+
281
+ ## Settings
282
+
283
+ Optional settings live under the `subagents` key of Pi's settings (global
284
+ `~/.pi/agent/settings.json` or project `.pi/settings.json`):
285
+
286
+ ```json
287
+ {
288
+ "subagents": {
289
+ "confirmProjectAgents": "ask",
290
+ "allowModelCreatedDefinitions": true,
291
+ "allowUserScopeCreation": false,
292
+ "maxDepth": 2
293
+ }
294
+ }
295
+ ```
296
+
297
+ | Setting | Meaning | Default |
298
+ |---|---|---|
299
+ | `confirmProjectAgents` | `"ask"`, `"allow"`, or `"deny"`: whether a project-level agent needs consent before its first use in a session | `"ask"` |
300
+ | `allowModelCreatedDefinitions` | whether the model may author definitions with `create_subagent` | `true` |
301
+ | `allowUserScopeCreation` | whether definitions may be written to the user-level directory | `false` |
302
+ | `maxDepth` | delegation depth limit (reserved for controlled recursion) | `2` |
303
+
304
+ Consent is remembered per agent for the session, and a denial runs nothing.
305
+ User-level agents and ad-hoc entries never prompt. In a session without a
306
+ dialog UI, `"ask"` proceeds (automation never hangs) while `"deny"` refuses.
307
+
308
+ ## Development
309
+
310
+ ```bash
311
+ npm install
312
+ npm test # vitest, hermetic: scripted fake model, no network
313
+ npm run typecheck
314
+ npm run test:live # live-model smoke suite (real provider, real cost)
315
+ ```
316
+
317
+ `npm test` is offline and never needs credentials. The live suite is excluded
318
+ from it and runs only through `npm run test:live`, which enables it with
319
+ `PI_NEO_SUBAGENTS_LIVE=1`:
320
+
321
+ - It uses the credentials Pi already has, so run `pi auth` first if needed.
322
+ - `PI_NEO_SUBAGENTS_LIVE_MODEL=provider/model` picks the model (default
323
+ `deepseek/deepseek-flash`).
324
+ - A missing model or provider fails loudly with instructions instead of
325
+ skipping, so a green run always means the real path worked.
326
+ - A full run costs roughly 25 seconds and a few thousand tokens: it creates two
327
+ definitions in a temp project, fans out to them, checks the files and the
328
+ ledger, and delegates one ad-hoc task to prove no definition is created.
329
+
330
+ Tests drive full in-memory agent sessions through the Pi SDK with pi-ai's
331
+ `fauxProvider` as the scripted model; behaviour is asserted only at the
332
+ session boundary (tool results, visible messages, recorded UI output).