Orchestrator playbook — the full delegation contract (research pipeline, subagent output contract, spawn economics, forks, teammate lifecycle, verification procedure, chair hygiene). The chair MUST load this before its first delegation of every session; the core only summarizes it.
Scanned 8/30/2026
Install to Claude Code
npx -y skills add Rylaa/fable5-opus5-orchestrator --skill playbook --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Playbook?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/rylaa-playbook)More formats (shields.io, HTML) on the badges page.
---
name: playbook
description: Orchestrator playbook — the full delegation contract (research pipeline, subagent output contract, spawn economics, forks, teammate lifecycle, verification procedure, chair hygiene). The chair MUST load this before its first delegation of every session; the core only summarizes it.
---
# Orchestrator Playbook
Applies to both chair profiles (FABLE and OPUS). The injected core wins
on routing and limits; this file is the detail behind it.
## Research pipeline — parallel fan-out, no mid-flight dumps
YOU pick the questions and sources — never a fetch worker. ONE sonnet
(`medium`) per source: it fetches the source VERBATIM to
./.workflow/scratch/ FIRST (the disk copy is the audit trail — no
filtering during fetch), THEN returns a brief from that copy: claims,
evidence, exact quotes, confidence, contradictions, and the path. A
final sonnet (`high`) synthesizes across the briefs. YOU check the
synthesis and its verbatim evidence against the ledger and decide.
Intermediates never enter your context.
## Subagent output contract (enforced)
Every subagent returns:
1. ledger items addressed, by number
2. summary
3. VERBATIM code/config/errors/quotes the conclusion depends on —
at most 10 lines inline; anything longer goes to
./.workflow/scratch/ and the report carries the path
4. confidence: "confident" / "uncertain because X"
5. "out of scope but noticed"
Reports are at most 40 lines TOTAL. A violating return is rejected and
re-run, never silently accepted.
## Spawn economics — batch before you multiply
Every spawn pays a fixed overhead (system prompt, project rules, tool
schemas) before any useful work. Batch similar mechanical steps into ONE
worker with a checklist; spawn separately only when parallelism or
isolation pays for it. Read-only agents share the repo; parallel
EDITORS each run with `isolation: "worktree"`.
## Worktrees — open one, land it, remove it
Parallel EDITORS get `isolation: "worktree"` each. A single editor does
not need one, and read-only agents never do. The harness auto-removes a
worktree only when it is UNCHANGED, which an editor's never is, so every
one you open is yours to close.
The worker's report NAMES its worktree path and its branch. A report
without them is incomplete and gets re-run like any other contract
violation — you cannot land what you cannot find.
Then, when you accept the report and BEFORE you dismiss the teammate:
1. LAND it — merge or cherry-pick the branch into the branch you are on.
You are the only actor that sees every wave, so a conflict between
two editors is yours to resolve, never theirs.
2. REMOVE it — `git worktree remove <path>`, then delete the branch once
it is merged. Not "later": later is how a leftover happens.
3. PRUNE — `git worktree prune` when a directory disappeared on its own
and left a record `git worktree list` still shows.
A worktree you cannot remove — dirty, or carrying commits that never
landed — is REPORTED to the user with its path. Never forced, never left
silent. Same for a branch you did not merge.
Measured on one machine, 2026-08-27: seven repositories carrying extra
worktrees, a stale record from April, and a live worktree parked in a
finished session's scratchpad. Nothing here had ever said whose job it
was.
## Forks
`subagent_type: "fork"` clones your FULL conversation at your model
and spends the usage limit: at most 2 per session, only while the
conversation is short, and only for bounded follow-ups that lean on
context a spec cannot carry. Forking a plan's phases is disguised solo
work — phases go to workers with specs.
## Named teammates — the user watches the work
NAME every substantive worker (implementation, review, research,
verification): named teammates run in tmux panes the user watches live,
and their lifecycle states reach the chat; an unnamed subagent is a
silent spinner until it returns. Only sub-minute lookups (a grep, one
read/fetch) stay unnamed. Steer a running teammate with SendMessage —
and a steering message is a SPEC, not a nudge. It carries the same
specificity the original brief did: the file, the line, the exact
string. The worker is mid-task and will not go looking. Measured
2026-08-27: a ledger item sent as one sentence was not done; the same
item re-sent with a file and a line number was.
Once its final report is ACCEPTED with no follow-up planned, dismiss
it: SendMessage `{"type": "shutdown_request"}`. Dismissal is final, so
process the output first — and never leave finished teammates stacked
(the plugin reaps forgotten panes).
## Watchdog — a spawn is not a start
"Spawned successfully" means a pane opened, not that a session booted:
measured twice in one day, whole waves lived past 20 minutes with no
session log while the chair called them running. Time is not progress.
Every async wave carries one more teammate, `watchdog` (sonnet, low).
Its job is to LOOP `python3 "<path in your profile>" --watch` — each
call polls read-only and returns in ~100s, so it calls again — and to
message the chair only on `unborn` (process alive, no log) or
`stalled` (log quiet past the threshold). The last line of each call
says which it is: `NOT DONE` with the command to repeat, or `DONE` when
there is something to report. A watchdog that returns on a quiet poll
leaves the wave unwatched, so the instruction rides the output rather
than the brief alone. A healthy `starting ->
working` transition is not news. The chair idles as usual, never polls.
It covers named `Agent` and `Task` spawns only, never `Workflow`: a
workflow names a script rather than an agent, so recording one would
park a name no log can match — a standing `unborn` alarm instead of a
gap.
Nothing is killed for you. On an alarm: ping; with no reply dismiss the
pane and RE-SPAWN — that is the default, because the work was delegated
for a reason and a stall does not shrink it. Taking it back yourself is
bounded by Rule 0 like anything else: one mechanical file, and you say
so.
## What the chair actually does
The chair's one act is the comparison: I said this, you did that. It
owns the work, hands it out, sequences it, judges what comes back — it
does not write the code. That comparison needs an account of the
delivery it can TRUST, and the builder's own report is not one: the
party being checked wrote it. The verifier is the CHAIR'S EYES, not a
gate at the end. Reading delegates; judgement does not. So the chair
reads reports, not diffs, and opens the code only when a report cannot
settle it — worker and verifier disagree, the report itself looks
wrong, or the decision hinges on short exact content, which Chair
context hygiene below tells you to read for yourself.
Rule 0's one writing exception — a single mechanical file — still
cannot close itself. Its `V.` goes to the verifier, or to the deferral
the user grants under SKIPPING; either way the reader is not you.
## Verification procedure
Review STREAMS. It does not wait for the end, because the end is where
a chair discovers that four items it called finished were never read by
anyone. Measured: a live run sat at 35 open and 0 done while the user
was told four were done.
PER ITEM, THE MOMENT IT TURNS `- [/]`. You mark the item
delivered-awaiting-review and spawn a reviewer for THAT ITEM ALONE, in
the BACKGROUND, at once — running BESIDE the next wave, never after it.
Hand it three things and nothing else: the item's ledger line, the diff
that claims to satisfy it, and the tests that item touches. It runs
those tests. It FIXES small defects itself — a wrong constant, a
missing guard, a test still pinning the old string — because a round
trip through the chair to change one line costs more than the line.
What it cannot fix, or judges wrong at the design level, it REPORTS,
and you reopen the item to `- [ ]` for re-dispatch.
`- [/]` is what makes delivered-but-unread visible, and it BLOCKS the
close exactly as `- [ ]` does, so no item reaches `- [x]` without a
reader who is not its builder.
ONE WRITER. Reviewers REPORT; the CHAIR marks. Several background
reviewers editing one file clobber each other, and the loser is silent
— the mark is simply not there on the next read.
WHERE A REVIEW WRITES. Anything that belongs on disk rather than in a
report — a wave-grain sweep on a long job, an item review too big to
quote — goes to ./.workflow/FINDINGS-<topic>-w<N>.md, one file per wave
so two background reviewers never append to one file and clobber each
other. Ledger form, `- [ ] W2.3 <finding>`, kept OUT of LEDGER*.md:
hooks read that path and raw findings there fire the stop guard on
noise — and one NAMED LEDGER-* is worse still, because find_ledger()
takes the most recent LEDGER*.md and a file carrying no
`## Clarified`/`## Approved` denies every later spawn. A wave-grain
review reads a PINNED ref — the sha in the chair's repo where that
wave's work landed, after any worktree branches are merged back — never
the live working tree the next wave is editing. You promote the real
findings into numbered ledger items and close the W-item `- [x]` when
you do. Nothing enforces that: no hook reads FINDINGS-*, so a W-item
you forget to promote is in no ledger, reaches no final pass, and goes
when the topic does. Promotion is a habit, not a guard.
FINAL INTEGRATION — the pass that closes `V.` A per-item review sees
one item, so it cannot see two items that are each correct alone and
broken together. One short pass survives at the end for exactly that:
the FULL test suite, plus ONE agent that is FRESH — it has not worked
on the task — over the COMBINED diff. Give it the original request, the
ledger path, and THE DIFF: a `git diff <base>..HEAD` command or a patch
file on disk, plus the report paths. Never the raw scratch dump, and
never "go find what changed": an agent that must locate the change
spends its budget looking instead of checking. It reads the FINDINGS
files rather than re-deriving them, and narrows to what no per-item
review could reach — items nobody claimed, and collisions where two
items touched the same lines. Only it closes the `V.` ledger item.
MORE THAN ONE REPOSITORY. `git diff <base>..HEAD` is a single-repo
command, so a change spanning two repositories gets ONE VERIFIER PER
REPOSITORY — each with its own diff command and the same ledger, run in
parallel. Tell each one which contracts are SHARED (a type, an API
shape, a status name) and require its report to state what it changed on
its side and what it consumes from the other. Then YOU compare the two
reports: a rename that lands in one repository and not the other breaks
nothing inside either, so the chair holding both reports is the only
place that mismatch is visible. `V.` closes when both reports are in and
that comparison is clean.
TIER AND EFFORT. The final pass is opus, effort FLOOR `medium` — never
`low`. `xhigh` is the normal ceiling; `max` is for complex STRUCTURE,
not mere size. Size it on how hard the change is to JUDGE, never on
line count: a hundred one-line mechanical edits are `medium`, three
files of interlocking state are `xhigh`. A per-item reviewer is sized
the same way and is usually sonnet — one item, one diff, one test file.
CYCLES. Findings become new phases; re-verify. Stop as soon as a cycle
finds nothing NEW — a repeated finding is disagreement, not progress,
and a third fresh reader repeats it again: put it to the user instead.
CAP: 3 verify→fix cycles regardless, then STOP and report open items.
SKIPPING. On a small diff the chair may PROPOSE a skip of the final
pass. With the user's ok `V.` is recorded `- [~] deferred: <reason>` —
a deferral the USER granted, never a pass the chair awarded itself, and
`- [x]` still belongs to the verifier alone. When the diff is the
chair's own lone mechanical edit, SAY so in the proposal: the user
becomes the fresh reader, and they need to know that is what they are
agreeing to. Nothing enforces any of this — the stop guard only stops
counting a line once it is neither `- [ ]` nor `- [/]`, so `- [~]` with
no reason and no user behind it closes just as quietly. The marker is a
record of a decision someone made, not proof that they made it.
## Decisions you make after the go
A choice the chair makes once the workers are out — where a new field
lives, which module owns a helper, which of two call sites is the real
one — is not a discovery and not a requirement, and until now it had
nowhere to go. It goes under `## Decisions` in the ledger: plain
bullets, one line each, with the reason.
The verifier is handed the original request, the ledger and the diff,
and nothing else. A load-bearing decision that lives only in a spawn
prompt is invisible to it, so it reads the result as unexplained and
files it as a finding. Measured 2026-08-27: a chair moved two new
fields onto a shared type mid-flight, wrote the reason into the spawn
prompt, and left no trace of it anywhere the verifier would look.
Hooks ignore the section — they scan `## Clarified`, `## Approved` and
`## Read` only — so nothing enforces it. Its readers are the verifier and the
next session.
## What it cost — every close reports it
`scripts/token_report.py` reads the session logs and answers "what did
this job cost" without anyone estimating: each assistant record carries
`message.usage` and the model that served it, and a named teammate is a
full session with its own log whose records declare `agentName`. Spend
per agent, per model, plus the total.
Two savings lines are arithmetic on what was recorded — cache reads bill
at 0.1x input, so 0.9x of their full-price cost never left the account;
and output that ran on a cheaper tier is priced against the tier the
chair would otherwise have used. A third line, the output style, is
NOT measurable: the unstyled answer was never generated, so there is
nothing to compare against. The report prints the ratio it assumed and
the arithmetic beside it. Quote it the way it is printed — measured and
assumed on separate lines — and never fold the three into one number.
Run it at the close, unasked, and give the user the total plus the two
measured lines. `FABLE_ORCH_STYLE_RATIO=0` drops the assumed one.
## Chair context hygiene
Consume briefs + verbatim snippets; bulk stays on disk. When a decision
hinges on short exact content, read it yourself — never decide on a
summary when the source fits in a few hundred lines. Prefer per-task
sessions: the ledger and scratch survive /clear — finish one, close it,
start the next clean. Drop closed-phase raw material; keep outputs
minimal; parallelize independent calls.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!