pi-herdr-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/.github/workflows/publish.yml +55 -0
- package/.pi/settings.json +8 -0
- package/.pi/skills/run-integration-tests/SKILL.md +28 -0
- package/LICENSE +21 -0
- package/README.md +483 -0
- package/RELEASING.md +103 -0
- package/agents/planner.md +546 -0
- package/agents/reviewer.md +150 -0
- package/agents/scout.md +104 -0
- package/agents/visual-tester.md +197 -0
- package/agents/worker.md +103 -0
- package/config.json.example +5 -0
- package/package.json +34 -0
- package/pi-extension/subagents/activity.ts +511 -0
- package/pi-extension/subagents/completion.ts +114 -0
- package/pi-extension/subagents/herdr.ts +200 -0
- package/pi-extension/subagents/index.ts +2182 -0
- package/pi-extension/subagents/plan-skill.md +203 -0
- package/pi-extension/subagents/plugin/.claude-plugin/plugin.json +5 -0
- package/pi-extension/subagents/plugin/hooks/hooks.json +15 -0
- package/pi-extension/subagents/plugin/hooks/on-stop.sh +68 -0
- package/pi-extension/subagents/session.ts +180 -0
- package/pi-extension/subagents/status.ts +513 -0
- package/pi-extension/subagents/subagent-done.ts +324 -0
- package/pi-extension/subagents/terminal.ts +106 -0
- package/test/integration/agents/test-echo.md +13 -0
- package/test/integration/agents/test-ping.md +11 -0
- package/test/integration/harness.ts +319 -0
- package/test/integration/mux-surface.test.ts +225 -0
- package/test/integration/subagent-lifecycle.test.ts +329 -0
- package/test/system-prompt-mode.test.ts +163 -0
- package/test/test.ts +2190 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: npm-publish-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
publish:
|
|
18
|
+
name: Test and publish
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Check out repository
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Set up Node.js
|
|
26
|
+
uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: 22
|
|
29
|
+
registry-url: https://registry.npmjs.org
|
|
30
|
+
cache: npm
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: npm ci
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: npm test
|
|
37
|
+
|
|
38
|
+
- name: Verify tag matches package version
|
|
39
|
+
shell: bash
|
|
40
|
+
run: |
|
|
41
|
+
package_version="$(node --input-type=module -e "import pkg from './package.json' with { type: 'json' }; process.stdout.write(pkg.version)")"
|
|
42
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
43
|
+
|
|
44
|
+
if [[ "$package_version" != "$tag_version" ]]; then
|
|
45
|
+
echo "Tag version ($tag_version) does not match package.json ($package_version)."
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
- name: Verify package contents
|
|
50
|
+
run: npm pack --dry-run
|
|
51
|
+
|
|
52
|
+
- name: Publish package
|
|
53
|
+
run: npm publish --access public --provenance
|
|
54
|
+
env:
|
|
55
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-integration-tests
|
|
3
|
+
description: Run the integration test suite and verify all sessions end-to-end. Use when asked to run integration or e2e tests, test before release, or check everything works.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Run integration tests
|
|
7
|
+
|
|
8
|
+
Run this workflow from inside herdr. This project supports no other terminal backend.
|
|
9
|
+
|
|
10
|
+
## Preflight
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
echo "HERDR_ENV=$HERDR_ENV"
|
|
14
|
+
command -v herdr
|
|
15
|
+
npm test
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Stop and ask the user to start pi inside herdr if `HERDR_ENV` is not `1` or the CLI is missing.
|
|
19
|
+
|
|
20
|
+
## Integration suite
|
|
21
|
+
|
|
22
|
+
From the repository root:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run test:integration
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The harness loads the extension directly from the working tree and creates isolated test agents. Report passing, failing, and skipped tests. Do not claim full verification when herdr-dependent tests were skipped.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HazAT
|
|
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
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
# pi-herdr-subagents
|
|
2
|
+
|
|
3
|
+
Async subagents for [pi](https://github.com/badlogic/pi-mono) running exclusively in [herdr](https://herdr.dev). Spawn, orchestrate, and manage sub-agent sessions in dedicated herdr tabs or panes. **Fully non-blocking** — the main agent keeps working while subagents run in the background.
|
|
4
|
+
|
|
5
|
+
https://github.com/user-attachments/assets/30adb156-cfb4-4c47-84ca-dd4aa80cba9f
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Call `subagent()` and it **returns immediately**. The sub-agent runs in its own terminal pane. A live widget above the input shows all running agents with their current state — `starting`, `active`, `waiting`, `stalled`, or `running`. When a sub-agent finishes, its result is **steered back** into the main session as an async notification — triggering a new turn so the agent can process it.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
╭─ Subagents ──────────────────────────── 2 running ─╮
|
|
13
|
+
│ 00:23 Scout: Auth (scout) active · bash 7m │
|
|
14
|
+
│ 00:45 Scout: DB (scout) waiting 2m │
|
|
15
|
+
╰────────────────────────────────────────────────────╯
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For parallel execution, just call `subagent` multiple times — they all run concurrently:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
subagent({ name: "Scout: Auth", agent: "scout", task: "Analyze auth module" });
|
|
22
|
+
subagent({ name: "Scout: DB", agent: "scout", task: "Map database schema" });
|
|
23
|
+
// Both return immediately, results steer back independently
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Install the package explicitly from this repository (replace the URL if you use a fork):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pi install git:github.com/0xRichardH/pi-herdr-subagents
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This project does not install or load `HazAT/pi-interactive-subagents` automatically.
|
|
35
|
+
|
|
36
|
+
For maintainers publishing a release to npm, see [RELEASING.md](RELEASING.md).
|
|
37
|
+
|
|
38
|
+
Start herdr, then run pi inside it:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
herdr
|
|
42
|
+
pi
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
herdr is the only supported terminal environment. The extension requires `HERDR_ENV=1` and the `herdr` CLI to be available.
|
|
46
|
+
|
|
47
|
+
If your shell startup is slow and subagent commands sometimes get dropped before the prompt is ready, set `PI_SUBAGENT_SHELL_READY_DELAY_MS` to a higher value (defaults to `500`):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
export PI_SUBAGENT_SHELL_READY_DELAY_MS=2500
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Subagent tabs and panes are created without stealing keyboard focus. Launch commands target child panes by explicit ID, so focus and command delivery are independent. Note: the `interactive` option controls parent status notifications, not terminal focus.
|
|
54
|
+
|
|
55
|
+
## What's Included
|
|
56
|
+
|
|
57
|
+
### Extensions
|
|
58
|
+
|
|
59
|
+
**Subagents** — 4 main-session tools + 3 commands, plus 1 subagent-only tool:
|
|
60
|
+
|
|
61
|
+
| Tool | Description |
|
|
62
|
+
| -------------------- | ------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `subagent` | Spawn a sub-agent in a dedicated herdr pane (async — returns immediately) |
|
|
64
|
+
| `subagent_interrupt` | Interrupt a running Pi-backed subagent's current turn |
|
|
65
|
+
| `subagents_list` | List available agent definitions |
|
|
66
|
+
| `subagent_resume` | Resume a previous sub-agent session (async) |
|
|
67
|
+
|
|
68
|
+
| Command | Description |
|
|
69
|
+
| -------------------------- | ------------------------------------ |
|
|
70
|
+
| `/plan` | Start a full planning workflow |
|
|
71
|
+
| `/iterate` | Fork into a subagent for quick fixes |
|
|
72
|
+
| `/subagent <agent> <task>` | Spawn a named agent directly |
|
|
73
|
+
|
|
74
|
+
### Bundled Agents
|
|
75
|
+
|
|
76
|
+
| Agent | Model | Role |
|
|
77
|
+
| ----------------- | ---------------------- | ---------------------------------------------------------------------------------------- |
|
|
78
|
+
| **planner** | Opus (medium thinking) | Brainstorming — clarifies requirements, explores approaches, writes plans, creates todos |
|
|
79
|
+
| **scout** | Haiku | Fast codebase reconnaissance — maps files, patterns, conventions |
|
|
80
|
+
| **worker** | Sonnet | Implements tasks from todos — writes code, runs tests, makes polished commits |
|
|
81
|
+
| **reviewer** | Opus (medium thinking) | Reviews code for bugs, security issues, correctness |
|
|
82
|
+
| **visual-tester** | Sonnet | Visual QA via Chrome CDP — screenshots, responsive testing, interaction testing |
|
|
83
|
+
|
|
84
|
+
Agent discovery follows priority: **project-local** (`.pi/agents/`) > **global** (`~/.pi/agent/agents/`) > **package-bundled**. Override any bundled agent by placing your own version in the higher-priority location.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Async Subagent Flow
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
1. Agent calls subagent() → returns immediately ("started")
|
|
92
|
+
2. Sub-agent runs in herdr pane → widget shows live status
|
|
93
|
+
3. User keeps chatting → main session fully interactive
|
|
94
|
+
4. Sub-agent finishes → result steered back as a normal completion/failure
|
|
95
|
+
5. Main agent processes result → continues with new context
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Multiple subagents run concurrently — each steers its result back independently as it finishes. The live widget above the input tracks all running agents:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
╭─ Subagents ───────────────────────────────── 3 running ─╮
|
|
102
|
+
│ 01:23 Scout: Auth (scout) active · write 7m │
|
|
103
|
+
│ 00:45 Researcher (researcher) stalled 4m │
|
|
104
|
+
│ 00:12 Scout: DB (scout) starting… │
|
|
105
|
+
╰─────────────────────────────────────────────────────────╯
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Completion messages render with a colored background and are expandable with `Ctrl+O` to show the full summary and session file path.
|
|
109
|
+
|
|
110
|
+
### In-progress status updates
|
|
111
|
+
|
|
112
|
+
The widget tracks each Pi-backed sub-agent from a child-written runtime snapshot and labels it with a coarse state:
|
|
113
|
+
|
|
114
|
+
- `starting` — launched, but no valid child snapshot has been observed yet
|
|
115
|
+
- `active` — the child is doing observed runtime work: agent turn, provider request, streaming, or tool execution
|
|
116
|
+
- `waiting` — the child finished a turn and is intentionally open for more input or another stage
|
|
117
|
+
- `stalled` — the parent has gone too long without a valid current child snapshot and can no longer trust the run is healthy
|
|
118
|
+
- `running` — fallback for backends without child snapshots (e.g. Claude)
|
|
119
|
+
|
|
120
|
+
These labels are no longer derived from session-file growth. Session JSONL is still used for transcript, resume, lineage, and result extraction, but Pi-backed liveness now comes from a small activity snapshot written by the child extension. A fixed internal watchdog marks a run as `stalled` when valid snapshots never appear, stop being readable, or stop matching the current child; valid long-running `active` or `waiting` states do not become `stalled` just because time passes. When a run enters `stalled` or recovers from it, the parent agent receives a steer message so it can react. All other status transitions stay in the widget only.
|
|
121
|
+
|
|
122
|
+
**Interactive subagents stay silent.** Long-running user-driven subagents (e.g. `planner`, or any `/iterate` fork) do not wake the parent session on `stalled`/`recovered` transitions — the user is working directly in the subagent's pane, and a steer message there would just burn an orchestrator turn on a no-op "still waiting" ping. The widget still updates normally, and child snapshots are still recorded/classified regardless of the `interactive` setting. By default, agents with `auto-exit: true` are treated as autonomous and get stall pings; agents without it are treated as interactive and stay quiet. Override per-agent with `interactive: true|false` in frontmatter, or per-spawn with `interactive: true|false` on the tool call.
|
|
123
|
+
|
|
124
|
+
#### Configuration
|
|
125
|
+
|
|
126
|
+
Status display is controlled by `config.json` in the extension directory. Copy `config.json.example` to get started:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
cp config.json.example config.json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"status": {
|
|
135
|
+
"enabled": true
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`config.json` is gitignored so local overrides don't get committed.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Spawning Subagents
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Named agent with defaults from agent definition
|
|
148
|
+
subagent({ name: "Scout", agent: "scout", task: "Analyze the codebase..." });
|
|
149
|
+
|
|
150
|
+
// Force a full-context fork for this spawn
|
|
151
|
+
subagent({ name: "Iterate", fork: true, task: "Fix the bug where..." });
|
|
152
|
+
|
|
153
|
+
// Agent defaults can choose a different session-mode via frontmatter
|
|
154
|
+
subagent({ name: "Planner", agent: "planner", task: "Work through the design with me" });
|
|
155
|
+
|
|
156
|
+
// Custom working directory
|
|
157
|
+
subagent({ name: "Designer", agent: "game-designer", cwd: "agents/game-designer", task: "..." });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Parameters
|
|
161
|
+
|
|
162
|
+
| Parameter | Type | Default | Description |
|
|
163
|
+
| ---------------------- | ------- | -------------- | ------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| `name` | string | required | Display name (shown in widget and pane title) |
|
|
165
|
+
| `task` | string | required | Task prompt for the sub-agent |
|
|
166
|
+
| `agent` | string | — | Load defaults from agent definition |
|
|
167
|
+
| `fork` | boolean | `false` | Force the full-context fork mode for this spawn, overriding any agent `session-mode` frontmatter |
|
|
168
|
+
| `interactive` | boolean | derived | Mark this spawn as interactive (don't wake the parent on stall/recovery). Defaults to the agent's `interactive` frontmatter, otherwise the inverse of `auto-exit`. |
|
|
169
|
+
| `model` | string | — | Override agent's default model |
|
|
170
|
+
| `systemPrompt` | string | — | Append to system prompt |
|
|
171
|
+
| `skills` | string | — | Comma-separated skill names |
|
|
172
|
+
| `tools` | string | — | Comma-separated tool names |
|
|
173
|
+
| `cwd` | string | — | Working directory for the sub-agent (see [Role Folders](#role-folders)) |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Interrupting a running subagent
|
|
178
|
+
|
|
179
|
+
Use `subagent_interrupt` to cancel the active turn of a running Pi-backed subagent:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
subagent_interrupt({ id: "abcd1234" });
|
|
183
|
+
// or
|
|
184
|
+
subagent_interrupt({ name: "Scout" });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This sends Escape to the child pane, cancelling the in-progress model turn. The subagent session stays alive — the pane, session file, and background polling all remain intact. After the interrupt, the widget immediately moves the child back to `waiting`, and stale pre-interrupt snapshots are ignored. If the child starts work later, newer snapshots return it to `active`; completion, failure, and `caller_ping` still flow through normally.
|
|
188
|
+
|
|
189
|
+
This is a turn-level interrupt, not a method for forcibly terminating a subagent session.
|
|
190
|
+
|
|
191
|
+
> **Note:** Only Pi-backed subagents are supported. Claude-backed runs will return an error.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## caller_ping — Child-to-Parent Help Request
|
|
196
|
+
|
|
197
|
+
The `caller_ping` tool lets a subagent request help from its parent agent. When called, the child session **exits** and the parent receives a notification with the help message. The parent can then **resume** the child session with a response using `subagent_resume`.
|
|
198
|
+
|
|
199
|
+
**`caller_ping` parameters:**
|
|
200
|
+
- `message` (required): What you need help with
|
|
201
|
+
|
|
202
|
+
**`subagent_resume` parameters:**
|
|
203
|
+
- `sessionPath` (required): Path to the child session `.jsonl` file
|
|
204
|
+
- `name` (optional): Display name for the resumed pane (defaults to `Resume`)
|
|
205
|
+
- `message` (optional): Follow-up prompt to send after resuming
|
|
206
|
+
- `autoExit` (optional): Whether the resumed session should auto-exit after its next response. Defaults to `true` for autonomous follow-up work; set `false` when resuming for an interactive handoff.
|
|
207
|
+
|
|
208
|
+
**Interaction flow:**
|
|
209
|
+
1. Child calls `caller_ping({ message: "Not sure which schema to use" })`
|
|
210
|
+
2. Child session exits (like `subagent_done`)
|
|
211
|
+
3. Parent receives a steer notification: *"Sub-agent Worker needs help: Not sure which schema to use"*
|
|
212
|
+
4. Parent resumes the child session via `subagent_resume` with the response
|
|
213
|
+
5. Child picks up where it left off with the parent's guidance
|
|
214
|
+
|
|
215
|
+
**Example:**
|
|
216
|
+
```typescript
|
|
217
|
+
// Inside a worker subagent
|
|
218
|
+
await caller_ping({
|
|
219
|
+
message: "Found two conflicting migration files — should I use v1 or v2?"
|
|
220
|
+
});
|
|
221
|
+
// Session exits here. Parent receives the ping, then resumes this session
|
|
222
|
+
// with guidance like "Use v2, v1 is deprecated"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
> **Note:** `caller_ping` is only available inside subagent contexts. Calling it from a standalone pi session returns an error.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## The `/plan` Workflow
|
|
230
|
+
|
|
231
|
+
The `/plan` command orchestrates a full planning-to-implementation pipeline.
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
/plan Add a dark mode toggle to the settings page
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
Phase 1: Investigation → Quick codebase scan
|
|
239
|
+
Phase 2: Planning → Interactive planner subagent (user collaborates)
|
|
240
|
+
Phase 3: Review Plan → Confirm todos, adjust if needed
|
|
241
|
+
Phase 4: Execute → Scout + sequential workers implement todos
|
|
242
|
+
Phase 5: Review → Reviewer subagent checks all changes
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Tab/window titles update to show current phase:
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
🔍 Investigating: dark mode → 💬 Planning: dark mode
|
|
249
|
+
→ 🔨 Executing: 1/3 → 🔎 Reviewing → ✅ Done
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## The `/iterate` Workflow
|
|
255
|
+
|
|
256
|
+
For quick, focused work without polluting the main session's context.
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
/iterate Fix the off-by-one error in the pagination logic
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
This always forks the current session into a subagent with full conversation context. It does not inherit an agent default `session-mode`. Make the fix, verify it, and exit to return. The main session gets a summary of what was done.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Custom Agents
|
|
267
|
+
|
|
268
|
+
Place a `.md` file in `.pi/agents/` (project) or `~/.pi/agent/agents/` (global):
|
|
269
|
+
|
|
270
|
+
```markdown
|
|
271
|
+
---
|
|
272
|
+
name: my-agent
|
|
273
|
+
description: Does something specific
|
|
274
|
+
model: anthropic/claude-sonnet-4-6
|
|
275
|
+
thinking: minimal
|
|
276
|
+
tools: read, bash, edit, write
|
|
277
|
+
session-mode: lineage-only
|
|
278
|
+
spawning: false
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
# My Agent
|
|
282
|
+
|
|
283
|
+
You are a specialized agent that does X...
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Frontmatter Reference
|
|
287
|
+
|
|
288
|
+
| Field | Type | Description |
|
|
289
|
+
| ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
290
|
+
| `name` | string | Agent name (used in `agent: "my-agent"`) |
|
|
291
|
+
| `description` | string | Shown in `subagents_list` output |
|
|
292
|
+
| `model` | string | Default model (e.g. `anthropic/claude-sonnet-4-6`) |
|
|
293
|
+
| `thinking` | string | Thinking level: `minimal`, `medium`, `high` |
|
|
294
|
+
| `tools` | string | Comma-separated **native pi tools only**: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls` |
|
|
295
|
+
| `skills` | string | Comma-separated skill names to auto-load |
|
|
296
|
+
| `session-mode` | string | Default child-session mode: `standalone`, `lineage-only`, or `fork` |
|
|
297
|
+
| `spawning` | boolean | Set `false` to deny all subagent-spawning tools |
|
|
298
|
+
| `deny-tools` | string | Comma-separated extension tool names to deny |
|
|
299
|
+
| `auto-exit` | boolean | Auto-shutdown when the agent finishes its turn — no `subagent_done` call needed. If the user sends any input, auto-exit is permanently disabled and the user takes over the session. Recommended for autonomous agents (scout, worker); not for interactive ones (planner). Also determines the default value of `interactive` (see below). |
|
|
300
|
+
| `interactive` | boolean | derived | Override whether stall/recovery transitions wake the parent session. Defaults to the inverse of `auto-exit`: autonomous agents (`auto-exit: true`) are non-interactive and get stall pings; agents without `auto-exit` are interactive and stay quiet. Explicit values take precedence. |
|
|
301
|
+
| `cwd` | string | Default working directory (absolute or relative to project root) |
|
|
302
|
+
| `disable-model-invocation` | boolean | Hide this agent from discovery surfaces like `subagents_list`. The agent still remains directly invokable by explicit name via `subagent({ agent: "name", ... })`. |
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
Discovery still resolves precedence before visibility filtering. If a project-local hidden agent has the same name as a visible global or bundled agent, the hidden project agent wins and the lower-precedence agent does not appear in `subagents_list`.
|
|
307
|
+
|
|
308
|
+
### `session-mode`
|
|
309
|
+
|
|
310
|
+
Choose how a subagent session starts:
|
|
311
|
+
|
|
312
|
+
- `standalone` — default fresh session with no lineage link to the caller
|
|
313
|
+
- `lineage-only` — fresh blank child session with `parentSession` linkage, but no copied turns from the caller
|
|
314
|
+
- `fork` — linked child session seeded with the caller's prior conversation context
|
|
315
|
+
|
|
316
|
+
`lineage-only` is useful when you want session discovery and fork lineage UX to show the relationship later, but you do **not** want the child to inherit the parent's turns.
|
|
317
|
+
|
|
318
|
+
`fork: true` on the tool call always forces the `fork` mode for that specific spawn. `/iterate` uses this explicit override on purpose.
|
|
319
|
+
|
|
320
|
+
```yaml
|
|
321
|
+
---
|
|
322
|
+
name: planner
|
|
323
|
+
session-mode: lineage-only
|
|
324
|
+
---
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### `auto-exit`
|
|
328
|
+
|
|
329
|
+
When set to `true`, the agent session shuts down automatically as soon as the agent finishes its turn — no explicit `subagent_done` call is needed.
|
|
330
|
+
|
|
331
|
+
**Behavior:**
|
|
332
|
+
|
|
333
|
+
- The session closes after the agent's final message (on the `agent_end` event)
|
|
334
|
+
- If the user sends **any input** before the agent finishes, auto-exit is permanently disabled for that session — the user takes over interactively
|
|
335
|
+
- The modeHint injected into the agent's task is adjusted accordingly: autonomous agents see "Complete your task autonomously." rather than instructions to call `subagent_done`
|
|
336
|
+
|
|
337
|
+
**When to use:**
|
|
338
|
+
|
|
339
|
+
- ✅ Autonomous agents (scout, worker, reviewer) that run to completion
|
|
340
|
+
- ❌ Interactive agents (planner, iterate) where the user drives the session
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
---
|
|
344
|
+
name: scout
|
|
345
|
+
auto-exit: true
|
|
346
|
+
---
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### `interactive`
|
|
350
|
+
|
|
351
|
+
Controls whether status transitions (`stalled`, `recovered`) wake the parent session with a steer message.
|
|
352
|
+
|
|
353
|
+
**Default:** the inverse of `auto-exit`. Autonomous agents (`auto-exit: true`) are non-interactive and ping the parent on stall/recovery; agents without `auto-exit` are interactive and stay quiet. Bare spawns with no agent defs (e.g. `/iterate` with `fork: true`) are treated as interactive.
|
|
354
|
+
|
|
355
|
+
**Why it exists:** Interactive agents can run for minutes or hours while the user thinks, types, and reads in the subagent's pane. Child snapshots still update the widget, but stalled/recovered supervision messages rarely need to wake the parent for user-driven sessions. Skipping the steer keeps the parent quiet until the child actually finishes.
|
|
356
|
+
|
|
357
|
+
**When to override:**
|
|
358
|
+
|
|
359
|
+
- Set `interactive: false` on an agent that doesn't auto-exit but you still want stall pings for
|
|
360
|
+
- Set `interactive: true` on an autonomous agent you'd rather check on yourself
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
---
|
|
364
|
+
name: planner
|
|
365
|
+
# interactive defaults to true because auto-exit is not set
|
|
366
|
+
---
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Or per spawn:
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
subagent({ name: "Scout", agent: "scout", interactive: true, task: "..." });
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Tool Access Control
|
|
378
|
+
|
|
379
|
+
By default, every sub-agent can spawn further sub-agents. Control this with frontmatter:
|
|
380
|
+
|
|
381
|
+
### `spawning: false`
|
|
382
|
+
|
|
383
|
+
Denies all subagent lifecycle tools (`subagent`, `subagent_interrupt`, `subagents_list`, `subagent_resume`):
|
|
384
|
+
|
|
385
|
+
```yaml
|
|
386
|
+
---
|
|
387
|
+
name: worker
|
|
388
|
+
spawning: false
|
|
389
|
+
---
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### `deny-tools`
|
|
393
|
+
|
|
394
|
+
Fine-grained control over individual extension tools:
|
|
395
|
+
|
|
396
|
+
```yaml
|
|
397
|
+
---
|
|
398
|
+
name: focused-agent
|
|
399
|
+
deny-tools: subagent
|
|
400
|
+
---
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Recommended Configuration
|
|
404
|
+
|
|
405
|
+
| Agent | `spawning` | Rationale |
|
|
406
|
+
| ---------- | ----------- | -------------------------------------------- |
|
|
407
|
+
| planner | _(default)_ | Legitimately spawns scouts for investigation |
|
|
408
|
+
| worker | `false` | Should implement tasks, not delegate |
|
|
409
|
+
| researcher | `false` | Should research, not spawn |
|
|
410
|
+
| reviewer | `false` | Should review, not spawn |
|
|
411
|
+
| scout | `false` | Should gather context, not spawn |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Role Folders
|
|
416
|
+
|
|
417
|
+
The `cwd` parameter lets sub-agents start in a specific directory with its own configuration:
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
project/
|
|
421
|
+
├── agents/
|
|
422
|
+
│ ├── game-designer/
|
|
423
|
+
│ │ └── CLAUDE.md ← "You are a game designer..."
|
|
424
|
+
│ ├── sre/
|
|
425
|
+
│ │ ├── CLAUDE.md ← "You are an SRE specialist..."
|
|
426
|
+
│ │ └── .pi/skills/ ← SRE-specific skills
|
|
427
|
+
│ └── narrative/
|
|
428
|
+
│ └── CLAUDE.md ← "You are a narrative designer..."
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
subagent({ name: "Game Designer", cwd: "agents/game-designer", task: "Design the combat system" });
|
|
433
|
+
subagent({ name: "SRE", cwd: "agents/sre", task: "Review deployment pipeline" });
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Set a default `cwd` in agent frontmatter:
|
|
437
|
+
|
|
438
|
+
```yaml
|
|
439
|
+
---
|
|
440
|
+
name: game-designer
|
|
441
|
+
cwd: ./agents/game-designer
|
|
442
|
+
spawning: false
|
|
443
|
+
---
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Tools Widget
|
|
449
|
+
|
|
450
|
+
Every sub-agent session displays a compact tools widget showing available and denied tools. Toggle with `Ctrl+J`:
|
|
451
|
+
|
|
452
|
+
```
|
|
453
|
+
[scout] — 12 tools · 4 denied (Ctrl+J) ← collapsed
|
|
454
|
+
[scout] — 12 available (Ctrl+J to collapse) ← expanded
|
|
455
|
+
read, bash, edit, write, todo, ...
|
|
456
|
+
denied: subagent, subagents_list, ...
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Requirements
|
|
462
|
+
|
|
463
|
+
- [pi](https://github.com/badlogic/pi-mono) — the coding agent
|
|
464
|
+
- [herdr](https://herdr.dev) — the required terminal workspace
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
herdr
|
|
468
|
+
pi
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Other multiplexers and terminal backends are not supported.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Acknowledgements
|
|
476
|
+
|
|
477
|
+
The sub-agent status supervision and turn-only interruption features were inspired by [RepoPrompt](https://repoprompt.com/)'s sub-agent snapshot polling and run cancellation features.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## License
|
|
482
|
+
|
|
483
|
+
MIT
|