$npx -y skills add andrewstellman/quality-playbook --skill quality-playbook-harnessOrchestrate Quality Playbook (or any) runs across multiple repos from one agent session. Drives a disk-backed state machine one idempotent tick at a time — each tick the tick script reads workers' heartbeats, advances the state machine, and lists which workers to dispatch; the or
| 1 | # Quality Playbook harness |
| 2 | |
| 3 | You are the harness orchestrator. Your entire per-tick job is small and |
| 4 | fixed: run one Python script, dispatch the worker subagents it lists, |
| 5 | print the table it formats, and schedule the next tick. **All** the |
| 6 | state-machine logic lives in `bin/qpb_harness_tick.py` — you never reason |
| 7 | about run state yourself. (Details: `references/STATE_MACHINE.md`.) |
| 8 | |
| 9 | **The worker contract (the whole of it):** *a job is anything that appends |
| 10 | JSON lines to a file.* `status` is the **only** field the harness |
| 11 | interprets; `label` (a short free string shown in the ACTIVITY column), |
| 12 | `message`, and the opaque `data` object are displayed but never read. The |
| 13 | contract honors **Postel's law — conservative in what the harness emits, |
| 14 | liberal in what it accepts**: a worker that never writes, dies, or writes |
| 15 | garbage degrades to a visible STALLED / failed / LAUNCH-FAIL row, never to |
| 16 | a wedged state machine; a malformed line is skipped with a warning, never |
| 17 | fatal. Heartbeats are `schema_version: "2"` (`label`/`data`); the reader |
| 18 | still accepts v1 (`phase`/`step`). **You never read or transcribe a path:** |
| 19 | every harness-known path — including `{HARNESS_BIN}` — is substituted |
| 20 | mechanically by the engine before dispatch (FR-21a). Pass each worker |
| 21 | prompt **verbatim**; it is already fully resolved. |
| 22 | |
| 23 | ## Capability ladder — probe, announce, degrade (do this FIRST) |
| 24 | |
| 25 | The harness degrades along two axes; the disk state machine is identical at |
| 26 | every rung. At startup, PROBE your own tooling and ANNOUNCE the rungs you |
| 27 | selected, in one line to the operator: |
| 28 | |
| 29 | - **Cadence** (how the next tick happens): rung 1 = you have an in-session |
| 30 | scheduling primitive (`ScheduleWakeup`); rung 2 = an OS scheduler; |
| 31 | rung 3 = the foreground `harness_ticker.py` loop; rung 4 = manual ticks. |
| 32 | - **Dispatch** (how workers start): rung 1 = in-session subagents |
| 33 | (`Task`/`Agent`); rung 2 = detached host-CLI processes |
| 34 | (`dispatch_mode: "shell"`). |
| 35 | |
| 36 | As a Claude Code session you run at **cadence 1 + dispatch 1**: you have |
| 37 | `ScheduleWakeup` and a subagent tool, and your session persists across the |
| 38 | workers' lifetime. Announce that: *"Harness: cadence rung 1 (ScheduleWakeup) |
| 39 | + dispatch rung 1 (subagent). Plan has N entries, pool P."* If the plan's |
| 40 | entries are `dispatch_mode: "shell"`, you cannot run them in-session — tell |
| 41 | the operator to drive the run with the ticker (the printed command below) |
| 42 | and stop. |
| 43 | |
| 44 | **Degrade with a printed command (NON-NEGOTIABLE, FR-25).** If ANY |
| 45 | scheduling step fails — you cannot call `ScheduleWakeup`, a wakeup silently |
| 46 | never fires, or the operator asks how to continue elsewhere — print the |
| 47 | EXACT command to continue this run from a plain terminal window, with the |
| 48 | absolute paths filled in: |
| 49 | |
| 50 | To continue this run in another window, execute: |
| 51 | python3 <QPB_REPO>/bin/harness_ticker.py --once <RUN_DIR> |
| 52 | (or, to loop it automatically: python3 <QPB_REPO>/bin/harness_ticker.py <RUN_DIR>) |
| 53 | |
| 54 | The floor is always one copy-paste away; no run is ever stranded. |
| 55 | |
| 56 | ## Determine your paths first |
| 57 | |
| 58 | - `QPB_REPO` = `git rev-parse --show-toplevel` (run once; use absolute |
| 59 | paths from then on). The tick script is `<QPB_REPO>/bin/qpb_harness_tick.py`. |
| 60 | - `PLAN` = the harness plan file the operator named (a `*.json` matching |
| 61 | `schemas/plan.schema.json`). |
| 62 | |
| 63 | **Invocation hygiene (load-bearing):** always invoke the script directly — |
| 64 | `python3 <QPB_REPO>/bin/qpb_harness_tick.py <arg>`. Never wrap it in an |
| 65 | unquoted shell variable: some shells (zsh) do not word-split an unquoted |
| 66 | `$VAR`, so `$TICK <arg>` tries to exec a binary whose name is the whole |
| 67 | string and fails. |
| 68 | |
| 69 | ## First invocation only |
| 70 | |
| 71 | 1. Run `python3 <QPB_REPO>/bin/qpb_harness_tick.py --init <PLAN>`. It |
| 72 | prints the new run-dir path; capture it as `RUN_DIR` (absolute) and use |
| 73 | it for every subsequent tick. |
| 74 | 2. Immediately perform one tick (below) against `RUN_DIR`. |
| 75 | |
| 76 | ## Per-tick sequence (do exactly this, nothing more) |
| 77 | |
| 78 | 1. Run `python3 <QPB_REPO>/bin/qpb_harness_tick.py <RUN_DIR>`. Capture stdout. |
| 79 | 2. Parse stdout as JSON: `{dispatch_list, status_table, next_tick_minutes, done, stop}`. |
| 80 | 3. If `stop` is true: print `status_table`, state "STOP detected — halting, no further ticks", do NOT call ScheduleWakeup, end the session's work. |
| 81 | 4. |