all repos — dot @ master

Shell, editor and terminal configuration, and the tools that go with them

skills/pi-subagent/SKILL.md (view raw)

 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
 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
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
---
name: pi-subagent
description: >-
  Delegates work to one or more headless `pi` subagents on any provider/model,
  run in the background, and collects each one's final answer plus its actual
  billed cost. Covers a single delegated task, the same task fanned out to
  several models for independent answers, or a job split into separate tasks
  run in parallel, followed by verifying what came back; a run saved as a
  session can be followed up, resumed after a timeout, or forked. Use when
  the user asks for subagents, to hand something to another model, to get several
  models' takes, or to parallelize work across pi runs — and when another
  skill (such as pi-review-panel) builds on it. Spawning costs money: never
  start subagents on your own initiative without the user asking.
---

# pi subagents

Run `pi` headless as a subagent: a fresh process, a written brief, no memory of
this conversation, one final answer. You stay the orchestrator. Subagents
produce raw material; you check it before it reaches the user.

The fiddly parts (hang avoidance, output extraction, cost accounting, keeping
failed attempts) are solved in `run-agent.sh` next to this file. Use it. Don't
hand-roll `pi -p` invocations — the flag set and the redirection shape are
load-bearing, and the failure modes are silent hangs. The reasons are at the
top of the script. `$SK` below is this skill's directory.

## 0. Shape the job

Pick one of three shapes, and say which to the user if it isn't obvious:

| shape | what | when |
|---|---|---|
| **delegate** | one task, one model | a self-contained job worth running elsewhere: a long investigation, a second opinion from a specific model, work you want off your own context |
| **fan-out** | one brief, N models | you want independent answers to compare: reviews, designs, hard questions. Disagreement is the signal |
| **split** | N briefs, one model each | a job that divides cleanly into parts that don't depend on each other's results |

A subagent knows nothing you don't write down, can't ask you anything, and
can't see your other subagents. If the parts of a split need each other's
output, it's a sequence, not a split — run it in stages.

**Models.** Use exactly the provider/model pairs the user names; don't add
others. If they named none, ask — or, for a fan-out, offer the default panel in
the pi-review-panel skill. Check a name resolves first:
`pi --offline --list-models <search>`. Credentials are already configured in
`pi`.

## 1. Set up a workdir

```bash
P="$(mktemp -d -t pi-subagent)"; mkdir -p "$P/out"
```

`$P` is scratch. One workdir per job; several briefs can live in it
(`$P/brief-<part>.md`), and every run writes `$P/out/<name>.*`.

**Snapshot the inputs.** If the subagents will read files someone else may be
editing — including you — record their content hash now and re-check before you
use the answers. Input that changes mid-run invalidates parts of their
reasoning, and you need to know that happened.

## 2. Write the brief

The brief is the whole interface. Write it as if for a capable contractor who
has never seen the project and will not get to ask questions:

- **The task, first sentence.** What you actually want. "Find bugs in this
  diff" and "propose a better design than this one" produce very different
  work; don't leave it to be guessed.
- **Context.** One paragraph on the project (from its README) and on why this
  task exists.
- **The material, inline** in fenced blocks, even if you also give paths — the
  subagent should not have to go looking for the thing it's about.
- **Absolute paths** of relevant files and directories, so it can read the
  surroundings with its tools.
- **Criteria**, as hard requirements. If the user gave criteria, quote them
  verbatim.
- **Evidence rules.** Verify empirically before asserting, and say which
  command, interpreter, or version produced each claim. Distinguish what was
  run from what was reasoned.
- **What it may touch** — see §3 — stated plainly. `pi` has edit and write
  tools and will use them unless told, or prevented.
- **The deliverable**: format, sections, length. End with a **fixed final
  line** where answers will be compared — `VERDICT: SHIP` /
  `VERDICT: DO NOT SHIP`, `ANSWER: <x>`, `STATUS: DONE` /
  `STATUS: BLOCKED — <why>`. Fixed strings make the tally and the success check
  mechanical.
- **No questions, no follow-ups.** Deliver the full result as the final answer;
  don't ask for confirmation, don't offer further work.

## 3. Decide what it may touch

Subagents share this machine and its filesystem. Constrain them in this order
of preference:

1. **Read-only by construction**: `--tools read,grep,find,ls`. No shell, so it
   can't run or change anything. Right for pure reading and reasoning.
2. **Read-only by instruction**: default tools (bash included), with the brief
   saying everything is read-only. Needed when the subagent must run things to
   verify claims — tests, interpreters, measurements. Tell it to put scratch
   files under its own `$P/scratch-<name>/` and nowhere else.
3. **Writes, isolated**: give each writing subagent its own git worktree and
   pass it as `--cwd`; never let two writers share a tree, and never point one
   at the user's working copy. Worktrees go under
   `~/x/worktrees/<repo>/<name>`. You review and bring over the result; the
   subagent doesn't commit, push or post anything — say so in the brief.

Context files (AGENTS.md/CLAUDE.md) are off by default, so the brief is the
only instruction a subagent gets. Pass `--context-files` when it works inside
a repo whose conventions it must follow.

## 4. Launch

Always in the background, so you can keep working:

```bash
"$SK/run-agent.sh" "$P" <provider> "<model>" <name> > "$P/out/_<name>.log" 2>&1 &
```

Options go before the positionals: `--brief FILE` (default `$P/brief.md`),
`--timeout SECS` (default 1800), `--thinking LEVEL` (default `high`),
`--tools LIST`, `--cwd DIR`, `--context-files`, `--deliver TEXT`, and
`--session` to keep the conversation for a follow-up (§10). Names must be
unique within a workdir; a natural scheme is `<provider-abbrev>-<model>` for a
fan-out and `<part>` for a split.

A fan-out of one brief to three models:

```bash
"$SK/run-agent.sh" "$P" fireworks  "accounts/fireworks/models/kimi-k3" fw-kimi-k3 > "$P/out/_fw-kimi-k3.log" 2>&1 &
"$SK/run-agent.sh" "$P" openrouter "z-ai/glm-5.3"                      or-glm-5.3 > "$P/out/_or-glm-5.3.log" 2>&1 &
"$SK/run-agent.sh" "$P" openrouter "google/gemini-3.7-flash"           or-gemini  > "$P/out/_or-gemini.log"  2>&1 &
```

A split, each part with its own brief:

```bash
for part in parser cli docs; do
  "$SK/run-agent.sh" --brief "$P/brief-$part.md" "$P" openrouter "z-ai/glm-5.3" "$part" \
    > "$P/out/_$part.log" 2>&1 &
done
```

## 5. Monitor — and work meanwhile

Expect minutes to tens of minutes per run. Check progress with:

```bash
"$SK/status.sh" "$P"                # once: running names, then the table so far
"$SK/status.sh" --wait 60 "$P"      # block until all are done (exit 0)
```

`status.sh` exits 3 while anything is still running, and also prints free disk
space — the event streams are big while runs are in flight.

**Get woken instead of waiting.** In an interactive pi, the `alarm` tool can
fire when processes exit. Launch, set one alarm on all the runs' PIDs, and end
your turn: when the last run exits, the alarm starts a new turn, or arrives
after the tool call in progress if you're busy by then. For the PIDs, print
`$!` after each launch in the same bash call, or read `"$P"/out/*.running`,
which holds each run's PID while it's in flight.

```
alarm action=set when_exits=[<pids>] in_minutes=<the --timeout, in minutes, + 5>
  note="pi-subagent runs <names> in <$P> have ended. Run <$SK>/status.sh <$P>,
        handle failures (§6), verify (§7), report with the cost table (§8)."
```

- Write the note with absolute paths. By the time it fires, this context may
  have been compacted away.
- One alarm per PID wakes you as each run ends instead. That's worth it for a
  long split whose parts you can check as they come; for a fan-out, one
  alarm for all is the point.
- The alarm sees no exit status. `status.sh` has it.
- The deadline is a backstop, in case a run hangs past its own timeout.
- In Claude Code, which has no `alarm` but wakes you when a background Bash
  task exits: launch the whole job as one `run_in_background` command that
  starts the runs with `&` and ends with `wait`, and end your turn.
- Without either (pi in print or RPC mode), monitor with `status.sh`.

**Don't sit on the wait loop.** With an alarm set, there's nothing to wait
for. Otherwise, launching early is only worth it if you use the time: do your
own investigation of the same question, build whatever harness you'll need to
check the answers, establish baselines. You need your own
evidence in §7 regardless. When you do block, give the shell call a timeout
and loop, rather than one unbounded wait.

## 6. Handle failures

A run succeeded if `$P/out/<name>.md` is non-empty and (when you asked for one)
ends with the fixed final line. Exit 124 is the timeout firing. `<name>.err`
and `<name>.jsonl` say what happened otherwise.

Retry a failure once, under the same name: `run-agent.sh` moves the failed
run's files to `<name>.attempt<N>.*` first, cost included. A run started with
`--session` that timed out after real progress is often better continued than
retried: `--followup` it (§10), and it picks up with everything it had read
and run. If it fails twice, report it with its cost and carry on — one dead
provider must not sink the job.
For a split, a failed part is a gap you either fill yourself or report.

## 7. Verify, then use

What comes back is raw material, not results:

- **Reproduce every substantive claim** before passing it on. Models
  hallucinate line numbers, APIs, file contents and measurements, with
  confidence.
- **Disagreement is where the answer is.** When answers conflict, run the
  experiment that decides it and say who was right. With sessions (§10) you
  can also put each side's claim to the other first — but a subagent
  conceding or holding firm is not evidence either; the experiment is.
- **Ask for the evidence.** With a session, a vague or surprising claim can be
  followed up: "show the exact command and output behind X".
- **Consensus is weak evidence.** Several models agreeing can all be making the
  same mistake, or testing the same wrong version. One claim you confirmed
  outranks four you didn't.
- **Check what was actually tested.** Watch for a claim true of a variant but
  not of the thing written — a subagent "verifying" code it silently fixed
  first.
- **Distrust your own harness too.** A test extracted to run standalone can
  fail for reasons of its own (a missing import, a swallowed exception) that
  look exactly like the bug under discussion. Check the baseline passes what it
  should.
- **Written work**, from a worktree: read the whole diff and run the tests
  yourself before bringing any of it over. Never merge it unseen.

Say what you dropped and why, alongside what you kept — that's what makes the
kept part trustworthy.

## 8. Report cost

Every report that used subagents ends with the cost table; the user should
never have to ask. `status.sh` prints it: per run, from the provider's own
per-message `usage.cost` — billed figures, not estimates — failed attempts as
their own rows, then the total. A timed-out run bills for every token it
generated and can be the most expensive line. When cost per useful result
varies a lot across models, say so: it informs who to use next time.

## 9. Keep what matters

`$P` won't survive the session. If the answers matter, copy the `.md` outputs,
the cost files, and any verification scripts somewhere durable in the project,
and link those instead of `$P`.

## 10. Follow up, resume, fork

Off by default: a run saves nothing, and once it ends it can't be talked to
again. Pass `--session` at launch when you expect to come back to it — a long
run that may time out, a fan-out whose disagreements you'll want to put back
to the subagents, anything you may need to question. It costs nothing extra
until used. The session is kept as `$P/sessions/<timestamp>_<name>.jsonl`.

Then, once that run has finished:

```bash
# Continue the same conversation. Provider and model may differ from before.
"$SK/run-agent.sh" --followup "<message>" "$P" <provider> "<model>" <name>

# Branch it into a new name; the original session is left as it was.
"$SK/run-agent.sh" --fork <name> --followup "<message>" "$P" <provider> "<model>" <new-name>
```

- **Uses.** Continue a run that timed out ("You were cut off. Carry on from
  where you stopped and deliver the full result"). Ask for the evidence behind
  a claim. Put another subagent's contradicting finding to it ("Another
  reviewer says X, because Y. Check it and say who is right, with evidence").
  Fork to ask several different questions of the same context without them
  seeing each other, or to hand a whole investigation to a different model —
  it reads the full history, whoever produced it.
- **The message is sent as written.** No brief, no `--deliver` wrapper, so say
  what to deliver and end with the same fixed final line if you'll tally it.
- **What carries over.** A follow-up or fork inherits `--tools`, `--thinking`,
  `--cwd` and `--context-files` from the run it continues, so a read-only
  subagent stays read-only; pass one again to change it.
- **Outputs.** The earlier round's files move to `<name>.round<N>.*`, so every
  answer is kept and every round is its own row in the cost table. Each
  follow-up resends the whole conversation as input: a short question to a long
  session is not cheap.
- **Limits.** A run killed mid-step loses that step; everything before it is
  in the session. `run-agent.sh` refuses to follow up or fork a run still in
  flight. A fresh retry under the same name (no `--followup`) starts a new
  conversation and moves the old session aside.
- **Don't hand-roll the resume.** By id, pi looks only among sessions started
  in the current directory, and where it finds none it silently starts a new,
  empty one under that id — exit 0, and an answer from a model that remembers
  nothing. `run-agent.sh` opens the session by its file path instead.