@ladbabynpm/picc-subagents 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/README.md +379 -0
- package/biome.json +26 -0
- package/package.json +69 -0
- package/src/agent-manager.ts +636 -0
- package/src/agent-runner.ts +986 -0
- package/src/agent-types.ts +199 -0
- package/src/context.ts +58 -0
- package/src/cross-extension-rpc.ts +122 -0
- package/src/custom-agents.ts +167 -0
- package/src/default-agents.ts +126 -0
- package/src/enabled-models.ts +180 -0
- package/src/env.ts +33 -0
- package/src/group-join.ts +141 -0
- package/src/index.ts +2154 -0
- package/src/invocation-config.ts +38 -0
- package/src/memory.ts +174 -0
- package/src/model-resolver.ts +100 -0
- package/src/output-file.ts +110 -0
- package/src/prompts.ts +114 -0
- package/src/schedule-store.ts +153 -0
- package/src/schedule.ts +365 -0
- package/src/settings.ts +272 -0
- package/src/skill-loader.ts +102 -0
- package/src/status-note.ts +25 -0
- package/src/subagent-env.ts +52 -0
- package/src/types.ts +206 -0
- package/src/ui/agent-widget.ts +566 -0
- package/src/ui/conversation-viewer.ts +362 -0
- package/src/ui/fleet-list.ts +380 -0
- package/src/ui/schedule-menu.ts +104 -0
- package/src/ui/viewer-keys.ts +39 -0
- package/src/usage.ts +60 -0
- package/src/worktree.ts +191 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# picc-subagents
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ladbabynpm/picc-subagents)
|
|
4
|
+
|
|
5
|
+
Fork of [`@tintinweb/pi-subagents`](https://github.com/tintinweb/pi-subagents), adding
|
|
6
|
+
`PI_SUBAGENT_MODEL` / `CLAUDE_CODE_SUBAGENT_MODEL` env-var model selection, removing `get_subagent_result` and `steer_subagent` tools.
|
|
7
|
+
To switch back to upstream, run `pi install npm:@tintinweb/pi-subagents`.
|
|
8
|
+
|
|
9
|
+
Part of [picc](https://github.com/Ladbaby/picc), a pi agent setup mirroring Claude Code's harness.
|
|
10
|
+
|
|
11
|
+
> pi has no built-in sub-agent concept. This extension adds one faithful to Claude Code: the
|
|
12
|
+
> `Agent` tool, foreground + background runs, a
|
|
13
|
+
> live widget and FleetView, custom agent types, mid-run steering, session resume, and a graceful
|
|
14
|
+
> turn limit — all with Claude Code's names, calling conventions, and UI patterns.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
Install via `pi install npm:@ladbabynpm/picc-subagents`.
|
|
19
|
+
|
|
20
|
+
## Tools
|
|
21
|
+
|
|
22
|
+
### `Agent`
|
|
23
|
+
|
|
24
|
+
Launch a sub-agent.
|
|
25
|
+
|
|
26
|
+
| Parameter | Type | Required | Description |
|
|
27
|
+
|-----------|------|----------|-------------|
|
|
28
|
+
| `prompt` | string | yes | The task for the agent |
|
|
29
|
+
| `description` | string | yes | Short 3-5 word summary (shown in UI) |
|
|
30
|
+
| `subagent_type` | string | yes | Agent type (built-in or custom) |
|
|
31
|
+
| `model` | string | no | `provider/modelId` or fuzzy name (`"haiku"`, `"sonnet"`); resolved tolerantly with provider fallback |
|
|
32
|
+
| `thinking` | string | no | off, minimal, low, medium, high, xhigh, max |
|
|
33
|
+
| `max_turns` | number | no | Max agentic turns; omit for unlimited |
|
|
34
|
+
| `run_in_background` | boolean | no | Run without blocking |
|
|
35
|
+
| `resume` | string | no | Agent ID to resume a previous session |
|
|
36
|
+
| `isolated` | boolean | no | No extension/MCP tools |
|
|
37
|
+
| `isolation` | `"worktree"` | no | Run in an isolated git worktree |
|
|
38
|
+
| `inherit_context` | boolean | no | Fork parent conversation into agent |
|
|
39
|
+
| `schedule` | string | no | Fire later instead of now (cron / interval / one-shot) |
|
|
40
|
+
|
|
41
|
+
## Scheduling
|
|
42
|
+
|
|
43
|
+
Pass `schedule` to the `Agent` tool to fire the agent later instead of running now:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Agent({
|
|
47
|
+
subagent_type: "Explore",
|
|
48
|
+
prompt: "Look at recent commits and summarize what changed since last week",
|
|
49
|
+
description: "Weekly commit review",
|
|
50
|
+
schedule: "0 0 9 * * 1", // 9am every Monday (6-field cron)
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Formats:
|
|
55
|
+
|
|
56
|
+
- **Cron** — 6-field (`second minute hour day-of-month month day-of-week`), e.g. `"0 */15 * * * *"` every 15 minutes.
|
|
57
|
+
- **Interval** — `"5m"`, `"1h"`, `"30s"`, `"2d"`. Fires repeatedly.
|
|
58
|
+
- **One-shot relative** — `"+10m"`, `"+2h"`, `"1d"`.
|
|
59
|
+
- **One-shot absolute** — full ISO timestamp, e.g. `"2026-12-25T09:00:00.000Z"`.
|
|
60
|
+
|
|
61
|
+
When a schedule fires, the spawn runs in the background and its completion arrives through the same
|
|
62
|
+
`subagent-notification` path as a manually-spawned background agent.
|
|
63
|
+
|
|
64
|
+
- Schedules are **session-scoped** — reset on `/new`, restore on `/resume`. Stored at `<cwd>/.pi/subagent-schedules/<sessionId>.json` with PID-based locking. Manage via `/agents → Scheduled jobs`.
|
|
65
|
+
- `schedule` cannot combine with `inherit_context` or `resume`; `run_in_background` is forced `true`; scheduled fires bypass the `maxConcurrent` queue.
|
|
66
|
+
- **Headless `pi -p` does not wait for scheduled subagents.**
|
|
67
|
+
- Disable entirely via `/agents → Settings → Scheduling → disabled` (removes `schema`, hides the menu entry, stops active schedulers).
|
|
68
|
+
|
|
69
|
+
## Custom Agents
|
|
70
|
+
|
|
71
|
+
Define agent types by creating `.md` files; the filename becomes the type name, and any name
|
|
72
|
+
overrides a same-named default. Discovered from three locations (higher wins):
|
|
73
|
+
|
|
74
|
+
| Priority | Location | Scope |
|
|
75
|
+
|----------|----------|-------|
|
|
76
|
+
| 1 (highest) | `.pi/agents/<name>.md` | Project — pi's config dir; authoritative |
|
|
77
|
+
| 2 | `.agents/agents/<name>.md` | Project — shared cross-tool `.agents` workspace |
|
|
78
|
+
| 3 | `$PI_CODING_AGENT_DIR/agents/<name>.md` (default `~/.pi/agent/agents/<name>.md`) | Global — available everywhere |
|
|
79
|
+
|
|
80
|
+
### Example: `.pi/agents/auditor.md`
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
---
|
|
84
|
+
description: Security Code Reviewer
|
|
85
|
+
tools: read, grep, find, bash
|
|
86
|
+
model: anthropic/claude-opus-4-6
|
|
87
|
+
thinking: high
|
|
88
|
+
max_turns: 30
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
You are a security auditor. Review code for vulnerabilities including:
|
|
92
|
+
- Injection flaws (SQL, command, XSS)
|
|
93
|
+
- Authentication and authorization issues
|
|
94
|
+
- Sensitive data exposure
|
|
95
|
+
- Insecure configurations
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then spawn it like any built-in: `Agent({ subagent_type: "auditor", ... })`.
|
|
99
|
+
|
|
100
|
+
### Frontmatter fields
|
|
101
|
+
|
|
102
|
+
All optional — sensible defaults throughout.
|
|
103
|
+
|
|
104
|
+
| Field | Default | Description |
|
|
105
|
+
|-------|---------|-------------|
|
|
106
|
+
| `description` | filename | Shown in tool listings |
|
|
107
|
+
| `display_name` | — | UI display name |
|
|
108
|
+
| `tools` | all 7 | Built-in names, `*`/`all`, `none`, and `ext:<ext>` / `ext:<ext>/<tool>` selectors |
|
|
109
|
+
| `extensions` | `true` | `true` (all), `false` (none), or a list: `[mcp, "/abs/path.ts", "*"]` |
|
|
110
|
+
| `exclude_extensions` | — | Extension denylist applied after `extensions:`; plain names only |
|
|
111
|
+
| `skills` | `true` | Inherit skills, or a comma list to preload |
|
|
112
|
+
| `memory` | — | Persistent memory scope: `project`, `local`, or `user` |
|
|
113
|
+
| `disallowed_tools` | — | Tools to deny even if extensions provide them |
|
|
114
|
+
| `isolation` | — | `worktree` to run in an isolated git worktree |
|
|
115
|
+
| `model` | inherit | `provider/modelId` or fuzzy name; resolved tolerantly with provider fallback |
|
|
116
|
+
| `thinking` | inherit | off, minimal, low, medium, high, xhigh, max |
|
|
117
|
+
| `max_turns` | unlimited | Max agentic turns before graceful shutdown |
|
|
118
|
+
| `persist_session` | `false` | Persist as a normal pi session (transcript written either way) |
|
|
119
|
+
| `session_dir` | pi default | Session dir when `persist_session: true` |
|
|
120
|
+
| `prompt_mode` | `replace` | `replace` (full prompt) or `append` (parent twin — inherits AGENTS.md/CLAUDE.md) |
|
|
121
|
+
| `inherit_context` | `false` | Fork parent conversation into agent |
|
|
122
|
+
| `run_in_background` | `false` | Run in background by default |
|
|
123
|
+
| `isolated` | `false` | Hermetic: `extensions: false` + `skills: false`, built-ins only |
|
|
124
|
+
| `enabled` | `true` | `false` to disable (hide a default per-project) |
|
|
125
|
+
|
|
126
|
+
Frontmatter is authoritative: if it sets `model`, `thinking`, `max_turns`, `inherit_context`,
|
|
127
|
+
`run_in_background`, `isolated`, or `isolation`, those are locked; `Agent` parameters only fill
|
|
128
|
+
unspecified fields. `model:` resolution is forgiving (`.`/`-` and a trailing date stamp are
|
|
129
|
+
interchangeable; a `provider/modelId` whose provider lacks the model retries the bare id), with
|
|
130
|
+
precedence **exact → fuzzy under named provider → same model under any provider → unavailable**
|
|
131
|
+
(inherits the parent model, flagged in `/agents`).
|
|
132
|
+
|
|
133
|
+
### Tool & extension scoping
|
|
134
|
+
|
|
135
|
+
`extensions:` decides **which extensions load**; `tools:` decides **which tools surface** to the
|
|
136
|
+
LLM. They compose:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
tools: read, grep, find # narrow built-ins; extensions still load
|
|
140
|
+
tools: "*" # all 7 built-ins (alias: `all`)
|
|
141
|
+
tools: none # zero built-ins
|
|
142
|
+
tools: "*, ext:mcp/search" # built-ins plus one extension tool
|
|
143
|
+
|
|
144
|
+
extensions: false # no extensions load
|
|
145
|
+
extensions: [mcp] # only mcp loads
|
|
146
|
+
exclude_extensions: pi-notify # everything except pi-notify
|
|
147
|
+
|
|
148
|
+
isolated: true # hermetic: built-ins only, no extensions/skills/context
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- `extensions:` is the sole loading authority — `ext:foo` in `tools:` narrows what surfaces but can't load `foo` alone.
|
|
152
|
+
- Any `ext:` entry flips extension tools to an explicit allowlist: `tools: "*, ext:mcp/search"` exposes only `search` from `mcp`, nothing from other extensions.
|
|
153
|
+
- Extension names match case-insensitively; `ext:foo/bar` tool names stay case-sensitive. A **package** extension matches by short name (`@scope/pi-subagents` → `[pi-subagents]`).
|
|
154
|
+
- Plain `tools:` typos fail loudly (`tools-error:…`), and `exclude_extensions:` wins over everything but is **not a sandbox** (excluded factories still run once).
|
|
155
|
+
|
|
156
|
+
## Commands
|
|
157
|
+
|
|
158
|
+
| Command | Description |
|
|
159
|
+
|---------|-------------|
|
|
160
|
+
| `/agents` | Interactive agent management menu |
|
|
161
|
+
|
|
162
|
+
`/agents` opens a menu of **Running agents** (open a live conversation viewer; `Enter` to steer,
|
|
163
|
+
`x`/`x` to stop — including background agents), **Agent types** (unified defaults + custom with
|
|
164
|
+
`•`/`◦`/`✕` source indicators; Eject / Edit / Disable / Delete per state), **Create new agent**
|
|
165
|
+
(manual wizard or AI-generated), and **Settings** (concurrency, max turns, grace turns, join mode,
|
|
166
|
+
scheduling, scope models, disable defaults, tool description mode, widget mode).
|
|
167
|
+
|
|
168
|
+
## Default Agent Types
|
|
169
|
+
|
|
170
|
+
| Type | Tools | Model | Prompt Mode | Description |
|
|
171
|
+
|------|-------|-------|-------------|-------------|
|
|
172
|
+
| `general-purpose` | all 7 | inherit | `append` (parent twin) | Inherits the parent's full system prompt — same rules, CLAUDE.md, conventions |
|
|
173
|
+
| `Explore` | read, bash, grep, find, ls | haiku (falls back to inherit) | `replace` | Fast codebase exploration (read-only) |
|
|
174
|
+
| `Plan` | read, bash, grep, find, ls | inherit | `replace` | Software architect for implementation planning (read-only) |
|
|
175
|
+
|
|
176
|
+
Default agents can be **ejected** (export as `.md`), **overridden** (create a `.md` with the same
|
|
177
|
+
name), or **disabled** per-project (`enabled: false`).
|
|
178
|
+
|
|
179
|
+
## UI
|
|
180
|
+
|
|
181
|
+
A persistent widget above the editor shows active agents (animated spinners, live tool activity,
|
|
182
|
+
token counts, status icons). Default `widgetMode: background` (foreground runs already render
|
|
183
|
+
inline as the `Agent` result); switch via `/agents → Settings → Widget` to `all` or `off`. The
|
|
184
|
+
token field is annotated with context-window utilization (`NN%`, color-coded) and compaction count
|
|
185
|
+
(`⇊N`).
|
|
186
|
+
|
|
187
|
+
**FleetView** renders a Claude Code-style navigable list of `main` + every running subagent below
|
|
188
|
+
the editor (earliest-launched first). At an empty prompt press `↓`/`←` to enter, `↑`/`↓` to move,
|
|
189
|
+
`Enter` to open the live conversation, `Esc` to return. Inside the overlay `Enter` opens a steering
|
|
190
|
+
composer, and `x` stops a running agent. Toggle via `/agents → Settings → Fleet view`.
|
|
191
|
+
|
|
192
|
+
Individual results render Claude Code-style (`⠹` running, `✓` completed/wrapped, `■` stopped, `✗`
|
|
193
|
+
error/aborted); completed results expand (ctrl+o) to full output. Both foreground and background
|
|
194
|
+
agents stream to `.pi/output/agent-<id>.jsonl`; background completions render as themed notification
|
|
195
|
+
boxes while the LLM receives structured `<task-notification>` XML.
|
|
196
|
+
|
|
197
|
+
## Graceful Max Turns
|
|
198
|
+
|
|
199
|
+
Instead of hard-aborting at `max_turns`, agents get a wrap-up warning, up to 5 grace turns to finish
|
|
200
|
+
cleanly, and a hard abort only after the grace period.
|
|
201
|
+
|
|
202
|
+
| Status | Meaning | Icon |
|
|
203
|
+
|--------|---------|------|
|
|
204
|
+
| `completed` | Finished naturally | `✓` green |
|
|
205
|
+
| `steered` | Hit limit, wrapped up in time | `✓` yellow |
|
|
206
|
+
| `aborted` | Grace period exceeded | `✗` red |
|
|
207
|
+
| `stopped` | User-initiated abort | `■` dim |
|
|
208
|
+
|
|
209
|
+
## Concurrency & Join Strategies
|
|
210
|
+
|
|
211
|
+
Background agents are subject to a configurable concurrency limit (default 4); excess agents queue
|
|
212
|
+
and start as slots free up. Foreground agents bypass the queue.
|
|
213
|
+
|
|
214
|
+
The **join mode** controls how background completion notifications are delivered:
|
|
215
|
+
|
|
216
|
+
| Mode | Behavior |
|
|
217
|
+
|------|----------|
|
|
218
|
+
| `smart` (default) | 2+ background agents from the same turn are consolidated into one notification; solo agents notify individually |
|
|
219
|
+
| `async` | Each agent notifies on completion (original behavior) |
|
|
220
|
+
| `group` | Force grouping even for a single agent |
|
|
221
|
+
|
|
222
|
+
Grouped agents start a 30-second window after the first completes; partial results notify on
|
|
223
|
+
timeout, stragglers re-batch over a 15-second window. Configure via `/agents → Settings → Join mode`.
|
|
224
|
+
|
|
225
|
+
## Model Scope
|
|
226
|
+
|
|
227
|
+
**Opt-in:** off by default; enable via `/agents → Settings → Scope models`. When on, each spawn's
|
|
228
|
+
effective model is validated against pi's `enabledModels` list (from `/scoped-models`). Both global
|
|
229
|
+
`~/.pi/agent/settings.json` and project `<cwd>/.pi/settings.json` are honored — **project overrides
|
|
230
|
+
global**.
|
|
231
|
+
|
|
232
|
+
| Model source | Out-of-scope behavior |
|
|
233
|
+
|---|---|
|
|
234
|
+
| Caller-supplied `Agent({ model })` | Hard error to the orchestrator, listing allowed models |
|
|
235
|
+
| Pinned in frontmatter | Warning; the pin runs (frontmatter authoritative) |
|
|
236
|
+
| Parent-inherited | Warning; the parent model runs |
|
|
237
|
+
|
|
238
|
+
Only exact `provider/modelId` entries are honored; globs, bare ids, and `:thinking` suffixes are
|
|
239
|
+
dropped. An empty/missing `enabledModels` makes the check a no-op.
|
|
240
|
+
|
|
241
|
+
## Persistent Settings
|
|
242
|
+
|
|
243
|
+
Runtime values set via `/agents → Settings` persist across restarts. Two files, merged on load:
|
|
244
|
+
|
|
245
|
+
- **Global:** `~/.pi/agent/subagents.json` — machine-wide defaults (hand-edited; the menu never writes here).
|
|
246
|
+
- **Project:** `<cwd>/.pi/subagents.json` — per-project overrides (written by the menu).
|
|
247
|
+
|
|
248
|
+
Project overrides global; missing fields fall back to hardcoded defaults (concurrency `4`, max
|
|
249
|
+
turns unlimited, grace `5`, join `smart`, defaults enabled). `disableDefaultAgents` (default
|
|
250
|
+
`false`) stops the three built-ins from registering. `toolDescriptionMode` (`"full"` / `"compact"` /
|
|
251
|
+
`"custom"`) controls which `Agent` tool description the LLM sees; `"custom"` reads a markdown file
|
|
252
|
+
with `{{typeList}}`, `{{compactTypeList}}`, `{{agentDir}}`, `{{scheduleGuideline}}` placeholders
|
|
253
|
+
(see [`examples/agent-tool-description.md`](examples/agent-tool-description.md) as a starting point).
|
|
254
|
+
|
|
255
|
+
## Events
|
|
256
|
+
|
|
257
|
+
Lifecycle events are emitted via `pi.events` so other extensions can react:
|
|
258
|
+
|
|
259
|
+
| Event | When |
|
|
260
|
+
|-------|------|
|
|
261
|
+
| `subagents:created` | Background agent registered |
|
|
262
|
+
| `subagents:started` | Agent transitions to running (incl. queued→running) |
|
|
263
|
+
| `subagents:completed` | Agent finished successfully |
|
|
264
|
+
| `subagents:failed` | Agent errored, stopped, or aborted |
|
|
265
|
+
| `subagents:steered` | Steering message sent |
|
|
266
|
+
| `subagents:compacted` | Agent's session compacted (`reason`: manual/threshold/overflow) |
|
|
267
|
+
| `subagents:scheduled` | Schedule lifecycle change (added/removed/updated/fired/error) |
|
|
268
|
+
| `subagents:scheduler_ready` | Scheduler bound, enabled jobs armed |
|
|
269
|
+
| `subagents:ready` | RPC handlers registered and armed (session start) |
|
|
270
|
+
| `subagents:settings_loaded` / `settings_changed` | Persisted settings applied / mutated |
|
|
271
|
+
|
|
272
|
+
`tokens.total` = `input + output + cacheWrite` (`cacheRead` excluded to avoid over-counting). Use
|
|
273
|
+
`contextUsage.percent` for current context size.
|
|
274
|
+
|
|
275
|
+
## Cross-Extension RPC
|
|
276
|
+
|
|
277
|
+
Other pi extensions can spawn and stop subagents via `pi.events` without importing this package.
|
|
278
|
+
Replies use a standardized envelope: `{ success: true, data? }` or `{ success: false, error }`.
|
|
279
|
+
|
|
280
|
+
- **Discovery** — listen for `subagents:ready` before calling; treat its absence as "not available here" (give discovery a timeout).
|
|
281
|
+
- **Ping** — `subagents:rpc:ping` returns the protocol version.
|
|
282
|
+
- **Spawn** — `subagents:rpc:spawn` with `type`, `prompt`, and `options` (e.g. `{ description, run_in_background, model, cwd }`). `options.model` accepts a `Model` object or `"provider/modelId"` string (resolved against `ctx.modelRegistry`). `options.cwd` runs the agent in another directory (`.pi` still loads from the parent project).
|
|
283
|
+
- **Stop** — `subagents:rpc:stop` with `agentId`.
|
|
284
|
+
|
|
285
|
+
Reply channels are scoped per `requestId`, so concurrent requests don't interfere.
|
|
286
|
+
|
|
287
|
+
## Persistent Agent Memory
|
|
288
|
+
|
|
289
|
+
Set `memory` in frontmatter to enable memory across sessions:
|
|
290
|
+
|
|
291
|
+
| Scope | Location | Use case |
|
|
292
|
+
|-------|----------|----------|
|
|
293
|
+
| `project` | `.pi/agent-memory/<name>/` | Shared across the team (committed) |
|
|
294
|
+
| `local` | `.pi/agent-memory-local/<name>/` | Machine-specific (gitignored) |
|
|
295
|
+
| `user` | `~/.pi/agent-memory/<name>/` | Global personal memory |
|
|
296
|
+
|
|
297
|
+
Memory uses a `MEMORY.md` index plus individual files. Agents with write tools get full read-write;
|
|
298
|
+
**read-only agents** (no `write`/`edit`) automatically get read-only memory to prevent unintended
|
|
299
|
+
tool escalation. `disallowed_tools` is respected when detecting write capability.
|
|
300
|
+
|
|
301
|
+
## Worktree Isolation
|
|
302
|
+
|
|
303
|
+
Set `isolation: worktree` to run an agent in a temporary git worktree. On completion: no changes →
|
|
304
|
+
cleaned up; changes made → committed to a `pi-agent-<id>` branch and returned; agent committed its
|
|
305
|
+
own work → branch created at its HEAD. The preservation commit uses `--no-verify` (local-only,
|
|
306
|
+
never pushed). If the worktree can't be created, the tool returns a clear error — `worktree` is a
|
|
307
|
+
strict guarantee, not a hint.
|
|
308
|
+
|
|
309
|
+
## Skill Preloading
|
|
310
|
+
|
|
311
|
+
Preload named skills into the agent's system prompt (`skills: api-conventions, error-handling`).
|
|
312
|
+
Discovery roots, checked in order (first match wins): `<cwd>/.pi/skills/`, `<cwd>/.agents/skills/`,
|
|
313
|
+
`$PI_CODING_AGENT_DIR/skills/` (default `~/.pi/agent/skills/`), `~/.agents/skills/`, `~/.pi/skills/`.
|
|
314
|
+
Within a root a skill `foo` resolves to `<root>/foo.md`, `<root>/foo/SKILL.md`, or a directory skill
|
|
315
|
+
found by recursive descent (skipping dotdirs and `node_modules`). Symlinks are rejected at every
|
|
316
|
+
layer; path-traversal skill names are rejected.
|
|
317
|
+
|
|
318
|
+
## Requirements
|
|
319
|
+
|
|
320
|
+
No external binaries. Runs entirely on the pi runtime.
|
|
321
|
+
|
|
322
|
+
## Development
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npm install
|
|
326
|
+
npm run lint # biome check
|
|
327
|
+
npm run typecheck # tsc --noEmit
|
|
328
|
+
npm run test # vitest run
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Architecture
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
src/
|
|
335
|
+
index.ts # Extension entry: tool/command registration, rendering
|
|
336
|
+
types.ts # Type definitions (AgentConfig, AgentRecord, etc.)
|
|
337
|
+
default-agents.ts # Embedded default agent configs (general-purpose, Explore, Plan)
|
|
338
|
+
agent-types.ts # Unified agent registry (defaults + user), tool name resolution
|
|
339
|
+
agent-runner.ts # Session creation, execution, graceful max_turns, steer/resume
|
|
340
|
+
agent-manager.ts # Agent lifecycle, concurrency queue, completion notifications
|
|
341
|
+
cross-extension-rpc.ts # RPC handlers for cross-extension spawn/ping via pi.events
|
|
342
|
+
group-join.ts # Batched completion notifications with timeout
|
|
343
|
+
custom-agents.ts # Load user-defined agents from .pi/agents/, .agents/agents/, global
|
|
344
|
+
memory.ts # Persistent agent memory (resolve, read, build prompt blocks)
|
|
345
|
+
skill-loader.ts # Preload skills (Pi-standard + Agent Skills spec layouts)
|
|
346
|
+
output-file.ts # Streaming output transcripts
|
|
347
|
+
worktree.ts # Git worktree isolation (create, cleanup, prune)
|
|
348
|
+
prompts.ts # Config-driven system prompt builder
|
|
349
|
+
context.ts # Parent conversation context for inherit_context
|
|
350
|
+
env.ts # Environment detection (git, platform)
|
|
351
|
+
subagent-env.ts # PI_SUBAGENT_MODEL / CLAUDE_CODE_SUBAGENT_MODEL overrides (fork)
|
|
352
|
+
ui/
|
|
353
|
+
agent-widget.ts # Persistent widget: spinners, activity, status icons, theming
|
|
354
|
+
conversation-viewer.ts # Live conversation overlay for viewing agent sessions
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Fork notes (PI_SUBAGENT_MODEL / CLAUDE_CODE_SUBAGENT_MODEL)
|
|
358
|
+
|
|
359
|
+
This fork adds support for picking the **default subagent model from an environment
|
|
360
|
+
variable**, mirroring claude-code's
|
|
361
|
+
[`CLAUDE_CODE_SUBAGENT_MODEL`](https://docs.claude.com/en/docs/claude-code/subagents) hook.
|
|
362
|
+
|
|
363
|
+
| Variable | Precedence | Notes |
|
|
364
|
+
|---|---|---|
|
|
365
|
+
| `PI_SUBAGENT_MODEL` | 1 (highest) | Fork-specific. |
|
|
366
|
+
| `CLAUDE_CODE_SUBAGENT_MODEL` | 2 | claude-code-compatible; ignored when `PI_SUBAGENT_MODEL` is set. |
|
|
367
|
+
| _unset_ | — | Falls back to existing precedence: caller `Agent({model})` > frontmatter `model:` > inherit parent. |
|
|
368
|
+
|
|
369
|
+
The chosen model **overrides everything** — frontmatter pins and `Agent` `model:` parameters —
|
|
370
|
+
matching claude-code's treatment of the env var as the user's authoritative default. Resolution uses
|
|
371
|
+
the same forgiving matcher as the `Agent` `model` parameter (fuzzy aliases, `provider/modelId`,
|
|
372
|
+
date stamps, provider fallback). A misconfigured value surfaces a `Model not found: …` tool error
|
|
373
|
+
rather than silently falling back; whitespace-only values are treated as unset. Affects in-process
|
|
374
|
+
`Agent` calls; cross-extension RPC callers pick up the same vars in their own process.
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
export PI_SUBAGENT_MODEL=haiku # always run subagents on haiku
|
|
378
|
+
export CLAUDE_CODE_SUBAGENT_MODEL=anthropic/claude-haiku-4-5 # claude-code-compatible
|
|
379
|
+
```
|
package/biome.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
|
|
3
|
+
"linter": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"rules": {
|
|
6
|
+
"recommended": true,
|
|
7
|
+
"style": {
|
|
8
|
+
"recommended": false
|
|
9
|
+
},
|
|
10
|
+
"suspicious": {
|
|
11
|
+
"noExplicitAny": "off",
|
|
12
|
+
"noControlCharactersInRegex": "off",
|
|
13
|
+
"noEmptyInterface": "off"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"formatter": {
|
|
18
|
+
"enabled": false
|
|
19
|
+
},
|
|
20
|
+
"files": {
|
|
21
|
+
"includes": [
|
|
22
|
+
"src/**/*.ts",
|
|
23
|
+
"test/**/*.ts"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ladbabynpm/picc-subagents",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Claude Code style Agent tool for pi agent. Fork of tintinweb/pi-subagents, better aligned with the harness of Claude Code.",
|
|
5
|
+
"author": "ladbabynpm",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/ladbaby/picc-subagents.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/ladbaby/picc-subagents#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/ladbaby/picc-subagents/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"pi-package",
|
|
17
|
+
"pi",
|
|
18
|
+
"pi-extension",
|
|
19
|
+
"subagent",
|
|
20
|
+
"agent",
|
|
21
|
+
"autonomous"
|
|
22
|
+
],
|
|
23
|
+
"files": [
|
|
24
|
+
"src/",
|
|
25
|
+
"package.json",
|
|
26
|
+
"tsconfig.json",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"biome.json"
|
|
31
|
+
],
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@earendil-works/pi-ai": ">=0.80.0",
|
|
34
|
+
"@earendil-works/pi-coding-agent": ">=0.80.0",
|
|
35
|
+
"@earendil-works/pi-tui": ">=0.80.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@sinclair/typebox": "^0.34.49",
|
|
39
|
+
"croner": "^10.0.1",
|
|
40
|
+
"nanoid": "^5.0.0"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:watch": "vitest",
|
|
50
|
+
"test:e2e": "vitest run e2e --reporter=verbose",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint": "biome check src/ test/",
|
|
53
|
+
"lint:fix": "biome check --fix src/ test/"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@biomejs/biome": "^2.4.14",
|
|
57
|
+
"@earendil-works/pi-ai": "^0.80.6",
|
|
58
|
+
"@earendil-works/pi-coding-agent": "^0.80.6",
|
|
59
|
+
"@earendil-works/pi-tui": "^0.80.6",
|
|
60
|
+
"@types/node": "^25.5.0",
|
|
61
|
+
"typescript": "^6.0.0",
|
|
62
|
+
"vitest": "^4.0.18"
|
|
63
|
+
},
|
|
64
|
+
"pi": {
|
|
65
|
+
"extensions": [
|
|
66
|
+
"./src/index.ts"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|