@cr1ms0n/pi-subagent 0.9.0 → 0.10.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 +16 -2
- package/README.md +130 -672
- package/README.zh-CN.md +132 -0
- package/docs/DEVELOPMENT.md +124 -0
- package/docs/PLAN.md +2 -0
- package/docs/REFERENCE.md +436 -0
- package/docs/RELEASING.md +151 -32
- package/docs/ROADMAP.md +2 -0
- package/docs/SECURITY.md +17 -18
- package/package.json +9 -1
- package/skills/subagent/SKILL.md +8 -4
- package/src/config.ts +1 -1
- package/src/jev-router.ts +7 -11
- package/src/routing-policy.ts +26 -18
- package/src/routing-types.ts +4 -4
package/README.md
CHANGED
|
@@ -1,672 +1,130 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
pi
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
{
|
|
132
|
-
tasks: [
|
|
133
|
-
{ task: "Implement feature A", profile: "general", isolation: "worktree" },
|
|
134
|
-
{ task: "Implement feature B", profile: "general", isolation: "worktree" }
|
|
135
|
-
]
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Close the worktree loop after the run finishes:
|
|
139
|
-
{ action: "diff", id: "abc123", index: 0 } // inspect the patch
|
|
140
|
-
{ action: "apply", id: "abc123", index: 0 } // land as uncommitted changes in your checkout
|
|
141
|
-
{ action: "discard", id: "abc123", index: 1 } // drop worktree + branch
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
The `/subagents` overlay mirrors the worktree loop interactively: `s` steer,
|
|
145
|
-
`a` apply, `x` discard on the selected run.
|
|
146
|
-
|
|
147
|
-
## Side questions (`/btw`)
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
/btw does this repo have a rate limiter?
|
|
151
|
-
/btw # prompts for the question
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
`/btw` runs a one-off read-only subagent for _you_, not for the model. It uses
|
|
155
|
-
the same policy, budget, semaphore and process-lock machinery as any run, but
|
|
156
|
-
delivers its answer as a custom session entry, which does not participate in
|
|
157
|
-
LLM context. The main agent keeps working and never sees the question or the
|
|
158
|
-
answer — useful for checking something mid-task without derailing the
|
|
159
|
-
conversation or polluting the context window.
|
|
160
|
-
|
|
161
|
-
## Backends
|
|
162
|
-
|
|
163
|
-
Jev routing manages Pi-backed new dispatch only. A `backend: "codex"` or
|
|
164
|
-
`backend: "claude"` new task is refused before any selector or provider work,
|
|
165
|
-
including a backend inherited from agent frontmatter; the extension never
|
|
166
|
-
silently switches it to Pi. Existing Codex/Claude runs stay manageable:
|
|
167
|
-
`status`, `wait`, `cancel`, `steer`, `diff`, `apply` and `discard` all still
|
|
168
|
-
work. Provider diversity is not lost, because another provider's execution
|
|
169
|
-
model stays eligible through Pi once it is in your configured candidate list.
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
// Refused on new work. Use the Pi-backed path so Jev can route it.
|
|
173
|
-
{ task: "Summarize this module", backend: "codex", profile: "explore" }
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
The low-level SDK is a different contract: `runTasks`/`runSubagent` execute the
|
|
177
|
-
explicit `TaskSpec` you hand them, so embedding code can still select a backend
|
|
178
|
-
directly. Everything else (worktrees, process locks, depth limits, budgets,
|
|
179
|
-
orphan reclaim) is backend-agnostic and applies unchanged.
|
|
180
|
-
|
|
181
|
-
Capabilities differ, and **unsupported combinations are refused with an
|
|
182
|
-
explanation rather than silently ignored**: a dropped `max_cost` or unenforced
|
|
183
|
-
read-only profile would be a safety regression, not a minor degradation.
|
|
184
|
-
|
|
185
|
-
| | `pi` (default) | `codex` | `claude` |
|
|
186
|
-
| ------------------------------- | -------------- | ------------------------------------- | ---------------------- |
|
|
187
|
-
| `max_cost` | yes | **refused** (reports tokens, no cost) | yes (`total_cost_usd`) |
|
|
188
|
-
| read-only profile | tool allowlist | `--sandbox read-only` (OS-level) | `--allowedTools` |
|
|
189
|
-
| steering / graceful wrap-up | yes | **no** (no stdin channel) | **no** (one-shot) |
|
|
190
|
-
| `resume` | yes | yes | yes |
|
|
191
|
-
| `context:'fork'`, `fork_resume` | yes | **refused** | yes |
|
|
192
|
-
| `thinking` | yes | no | no |
|
|
193
|
-
| `output_schema` | yes | yes | yes |
|
|
194
|
-
|
|
195
|
-
A budget breach on a backend without steering hard-stops instead of asking the
|
|
196
|
-
child to wrap up. Codex's read-only sandbox is enforced by the OS, which is
|
|
197
|
-
stronger than a tool allowlist.
|
|
198
|
-
|
|
199
|
-
Agent frontmatter `backend:` remains a default. New extension-managed work rejects
|
|
200
|
-
any effective backend other than Pi, including a native backend inherited from an agent.
|
|
201
|
-
Direct SDK specs retain the backend capabilities listed above.
|
|
202
|
-
|
|
203
|
-
## Profiles
|
|
204
|
-
|
|
205
|
-
| Profile | Tools | Writes |
|
|
206
|
-
| ---------------------------- | ------------------------------------------------------- | ------------------------------------------- |
|
|
207
|
-
| `explore` (parallel default) | locally permitted read-only tools + Pi context tools | no project-file writes |
|
|
208
|
-
| `review` | same as explore | no project-file writes |
|
|
209
|
-
| `general` | Jev chooses from the full available locally permitted catalog + Pi context tools | yes for selected write-capable tools; unknown custom tools count as writable |
|
|
210
|
-
|
|
211
|
-
Jev chooses individual tool names, not a capability bundle. Candidates come
|
|
212
|
-
from the full available locally permitted catalog, not from the agent file's
|
|
213
|
-
`tools` defaults and not from the parent's currently active tools. An explicit
|
|
214
|
-
task `tools` list is a ceiling, and explore/review keep their read-only rule
|
|
215
|
-
regardless of what the selector returns. An empty selection never means "all
|
|
216
|
-
tools".
|
|
217
|
-
|
|
218
|
-
For the Pi backend, the context-management tools `new_context`,
|
|
219
|
-
`get_context_remaining`, `history`, and `notes` are added locally when the
|
|
220
|
-
parent exposes them, so they are never a selector question. They are
|
|
221
|
-
control-plane tools: they may update continuity notes or the remote context
|
|
222
|
-
window, but cannot modify the child checkout or run a shell command. This
|
|
223
|
-
exception also applies when a task supplies a narrower tool list, so Pi's
|
|
224
|
-
`contextManagement` remains usable for configured gateway models. Locally added
|
|
225
|
-
controls are reported in the route metadata.
|
|
226
|
-
|
|
227
|
-
The finalized tool set is passed to the child as Pi's `--tools` allowlist
|
|
228
|
-
(`--no-tools` for a true empty set). Pi 0.86.0 is the verified baseline for
|
|
229
|
-
built-in, extension and late-registered tool enforcement; a host that cannot
|
|
230
|
-
honor that allowlist is refused rather than silently weakened, and the extension
|
|
231
|
-
does not claim identical behavior on untested older releases. Before the real
|
|
232
|
-
task prompt is sent, the child is also asked to confirm the selected model and
|
|
233
|
-
the finalized tool names through a verified private startup command; if the host
|
|
234
|
-
cannot verify that command or the child cannot confirm both, the launch aborts
|
|
235
|
-
with a startup diagnostic instead of running with a broader tool set.
|
|
236
|
-
|
|
237
|
-
Parallel write-capable tasks sharing one checkout are rejected unless each uses
|
|
238
|
-
`isolation: "worktree"`, distinct `cwd`, or explicit `allow_shared_writes: true`.
|
|
239
|
-
|
|
240
|
-
## Configuration
|
|
241
|
-
|
|
242
|
-
Defaults can be overridden in `~/.pi/subagent.json` and per-field via env vars
|
|
243
|
-
(env wins over file):
|
|
244
|
-
|
|
245
|
-
| Setting | Env var | Default |
|
|
246
|
-
| ----------------------- | ------------------------------------- | ------------------------------------- |
|
|
247
|
-
| `maxTasksPerRun` | `PI_SUBAGENT_MAX_TASKS` | 8 |
|
|
248
|
-
| `maxActiveProcesses` | `PI_SUBAGENT_MAX_ACTIVE` | 4 |
|
|
249
|
-
| `maxQueuedTasks` | `PI_SUBAGENT_MAX_QUEUED` | 32 |
|
|
250
|
-
| `maxGlobalActive` | `PI_SUBAGENT_MAX_GLOBAL_ACTIVE` | 16 |
|
|
251
|
-
| `defaultTimeoutMs` | `PI_SUBAGENT_TIMEOUT_MS` | 900000 |
|
|
252
|
-
| `maxDepth` | `PI_SUBAGENT_MAX_DEPTH` | 2 |
|
|
253
|
-
| `killGraceMs` | `PI_SUBAGENT_KILL_GRACE_MS` | 3000 |
|
|
254
|
-
| `sessionDir` | `PI_SUBAGENT_SESSION_DIR` | `~/.pi/subagent-sessions` |
|
|
255
|
-
| `worktreeDir` | `PI_SUBAGENT_WORKTREE_DIR` | `~/.pi/subagent-worktrees` |
|
|
256
|
-
| `lockDir` | `PI_SUBAGENT_LOCK_DIR` | `~/.pi/subagent-locks` |
|
|
257
|
-
| `worktreeRetentionDays` | `PI_SUBAGENT_WORKTREE_RETENTION_DAYS` | unused (lifecycle GC) |
|
|
258
|
-
| `sessionRetentionDays` | `PI_SUBAGENT_SESSION_RETENTION_DAYS` | unused (lifecycle GC) |
|
|
259
|
-
| `lockRetentionDays` | `PI_SUBAGENT_LOCK_RETENTION_DAYS` | 7 |
|
|
260
|
-
| `taskDefaults` | — | none |
|
|
261
|
-
| `jevRouting` | - | required for new dispatch (see below) |
|
|
262
|
-
| `graceTurns` | `PI_SUBAGENT_GRACE_TURNS` | 2 |
|
|
263
|
-
| `stallAfterMs` | `PI_SUBAGENT_STALL_AFTER_MS` | 90000 |
|
|
264
|
-
| `stallKillAfterMs` | `PI_SUBAGENT_STALL_KILL_AFTER_MS` | 90000 |
|
|
265
|
-
| `maxRetries` | `PI_SUBAGENT_MAX_RETRIES` | 1 |
|
|
266
|
-
| `widget` | `PI_SUBAGENT_WIDGET` | `background` (`off` disables) |
|
|
267
|
-
| `notifications` | `PI_SUBAGENT_NOTIFICATIONS` | `batched` (`off` disables) |
|
|
268
|
-
| (bin) | `PI_SUBAGENT_BIN` | auto (`process.execPath` + CLI entry) |
|
|
269
|
-
|
|
270
|
-
### Jev routing
|
|
271
|
-
|
|
272
|
-
New subagent dispatches are selected by Jev, TypeSafe's structured-decision API,
|
|
273
|
-
against a dedicated candidate list you maintain in `~/.pi/subagent.json`. Fixed
|
|
274
|
-
routing is gone: a `modelPolicy` block produces a migration error, and an
|
|
275
|
-
explicit `model` or `fallback_models` on new work is rejected rather than
|
|
276
|
-
bypassing selection. Management actions (`status`, `wait`, `cancel`, `steer`,
|
|
277
|
-
`diff`, `apply`, `discard`) never call the selector and need no credential.
|
|
278
|
-
|
|
279
|
-
```json
|
|
280
|
-
{
|
|
281
|
-
"jevRouting": {
|
|
282
|
-
"selectorModel": "jev-latest",
|
|
283
|
-
"apiKeyEnv": "TYPESAFE_API_KEY",
|
|
284
|
-
"timeoutMs": 15000,
|
|
285
|
-
"models": [
|
|
286
|
-
{
|
|
287
|
-
"model": "<provider/model-id>",
|
|
288
|
-
"description": "<your characteristics notes, Chinese allowed>",
|
|
289
|
-
"thinking": "<optional opaque Pi thinking default>"
|
|
290
|
-
}
|
|
291
|
-
]
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
- `selectorModel` defaults to the stable alias `jev-latest`. Pin an exact
|
|
297
|
-
version to control which selector version is requested. This does not guarantee
|
|
298
|
-
deterministic choices; the extension records the version that actually answered.
|
|
299
|
-
- `apiKeyEnv` defaults to `TYPESAFE_API_KEY`. Only the variable *name* lives in
|
|
300
|
-
the file. Set the credential in your local environment; the extension reads it
|
|
301
|
-
at request time and never writes it to config, prompts, argv, logs or results.
|
|
302
|
-
- `timeoutMs` defaults to 15000 and must be an integer between 100 and 600000.
|
|
303
|
-
It bounds one logical task selection, including all its HTTP requests and queue
|
|
304
|
-
waits. Parallel workers each have a selection allowance, still capped by their
|
|
305
|
-
absolute task `timeout_ms` deadline. Deferred synthesis has a separate allowance.
|
|
306
|
-
- `models` holds 1 to 255 entries, each with an exact `provider/model-id` and a
|
|
307
|
-
non-blank description. Those descriptions are what Jev matches against your
|
|
308
|
-
task, so write them the way you would explain the model to a colleague.
|
|
309
|
-
`thinking` is optional.
|
|
310
|
-
|
|
311
|
-
Plan and background-start native usage attachments are limited to 1024 selector
|
|
312
|
-
HTTP receipts per invocation. Larger requests fail with a request-splitting error;
|
|
313
|
-
background work has not started at that point. Previously incurred selector tokens
|
|
314
|
-
remain in the ledger. This bounds an atomic delivery record, not the number of tools
|
|
315
|
-
Jev may consider within each task.
|
|
316
|
-
|
|
317
|
-
The candidate list is intersected with the models the local Pi registry reports
|
|
318
|
-
as available. A configured model Pi cannot resolve is not eligible, and an empty
|
|
319
|
-
eligible pool fails before any request. Adding a model anywhere else in Pi does
|
|
320
|
-
not authorize it, and legacy `modelPolicy` entries are never imported
|
|
321
|
-
automatically. An unknown `jevRouting` field is an error, not a silent default.
|
|
322
|
-
|
|
323
|
-
Jev receives only the current delegated task text, your model IDs and
|
|
324
|
-
descriptions, candidate tool names and descriptions, and the permission/output
|
|
325
|
-
requirements it needs to choose. It does not receive repository files,
|
|
326
|
-
conversation history, full system prompts, persona text or tool parameter
|
|
327
|
-
schemas. Task text and descriptions are user content and may contain sensitive
|
|
328
|
-
material, so treat what you delegate as disclosure to TypeSafe.
|
|
329
|
-
|
|
330
|
-
Every new extension-managed dispatch routes through Jev: `task`/`tasks[]`,
|
|
331
|
-
`action:"plan"`, `/btw`, resume, fork, locally permitted nested dispatch and the
|
|
332
|
-
optional `synthesis` child. `action:"plan"` calls Jev and runs the same local
|
|
333
|
-
preflights, returns the resolved model/tool plan and the selector usage, and
|
|
334
|
-
creates no child or run entry. A later dispatch selects again; there is no cached
|
|
335
|
-
decision to reuse. If optional synthesis selection fails, the worker plan and its
|
|
336
|
-
usage stay valid and synthesis is reported as blocked with its diagnostic.
|
|
337
|
-
|
|
338
|
-
`thinking` is optional and is an opaque Pi thinking-level string. Common values
|
|
339
|
-
include `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`, but the
|
|
340
|
-
package does not remap or restrict model-specific values. Pi receives the value
|
|
341
|
-
unchanged and decides whether the active model supports it. Resolution order is:
|
|
342
|
-
explicit task `thinking` > agent frontmatter `thinking` > profile
|
|
343
|
-
`taskDefaults.<profile>.thinking` > the selected candidate's optional `thinking`
|
|
344
|
-
> the parent session's thinking level. Jev never chooses a thinking level.
|
|
345
|
-
|
|
346
|
-
The extension re-reads `jevRouting` on each dispatch and injects the current
|
|
347
|
-
routing guidance into the parent prompt, so configuration edits reach the next
|
|
348
|
-
decision without a code change. Missing or invalid `jevRouting`, or a missing
|
|
349
|
-
credential environment variable, rejects new dispatch and plan with a remedy;
|
|
350
|
-
management stays available.
|
|
351
|
-
|
|
352
|
-
The mandatory routing above is the Extension dispatch contract. The stable SDK
|
|
353
|
-
exports (`runTasks` and `runSubagent`) are trusted low-level library APIs: they
|
|
354
|
-
execute the explicit `TaskSpec` you pass and perform no implicit routing, config
|
|
355
|
-
discovery or network call. Library callers own model and tool choice, and must not
|
|
356
|
-
read these SDK calls as Jev enforcement.
|
|
357
|
-
|
|
358
|
-
### Named agent files
|
|
359
|
-
|
|
360
|
-
Define reusable subagent personas as markdown files, discovered from the same
|
|
361
|
-
conventional roots skills use (higher root wins name conflicts):
|
|
362
|
-
|
|
363
|
-
| Priority | Location | Scope |
|
|
364
|
-
| -------- | ----------------------------------------------------------------------- | --------------------------- |
|
|
365
|
-
| 1 | `.pi/agents/<name>.md` | project (authoritative) |
|
|
366
|
-
| 2 | `.agents/agents/<name>.md` | shared cross-tool workspace |
|
|
367
|
-
| 3 | `$PI_CODING_AGENT_DIR/agents/<name>.md` (default `~/.pi/agent/agents/`) | global |
|
|
368
|
-
|
|
369
|
-
The markdown body becomes the child's appended system prompt; frontmatter
|
|
370
|
-
supplies defaults using the same snake_case names as the tool parameters:
|
|
371
|
-
|
|
372
|
-
```md
|
|
373
|
-
---
|
|
374
|
-
description: Security-focused code reviewer
|
|
375
|
-
# Legacy model/fallback fields are ignored; Jev routing owns model/tool choice.
|
|
376
|
-
thinking: high
|
|
377
|
-
profile: review
|
|
378
|
-
max_turns: 20
|
|
379
|
-
spawns: false # or "*", "scout", "[reviewer, scout]"
|
|
380
|
-
---
|
|
381
|
-
|
|
382
|
-
You are a security auditor. Review code for injection flaws, auth issues,
|
|
383
|
-
and sensitive data exposure. Report findings with file:line evidence and
|
|
384
|
-
severity ratings.
|
|
385
|
-
|
|
386
|
-
@include shared/review-checklist.md
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
Agent files may also pin a structured contract with
|
|
390
|
-
`output_schema: {"type": "object", …}` (single-line inline JSON) or
|
|
391
|
-
`output_schema: @contract.json` (path relative to the agent file).
|
|
392
|
-
|
|
393
|
-
`spawns:` controls which agents a child of this persona may spawn:
|
|
394
|
-
`false` disables further nesting (no tool registered in that child),
|
|
395
|
-
`"*"` (or omit) is unrestricted, and a comma/bracket list is an allowlist
|
|
396
|
-
(agentless tasks are rejected under an allowlist). The policy is passed to
|
|
397
|
-
the child via `PI_SUBAGENT_SPAWNS` and enforced on each subsequent spawn.
|
|
398
|
-
|
|
399
|
-
Body lines that consist solely of `@include relative/path.md` expand that
|
|
400
|
-
file one level deep (relative to the agent file, same 64KB/symlink guards
|
|
401
|
-
as `@contract.json`). Missing or rejected includes leave the line verbatim;
|
|
402
|
-
includes do not recurse.
|
|
403
|
-
|
|
404
|
-
Invoke with `{ task: "…", agent: "reviewer" }`. The agent file supplies
|
|
405
|
-
persona, capability, thinking and budget defaults only: model and tool selection
|
|
406
|
-
stay with Jev routing, and a legacy `model`/`fallback_models` in frontmatter is
|
|
407
|
-
ignored. An explicit `system_prompt` appends after the persona body.
|
|
408
|
-
Profiles still enforce capability: `profile: review` filters candidates to read-only
|
|
409
|
-
tools. Legacy agent `tools` defaults are ignored; an explicit task `tools` list
|
|
410
|
-
requesting write tools under review fails closed. The agent catalog is advertised in the tool's
|
|
411
|
-
system-prompt guidelines (session start) and in bare `status` output (live),
|
|
412
|
-
and file changes are picked up within seconds — no restart needed.
|
|
413
|
-
|
|
414
|
-
### Per-profile task defaults
|
|
415
|
-
|
|
416
|
-
`taskDefaults` in `~/.pi/subagent.json` remains available for non-model
|
|
417
|
-
fields such as thinking, budgets, and retry counts. Its legacy `model` and
|
|
418
|
-
`fallbackModels` fields are ignored; model and tool routing belong only to
|
|
419
|
-
`jevRouting`. A profile `thinking` value overrides the selected candidate's
|
|
420
|
-
optional `thinking` default. Invalid fields are dropped field-by-field.
|
|
421
|
-
|
|
422
|
-
Notes on behavior:
|
|
423
|
-
|
|
424
|
-
- `timeout_ms` is the absolute task deadline: local preflight, Jev selection,
|
|
425
|
-
setup, queue time and runtime all count against it, and selection cannot reset
|
|
426
|
-
it. Timed-out tasks report `state: "timeout"` with
|
|
427
|
-
`timeoutPhase: "queued"|"starting"|"running"` so agents can retry capacity
|
|
428
|
-
issues without confusing them for task failures.
|
|
429
|
-
- Budget stops (`max_turns`, `max_cost`) trigger a **graceful wrap-up**: the
|
|
430
|
-
child is steered to produce its final answer NOW and allowed `graceTurns`
|
|
431
|
-
more turns before SIGTERM. Results end as `partial` with `wrappedUp: true`
|
|
432
|
-
when the child concluded in time. `graceTurns: 0` restores immediate stops.
|
|
433
|
-
- A **stall watchdog** flags children with no protocol activity for
|
|
434
|
-
`stallAfterMs` (a liveness probe distinguishes quiet-but-thinking from dead),
|
|
435
|
-
then kills after `stallKillAfterMs` more silence — feeding automatic retry
|
|
436
|
-
instead of burning the whole timeout.
|
|
437
|
-
- **Transient failures retry automatically** (queue timeouts, stalls, spawn
|
|
438
|
-
errors, provider errors) up to `maxRetries` extra attempts on the already
|
|
439
|
-
selected model and tool set. There are no emergency or fallback models, and a
|
|
440
|
-
quality or budget failure never reselects. Usage accumulates across attempts;
|
|
441
|
-
results record `attempts`. Task-quality failures (nonzero exit with complete
|
|
442
|
-
protocol, cancellations, budget stops, running timeouts) never retry.
|
|
443
|
-
- `context: "fork"` starts a single child from a real branched copy of the
|
|
444
|
-
parent conversation (`--fork` on the parent's session file). It requires a
|
|
445
|
-
persisted parent session, cannot combine with `resume`, and is rejected for
|
|
446
|
-
parallel fanout (context duplication × N is a cost bug, not a feature).
|
|
447
|
-
- **Structured output** (`output_schema`): the contract is appended to the
|
|
448
|
-
child's system prompt; the final message must end with a fenced
|
|
449
|
-
`json:result` block. Validation runs parent-side against a dependency-free
|
|
450
|
-
JSON-Schema subset (type/properties/required/items/enum/const — unknown
|
|
451
|
-
keywords are ignored, never rejected). Invalid output triggers **one
|
|
452
|
-
steer-based repair round**; still-invalid results end `partial` with
|
|
453
|
-
`structuredError` set and the raw text delivered — paid work is never
|
|
454
|
-
discarded. Validated parallel results feed the `synthesis` child as clean
|
|
455
|
-
JSON instead of prose.
|
|
456
|
-
- **Arg repair**: double-encoded task text (literal `\n` / `\"` escapes from
|
|
457
|
-
LLM re-encoding) is conservatively de-mangled once at validation time.
|
|
458
|
-
Identifier fields and paths are never touched.
|
|
459
|
-
Protocol streams truncated after useful assistant output also end as `partial`.
|
|
460
|
-
- Aborting a `wait` returns immediately without cancelling the background run.
|
|
461
|
-
- Child processes are launched via the same Node runtime + CLI entry as the
|
|
462
|
-
parent when possible (`PI_SUBAGENT_BIN` overrides). Bare `pi` on PATH is only
|
|
463
|
-
a logged last resort.
|
|
464
|
-
- Direct resume is exclusive **across processes** via durable locks under
|
|
465
|
-
`lockDir`. Lost runs block resume until startup orphan reconciliation kills
|
|
466
|
-
(or confirms dead) the recorded child process group.
|
|
467
|
-
- `maxGlobalActive` bounds concurrent children across every Pi parent process
|
|
468
|
-
on the machine (in addition to the per-session semaphore).
|
|
469
|
-
- Nested children at the depth ceiling do not re-register the subagent tool;
|
|
470
|
-
only top-level parents run maintenance/orphan reclaim/worktree GC.
|
|
471
|
-
- Preserved worktrees live under `worktreeDir` (durable, not `/tmp`) and are
|
|
472
|
-
garbage-collected on startup by **lifecycle**, not wall-clock retention: once
|
|
473
|
-
a run is over (not live, past a 1h concurrency race guard), the worktree's
|
|
474
|
-
unique work is archived as one applyable patch under
|
|
475
|
-
`<repo-container>/_patches/` and the directory is reclaimed immediately.
|
|
476
|
-
Branches holding commits that exist on no other ref are never deleted.
|
|
477
|
-
`diff`/`apply`/`discard` transparently fall back to the archived patch when
|
|
478
|
-
the directory is already gone. Live runs are never swept: the current
|
|
479
|
-
session's live worktrees plus any worktree recorded on a running run record
|
|
480
|
-
(concurrent Pi processes) are shielded machine-wide.
|
|
481
|
-
- Startup GC sweeps **every** repo container under `worktreeDir`, not just the
|
|
482
|
-
current checkout's, so repos you stop visiting are still reclaimed. A
|
|
483
|
-
container whose base repo no longer exists is kept and reported, never
|
|
484
|
-
deleted — its worktrees' object stores lived inside the deleted repo, so
|
|
485
|
-
unique work cannot be distinguished from a pristine checkout, let alone
|
|
486
|
-
archived. Empty containers (no worktrees, no archived patches) are removed.
|
|
487
|
-
- Child session transcripts are likewise distilled on lifecycle: when a run is
|
|
488
|
-
over and nothing on the parent branch references its session, the transcript
|
|
489
|
-
is reduced to a small `.digest.json` (task, final output, model, usage,
|
|
490
|
-
turn/tool/error counts) and the raw `.jsonl` is deleted. Resume needs the
|
|
491
|
-
transcript, so anything referenced or busy machine-wide is kept.
|
|
492
|
-
- `keep_background: true` on a task keeps processes the child intentionally
|
|
493
|
-
backgrounded (e.g. dev servers) alive after a clean exit.
|
|
494
|
-
- `include_wip: true` (with `isolation: "worktree"`) seeds the worktree with the
|
|
495
|
-
parent checkout's uncommitted changes so the child sees your dirty baseline.
|
|
496
|
-
`diff`/`apply` subtract that baseline when clean, else report the combined
|
|
497
|
-
delta with an explicit `[includes parent WIP]` warning.
|
|
498
|
-
|
|
499
|
-
## Using the runner as a library
|
|
500
|
-
|
|
501
|
-
Import the stable public SDK from the package root or the explicit `/sdk`
|
|
502
|
-
subpath — do not reach into `src/*` internals (those paths are not part of the
|
|
503
|
-
supported contract):
|
|
504
|
-
|
|
505
|
-
```ts
|
|
506
|
-
import {
|
|
507
|
-
runTasks,
|
|
508
|
-
runSubagent,
|
|
509
|
-
ChildRunner,
|
|
510
|
-
WorktreeManager,
|
|
511
|
-
Semaphore,
|
|
512
|
-
ProcessLockManager,
|
|
513
|
-
addUsage,
|
|
514
|
-
normalizeUsage,
|
|
515
|
-
emptyUsage,
|
|
516
|
-
type TaskSpec,
|
|
517
|
-
type TaskResult,
|
|
518
|
-
type RunState,
|
|
519
|
-
type UsageStats,
|
|
520
|
-
} from "@cr1ms0n/pi-subagent/sdk";
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
The package root is an alias for the same SDK:
|
|
524
|
-
`import { runTasks } from "@cr1ms0n/pi-subagent"`.
|
|
525
|
-
|
|
526
|
-
The Extension dispatch path routes every new task through Jev, so callers never
|
|
527
|
-
pass a model to it. The low-level SDK is the opposite contract: it is
|
|
528
|
-
explicit-spec and performs no implicit routing, config discovery or network
|
|
529
|
-
call, so embedding code supplies the model (and tool list) it resolved itself.
|
|
530
|
-
This placeholder is illustrative only and configures nothing:
|
|
531
|
-
|
|
532
|
-
```ts
|
|
533
|
-
const task: TaskSpec = {
|
|
534
|
-
task: "Audit src/ for unsafe parsing",
|
|
535
|
-
profile: "explore",
|
|
536
|
-
model: "<provider/model-id resolved by your embedding code>",
|
|
537
|
-
timeoutMs: 10 * 60_000,
|
|
538
|
-
};
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
Prefer `runTasks()` for multi-task / worktree orchestration (same path the
|
|
542
|
-
extension and pi-workflows use). `runSubagent()` runs a single child process
|
|
543
|
-
directly without the extension host, but durable coordination is **opt-in**.
|
|
544
|
-
Pass both `locks` (a `ProcessLockManager`) and a stable `runId` if you want
|
|
545
|
-
global concurrency slots and orphan reclaim to see the child. Without those
|
|
546
|
-
options no durable run record is written, so a parent restart cannot reclassify
|
|
547
|
-
the process and nested children vanish from reconcile. There is intentionally
|
|
548
|
-
no implicit default lock manager — embedding code that needs durability must
|
|
549
|
-
construct and share one.
|
|
550
|
-
|
|
551
|
-
The Pi extension entry is unchanged: package `pi.extensions` still points at
|
|
552
|
-
`./extensions/subagent.ts`.
|
|
553
|
-
|
|
554
|
-
## Design invariants
|
|
555
|
-
|
|
556
|
-
1. A run belongs to one parent session and cannot update another session.
|
|
557
|
-
2. Per-session + machine-wide process caps and nesting depth limits prevent process storms.
|
|
558
|
-
3. Cancellation prevents queued tasks from spawning.
|
|
559
|
-
4. Direct resume of a child session is exclusive **across processes** via durable locks.
|
|
560
|
-
5. Tool responses are capped to ~50KB/2000 lines; full output lives in
|
|
561
|
-
artifacts and `~/.pi/subagent-sessions`.
|
|
562
|
-
6. Status is compact; wait is the one-shot deliverable.
|
|
563
|
-
7. On parent session shutdown, live children are aborted and awaited briefly.
|
|
564
|
-
8. On parent (re)start, orphan process groups recorded under `lockDir` are reaped
|
|
565
|
-
before any resume is allowed for the matching child session.
|
|
566
|
-
9. Provider-reported usage is counted once per root message and terminal child run;
|
|
567
|
-
selector usage is a separate category counted once per selector request ID.
|
|
568
|
-
10. Protocol completion prefers `agent_settled` (falls back to non-retrying `agent_end`).
|
|
569
|
-
11. Jev selection precedes every new extension-managed launch, and the selected
|
|
570
|
-
tool subset is enforced by Pi's CLI allowlist; empty selection never means all tools.
|
|
571
|
-
|
|
572
|
-
## Layout
|
|
573
|
-
|
|
574
|
-
```
|
|
575
|
-
src/
|
|
576
|
-
index.ts # stable public SDK entry (@cr1ms0n/pi-subagent)
|
|
577
|
-
extension.ts # Pi wiring only
|
|
578
|
-
schema.ts # request schemas (subagent + subagent_wait)
|
|
579
|
-
btw.ts # /btw side questions (model-hidden entries)
|
|
580
|
-
backend.ts # backend adapter seam + capability gate
|
|
581
|
-
backends/ # pi | codex | claude adapters (invocation + parser)
|
|
582
|
-
policy.ts # profiles, normalization, write guards, agent resolution
|
|
583
|
-
routing-types.ts # selector DTOs, decisions, receipts, local resource limits
|
|
584
|
-
routing-policy.ts# strict jevRouting parser, candidate list, routing guidance
|
|
585
|
-
jev-router.ts # injectable Jev transport, response validation, receipts
|
|
586
|
-
dispatch-preflight.ts # bounded read-only checks before selector work
|
|
587
|
-
startup-check.ts / child-preflight.ts # private child model/tool verification
|
|
588
|
-
dispatch-routing.ts # prepare -> select -> finalize for one or many tasks
|
|
589
|
-
agents.ts # named agent files (.pi/agents/, .agents/agents/, global)
|
|
590
|
-
launch.ts # resolve child pi via execPath / PI_SUBAGENT_BIN
|
|
591
|
-
process-lock.ts # durable session locks, global slots, orphan records
|
|
592
|
-
worktree.ts # git worktree isolation + diff/apply/discard
|
|
593
|
-
orchestrator.ts # multi-task execution, worktree prep, bounded same-model retry
|
|
594
|
-
runner.ts # child process lifecycle, RPC channel, steering,
|
|
595
|
-
# graceful budget wrap-up, stall watchdog
|
|
596
|
-
protocol.ts # Pi RPC/JSON event parser (agent_settled-aware)
|
|
597
|
-
semaphore.ts # per-session concurrency limit
|
|
598
|
-
registry.ts # session-scoped run state + durable resume locks
|
|
599
|
-
persistence.ts # parent-session event folding
|
|
600
|
-
usage.ts # root/subagent/combined usage ledger
|
|
601
|
-
output.ts # exact global output caps
|
|
602
|
-
notifications.ts # batched background-run completion notifications
|
|
603
|
-
format.ts / ui.ts# renderers, ambient widget, /subagents overlay
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
## Develop
|
|
607
|
-
|
|
608
|
-
This checkout has no `scripts`, no `devDependencies`, no `tsconfig.json` and no
|
|
609
|
-
test runner, so `npm install`, `npm run typecheck`, `npm test` and
|
|
610
|
-
`npm run pack:check` are not defined here. The checks that do run locally are
|
|
611
|
-
offline:
|
|
612
|
-
|
|
613
|
-
```bash
|
|
614
|
-
npm pack --dry-run --json
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
That verifies the publishable file list matches `package.json` `files` and leaks
|
|
618
|
-
no backup, transcript, session data, research output or generated bundle. Source
|
|
619
|
-
changes are parse/type-strip checked by running the global Pi install's bundled
|
|
620
|
-
esbuild over every `src/` and `extensions/` file; that catches malformed
|
|
621
|
-
TypeScript only, not type errors or peer API mismatches. Provider-free fixtures
|
|
622
|
-
and an injected fake selector transport, run with the already installed Pi runtime
|
|
623
|
-
rather than a repository test framework, exercise routing behavior without any
|
|
624
|
-
model call. See [.trellis/spec/backend/quality-guidelines.md](.trellis/spec/backend/quality-guidelines.md)
|
|
625
|
-
for the exact commands and what each check does and does not prove.
|
|
626
|
-
|
|
627
|
-
## Cost accounting
|
|
628
|
-
|
|
629
|
-
`status`, `/subagent-cost`, and the `/subagents` overlay header show separate
|
|
630
|
-
**root**, **subagent**, and **combined** totals based on provider-reported
|
|
631
|
-
usage. On Pi builds after v0.80.10, delivered runs also report their total
|
|
632
|
-
usage natively on the tool result
|
|
633
|
-
([pi#6671](https://github.com/earendil-works/pi/pull/6671)), so Pi's own
|
|
634
|
-
footer, `/session`, and RPC totals include subagent spend — exactly once per
|
|
635
|
-
run; older Pi hosts ignore the field. Nested usage reported by a child's tool
|
|
636
|
-
results (e.g. grandchild subagents) folds into the run's totals and budgets.
|
|
637
|
-
The extension footer stays terse (running/ready counts only). Delivery and
|
|
638
|
-
replay do not double count runs. See
|
|
639
|
-
[docs/COST-ACCOUNTING.md](./docs/COST-ACCOUNTING.md).
|
|
640
|
-
|
|
641
|
-
Jev selection is billed separately from execution. TypeSafe reports tokens, not
|
|
642
|
-
currency, so the ledger shows routing tokens as their own category, counts each
|
|
643
|
-
selector request once by its request ID (including plan and pre-spawn failures),
|
|
644
|
-
and marks routing cost as **unreported** rather than free. Numeric dollar totals
|
|
645
|
-
exclude unreported routing spend, and `max_cost` caps provider-reported execution
|
|
646
|
-
cost only; it does not cap TypeSafe charges. Route metadata (selected model,
|
|
647
|
-
selected tools, locally added controls, selector version, confidence, outcome,
|
|
648
|
-
latency) travels with the run alongside usage.
|
|
649
|
-
|
|
650
|
-
## Roadmap
|
|
651
|
-
|
|
652
|
-
Planned work — agent spawn policies, dry-run validation, engine hardening,
|
|
653
|
-
live transcripts — lives in [docs/ROADMAP.md](./docs/ROADMAP.md) (rationale
|
|
654
|
-
and design sketches) and [docs/PLAN.md](./docs/PLAN.md) (execution contract:
|
|
655
|
-
work breakdown, acceptance criteria, test plans, and release gates per phase).
|
|
656
|
-
|
|
657
|
-
## Security
|
|
658
|
-
|
|
659
|
-
See [docs/SECURITY.md](./docs/SECURITY.md). Pi packages run with full system
|
|
660
|
-
access—review source before installing third-party packages.
|
|
661
|
-
|
|
662
|
-
## Status
|
|
663
|
-
|
|
664
|
-
v0.1 focuses on the correct lifecycle engine:
|
|
665
|
-
|
|
666
|
-
- process + session ownership
|
|
667
|
-
- budgets, caps, profiles
|
|
668
|
-
- persistence + inspector
|
|
669
|
-
- worktree isolation helpers
|
|
670
|
-
|
|
671
|
-
Named agent catalogs and automatic chain workflows are intentionally deferred
|
|
672
|
-
until the core is battle-tested.
|
|
1
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
2
|
+
|
|
3
|
+
# Pi Smart Subagents
|
|
4
|
+
|
|
5
|
+
Run isolated child agents in [Pi](https://pi.dev/), with Jev selecting an execution model and individual tools for each task.
|
|
6
|
+
|
|
7
|
+
Published on npm as `@cr1ms0n/pi-subagent`. This is an independent community fork of Luke Parke's `@parke.dev/pi-subagent` 0.8.0 from [LukasParke/pi-extensions](https://github.com/LukasParke/pi-extensions/tree/main/packages/pi-subagent), not an official upstream release. The original MIT license and copyright are preserved.
|
|
8
|
+
|
|
9
|
+
The upstream extension provides the child-process engine, named agents, background tasks, worktrees and usage accounting. This fork adds mandatory Jev model/tool selection and verifies the child's selected capabilities before sending it the task.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a id="quick-start"></a>
|
|
14
|
+
### Install and quick start
|
|
15
|
+
|
|
16
|
+
Use Node.js 22.19.0 or newer and an installed Pi CLI with a working model provider. Pi 0.86.0 is the verified host baseline for enforcing built-in, extension and late-registered tool allowlists. A host that cannot verify the selected capabilities is refused rather than granted more tools.
|
|
17
|
+
|
|
18
|
+
**1. Install the published package.**
|
|
19
|
+
|
|
20
|
+
Install the exact `0.10.0` release. The earlier `0.9.0` release uses the older `apiKeyEnv` configuration contract and does not accept `apiKey`:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pi install npm:@cr1ms0n/pi-subagent@0.10.0
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Pi loads the package directly. Do not enable another copy of this extension or `@parke.dev/pi-subagent` together with it: they register the same tools. The package provides `subagent`, `subagent_wait`, `/subagents`, `/subagent-cost` and `/btw`.
|
|
27
|
+
|
|
28
|
+
**2. Store your TypeSafe credential in private configuration.**
|
|
29
|
+
|
|
30
|
+
Set `jevRouting.apiKey` in your user-level `~/.pi/subagent.json`, as shown below. If you are upgrading from `0.9.0`, move the existing value from `jevRouting.apiKeyEnv` to `jevRouting.apiKey` and remove the old field before starting new dispatches. Do not paste the key into chat or repository files. The file stores the key in plaintext: restrict file access and protect backups. See [credential setup](docs/REFERENCE.md#credential-setup) for migration and security details. Provider authentication for the child models is configured separately in Pi.
|
|
31
|
+
|
|
32
|
+
**3. Configure your candidate models.**
|
|
33
|
+
|
|
34
|
+
Add this block to `~/.pi/subagent.json`, preserving unrelated settings. Replace the example model ID with an exact `provider/model-id` available in your Pi installation and write your own model characteristics. Remove any legacy `modelPolicy` block; it is not migrated automatically.
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"jevRouting": {
|
|
39
|
+
"selectorModel": "jev-latest",
|
|
40
|
+
"apiKey": "<your-typesafe-api-key>",
|
|
41
|
+
"timeoutMs": 15000,
|
|
42
|
+
"models": [
|
|
43
|
+
{
|
|
44
|
+
"model": "<provider/model-id>",
|
|
45
|
+
"description": "Describe this model's strengths and the tasks you want it to handle."
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Replace the `apiKey` placeholder with your TypeSafe key and remove any old `apiKeyEnv` field. There is no environment fallback or automatic migration. Candidate descriptions may be written in Chinese. See the [configuration reference](docs/REFERENCE.md#configuration) for optional thinking defaults, profile defaults and limits.
|
|
53
|
+
|
|
54
|
+
Jev selection can incur TypeSafe charges. It receives the delegated task text, model IDs/descriptions, candidate tool names/descriptions and required constraints. It does not automatically upload repository files or conversation history; text you include in the task can still disclose sensitive information. `action: "plan"` also calls Jev, and a later execution selects again.
|
|
55
|
+
|
|
56
|
+
**4. Start Pi and delegate a read-only task.**
|
|
57
|
+
|
|
58
|
+
Start Pi, or reload/restart it after switching extension code. Once `0.10.0` is loaded, each new dispatch re-reads the configuration; changing `apiKey` does not require a shell environment update.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pi
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Ask the parent agent to use `subagent` with a request such as:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"task": "Read README.md and summarize what this package does.",
|
|
69
|
+
"description": "Summarize the README",
|
|
70
|
+
"profile": "explore",
|
|
71
|
+
"tools": ["read"],
|
|
72
|
+
"max_turns": 4,
|
|
73
|
+
"timeout_ms": 120000,
|
|
74
|
+
"max_retries": 0
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Omit `model` and `fallback_models`. Jev chooses from your configured model list and permitted tools; a routing failure stops the new dispatch without a fallback. Existing-run management remains available without a routing credential.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
<a id="delegation"></a>
|
|
83
|
+
### Delegation
|
|
84
|
+
|
|
85
|
+
- **Model and tool routing:** this fork asks Jev to match each task to your model descriptions and select tools individually. Local permission checks and child startup verification enforce the result.
|
|
86
|
+
- **Named agents and parallel work:** the upstream engine supports reusable personas and concurrent child processes. This fork routes each new child through Jev; agent files do not pin its model or tool selection.
|
|
87
|
+
- **Background tasks:** the upstream engine supports status, interruptible waiting, cancellation and steering. The fork's display includes the selected model, with tool details in expanded results.
|
|
88
|
+
- **Isolated edits:** the upstream worktree flow lets you inspect, apply or discard changes without sharing one writable checkout between parallel agents.
|
|
89
|
+
- **Structured results and budgets:** the upstream engine validates structured output parent-side and preserves partial work. This fork keeps retries on the selected model/tool set and accounts for selector tokens separately.
|
|
90
|
+
|
|
91
|
+
For a background task, set `async: true`, then collect it using `subagent_wait` or `action: "wait"`. Aborting or timing out a wait does not cancel the child. Use `action: "cancel"` to stop it. Open `/subagents` to inspect runs and `/subagent-cost` to see usage.
|
|
92
|
+
|
|
93
|
+
The [reference](docs/REFERENCE.md#quick-usage) includes parallel work, synthesis, resume/fork, structured output, budgets and the worktree diff/apply/discard loop. The [TUI guide](docs/UX.md) describes the inspector and keyboard controls.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
<a id="permissions-and-costs"></a>
|
|
98
|
+
### Permissions and costs
|
|
99
|
+
|
|
100
|
+
| Profile | Tool selection | Project-file writes |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| `explore` | Jev-selected locally permitted read-only tools plus available Pi context controls | No |
|
|
103
|
+
| `review` | Same read-only policy | No |
|
|
104
|
+
| `general` | Jev-selected locally permitted tools plus available Pi context controls | Possible with selected write-capable tools |
|
|
105
|
+
|
|
106
|
+
Single tasks default to `general`; parallel tasks default to `explore`. An explicit `tools` list is a ceiling. Available Pi context-management controls are added locally even with `tools: []`. An empty tool selection never means all tools.
|
|
107
|
+
|
|
108
|
+
Profiles are tool-selection policy, not an OS sandbox. Children inherit the parent environment and can read files accessible to the same user, including the private config. Worktrees isolate the checkout only. Review the [security model](docs/SECURITY.md) before delegating untrusted work.
|
|
109
|
+
|
|
110
|
+
The ledger separates root, subagent, routing and combined usage. TypeSafe reports routing tokens, not currency, so selector cost is **unreported**, not free. `max_cost` limits provider-reported child execution cost; it does not cap TypeSafe fees. See [cost accounting](docs/COST-ACCOUNTING.md) for delivery, retry and branch semantics.
|
|
111
|
+
|
|
112
|
+
New extension-managed dispatch supports the Pi backend only. Native Codex/Claude requests are rejected. The [low-level SDK](docs/REFERENCE.md#using-the-runner-as-a-library) is a separate explicit-spec API: it does not automatically call Jev, and embedding code owns its model/tool choices.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
<a id="development"></a>
|
|
117
|
+
### Development
|
|
118
|
+
|
|
119
|
+
The source is a standalone TypeScript package with peer dependencies, no build step and no bundled test runner or typecheck script. Follow [development and verification](docs/DEVELOPMENT.md) for the checks this checkout supports. A syntax transform is not a semantic typecheck, and `npm pack --dry-run --ignore-scripts --json` verifies package contents without publishing.
|
|
120
|
+
|
|
121
|
+
The [architecture contract](docs/ARCHITECTURE.md) documents ownership and invariants. [Release maintenance](docs/RELEASING.md) covers selective source updates and the separate, explicitly authorized npm publication process.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
<a id="license"></a>
|
|
126
|
+
### License
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE). Copyright (c) 2026 Luke Parke. Fork maintained by cr1ms0n (awoaCrim). Preserve the original copyright and license when redistributing this work.
|
|
129
|
+
|
|
130
|
+
Thanks to [Linux.do](https://linux.do/).
|