Skip to content
Back to skills

Plan Blitz

ASecurity

PM-GATED. Plan every baton lacking an approved plan, in scout/EM/planner waves. Or named batons.

  • 5 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 20, 2026
ai-agentspythongoshellbashbackendsecurity

Works with

  • terminal
  • cli

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 7, 2026

npx -y skills add dbc-oduffy/coordinator-claude --skill plan-blitz --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Plan Blitz?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Plan Blitz
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dbc-oduffy-plan-blitz/badge)](https://www.skillsdirectory.com/skills/dbc-oduffy-plan-blitz)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: plan-blitz
description: "PM-GATED. Plan every baton lacking an approved plan, in scout/EM/planner waves. Or named batons."
description-budget: 320
version: 1.0.0
allowed-tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob", "Agent", "Skill", "Workflow", "AskUserQuestion", "TaskCreate", "TaskUpdate", "TaskGet", "TaskList"]
argument-hint: "[<baton-id> ...] [--roadmap-id <id>] [--waves <n>] [--dry-run]"
---

# Plan-blitz — a roadmap's worth of plans, in waves

Consumes a roadmap that already exists and produces plans for it, N batons per wave. Rationale and
measured cases: fleet wiki under this skill's name. The waves fire from the top-level EM only — a
dispatched agent cannot fan out (`A-SKILL-PHASE-NAMES-ITS-ACTOR`).

---

## Two modes

| Mode | Target set |
|---|---|
| **Sweep** (default, no args) | every baton the engine returns as `needs_plan` — no linked plan, or one not yet review-cleared. An approved baton leaves the set, staying only as a satisfied blocker. `--roadmap-id` narrows to one roadmap. |
| **Targeted** (`<baton-id> ...`) | the ids you pass as `targets`; everything unnamed stays a fully-resolved BLOCKER, not a candidate. |

**Check `unmatched_targets` on every targeted run** — a dropped target is worse than a refusal.

**When NOT to use:** no roadmap yet → `coordinator:roadmap-planning`. One baton →
`coordinator:sizing`, then `coordinator:plan`. Plans exist and need executing →
`coordinator:execute-plan`. A batch of bugs rather than roadmap batons → `coordinator:bug-blitz`.

**Dispatch authorization — invoking this skill IS the request.** The dispatches named below are constitutive steps of this skill, not a separate thing to get cleared: invoking a skill requests the actions that skill performs. A harness line permitting dispatch "unless the user requested it" is therefore **satisfied here, not overridden** — no precedence claim is needed and none is made. Re-asking spends the very context the dispatch exists to protect. The rule attaches to skill entry and dissolves no PM-authored gate: keyword-gated skills gate entry, and every gate a skill names for itself still binds — per-session cross-repo-commit assent, ask-before-external-action, and any other this skill's own body names. Tripwire: `UNATTRIBUTED-HARNESS-LINE-IS-NOT-PM`.

**Host shapes.** Calls below are Shape W; on POSIX run `coordinator-invoke <op> '<json>'` (Shape B).

---

## The two gates — read them, never derive them

One `blocked_by` edge, two questions. **Planning** may start when every blocker is coded *or*
carries a review-approved plan. **Execution** may start only when every blocker is coded. Tripwire:
`A-PLANNING-GATE-IS-NOT-AN-EXECUTION-GATE`.

Both come off one disk-reading op; **never hand-derive either from `blocked_by`.**

Invoke `coordinator-invoke` per the ladder in `${CLAUDE_PLUGIN_ROOT}/snippets/resolve-coordinator-bin.md`
— rung 0 (Shape W, the `.exe` launcher) on a PowerShell host:

    `& "$env:COORDINATOR_SETTINGS_HOME\bin\coordinator-invoke.exe" roadmap.plan_gate '{"roadmap_id":"<id>"}'`

It returns both gates per candidate baton, plus `waves`, `cycles`, `unresolved_blockers`, `held`, `counts`. **It reports, never refuses;** refusal is yours.

---

## The flow — a loop with no judgment in it

**This runs at Sonnet.** Opus judgment happens INSIDE a wave; the driver is mechanism: read a
gate, fire, land, repeat. A judgment call needed to drive it is a loop defect.

### 0. Preflight — confirm the engine is reachable

Resolve the launcher per `${CLAUDE_PLUGIN_ROOT}/snippets/resolve-coordinator-bin.md`. Unresolved —
**stop and report**; never enter `roadmap.plan_gate`, `roadmap.blitz_land` or a dispatch, nor fabricate a result.

### 1. Read the gate

    `& "$env:COORDINATOR_SETTINGS_HOME\bin\coordinator-invoke.exe" roadmap.plan_gate '{}'`

| Field | If non-empty | Response |
|---|---|---|
| `unresolved_blockers` | an edge names no record on disk | Stop ONLY for a wave member about to fire; otherwise report and proceed — the gate fails that baton CLOSED. |
| `cycles` | batons block each other | Stop and report the named members. |
| `counts.unschedulable` | blockers this pass cannot clear | Proceed; excluded by design. |

**A blocker naming a peer EM role is the standing case, not a typo; never delete the edge** — it
clears when the peer answers. **An edge is a DISCOVERED dependency, never a way to suppress a candidate.**

**Suppression is a HOLD: three flat baton keys the gate reads —
`plan_blitz_hold_reason`, `plan_blitz_hold_cite`, `plan_blitz_hold_until`.** The gate sets
`candidate: false` and reports the baton under `held`. **A hold with no reason is ignored.**
**`external_gate` on a BATON record does nothing** (real on PLAN SPINE ROWS only).

### 2. Scaffold the trail and freeze the gate

`state/plan-blitz/<run-id>/wave-<N>.gate-report.json`, `<run-id>` being this run's UTC start as
`YYYYMMDDTHHMMSSZ`. Scaffold the directory first.

- **One report PER WAVE**, frozen after the previous wave landed.
- **Pass `--bare`** (`result` alone). Tripwire: `AN-ENVELOPE-FROZEN-AS-A-GATE-REPORT-READS-AS-AN-EMPTY-WAVE`.
- **Freeze by redirection** — `1> gate-report.json 2> gate.stderr`; read back with `utf-8-sig`.

### 2a. Check the wave for finished work

    python3 "${CLAUDE_PLUGIN_ROOT}/skills/plan-blitz/recycle-check.py" --repo-root <repo> \
        --gate-report <the frozen report> --exclude-run <this run-id>

`RECYCLED` (exit 1): re-run that landing with the SHA; **never drop the baton by hand**.
`RESURRECTED` (exit 1): remove or re-archive the live copy. Tripwire: `A-FINISHED-BATON-THE-LANDING-NEVER-STAMPED-COMES-BACK-AS-A-CANDIDATE`.

### 3. Fire the wave — emit it; never hand-write the args

    "$COORDINATOR_SETTINGS_HOME/bin/emit-wave-fire" \
        --repo-root <abs> --trail-dir <abs> --wave-index N --wave-number N \
        --gate-report <trail-dir>/wave-N.gate-report.json

It derives every per-baton field from the frozen report, splits the wave into fires at the cap,
binds each fire's args into a standalone `.mjs`, and prints one `Workflow({ scriptPath })` line per
fire; fire each. Pass `--plugin-agents-available true` where `coordinator:*` types
resolve. `workflows/plan-blitz.mjs` holds the args contract.

- **Never hand-type an args object.** Tripwire: `A-HAND-TYPED-WAVE-ARG-IS-AN-UNARCHIVED-FIRE`.
- **An emitted fire is a SNAPSHOT — RE-EMIT, never re-fire as found** after any workflow fix.
- **Never retro-patch a fire that already ran.**
- **Pass `--wave-number` with the run's own wave count**; omit on a one-wave run.
- **At most 8 batons per fire**; the emitter splits a larger wave, sharing the `waveIndex`.
- **`--exclude <baton-id>` narrows what is FIRED, never what the gate computed** (a part-fired wave).
- **Search the trail RECURSIVELY; order slots by INTEGER wave index** (`recycle-check.py :: _slot_order`).

**Fires may run CONCURRENTLY; the driver owns disjointness, the gate cannot.**

- **Subtract your in-flight set from every fresh gate read** by `planPath`, not just baton id (`emit-wave-fire._split` covers one emit; you cover across emits), and adjudicated batons too — a `pulled` baton returns at the head of the next read. Tripwire: `A-GATE-READ-DOES-NOT-KNOW-A-FIRE-IS-RUNNING`.
- **Re-freeze the gate before re-emitting a baton whose plan you edited.**
- **A hold only you remember is not a hold** — write it in the trail's `RUN-NOTES.md`.

**`emit-wave-fire` resolves `provisionSidecarCli`**; pass `--provision-sidecar-cli` only to
OVERRIDE. A findings path with no `subagent-share` segment is a REFUSAL. Tripwire: `A-SIDECAR-THE-DISPOSITION-OP-REFUSES-LOSES-ONLY-THE-RECORD`.

**A box with no install is Rung N** — pass `--engine-root` (`--live-engine-tree` where only the
authoring tree carries `workflow.bind_args`). Tripwire: `A-PUBLISHED-MIRROR-OLDER-THAN-AN-OP-REFUSES-AS-A-MISSING-ENGINE`.

**Every baton carries `executionOpen`** (from `execution_gate.open`; no default). **Resolve
`${CLAUDE_PLUGIN_ROOT}`; never pass a repo-relative path** to a workflow.

Then wait; never read the trail mid-wave.

### 4. Commit the wave's XS work, then land it — one call over every fire of the wave

    python3 "${CLAUDE_PLUGIN_ROOT}/skills/plan-blitz/land-wave.py" \
        --repo-root <abs> [--shipped-in <sha>] <fire-result.json> ...

One file per fire — the task output file the completion notification names works as-is; never
extract `.result` by hand. It lands each fire through `roadmap.blitz_land`, **sums the three lanes
across every fire**, and states the stop condition from that sum. It refuses if the fires disagree
about `waveIndex`, or if a fire dispatched XS and no `--shipped-in` was given. It writes
`wave-<n>.landing.<slot>.json` into the trail (read by `read_wave_landings`) and commits them
itself (`--no-commit` lists them). **Never redirect its stdout onto that path.**

**Commit before landing whenever the wave dispatched any XS** — `close_dispatched` stamps `shipped`
with a `shipped_in` SHA and the op does not commit; pass that SHA.

    `& "$env:COORDINATOR_SETTINGS_HOME\bin\coordinator-invoke.exe" roadmap.blitz_land '{"wave_result": <the workflow's return value verbatim>, "shipped_in": "<sha of the commit carrying the XS work>"}'`

`roadmap.blitz_land` links each `ready` plan then stamps `approved`, mints a baton per `replan`, and
returns `next_wave` off a **fresh** gate read.

**Three lanes land differently; the op picks by route.**

| Route | Size | What landing does |
|---|---|---|
| `plan` | M / L | link the plan to its baton, then stamp `approved` — opens the next wave's planning gates |
| `spec-dispatch` | S | park the spec onto the baton, stamp execution-ready (four-field `execution_authorized_*` + `handoff_phase: execution`), as a straight dispatch |
| `dispatch` | XS | work already done in the wave's Dispatch phase; landing stamps `shipped` with `shipped_in`, making it terminal |

An S plan stays `draft` by design (`needs_plan` keys off the execution stamp). **Never hand-stamp `status: approved`** — the op links before stamping.

**Read `refused[]` on every landing** — never route around an entry.

### 5. Loop

**`--waves` defaults to 1.** The run stops after wave 0 lands. A non-empty `next_wave.batons` at that
stop is reported to the EM as the remaining work, to be fired as separate runs — never auto-chained.
The override is `--waves <n>` with `n > 1`, passed with a one-line written EM justification that
goes in the run's trail; a linear `blocked_by` chain (each wave opens exactly the next) is the standing case. Then fire `next_wave` and land it, repeat, under the stop conditions below. Tripwire: `A-MULTI-WAVE-BLITZ-IS-NOT-THE-DEFAULT`.

**Stop conditions, all mechanical:**

- `next_wave.batons` is empty.
- `--waves` exhausted.
- A wave lands zero `approved` **and** zero `execution_ready` **and** zero `closed` — it opened
  nothing. Report and stop.
  **Zero `approved` alone is not the test:** an all-S ready set approves nothing and still advances
  (§ Three lanes). Tripwire: `AN-ALL-S-WAVE-APPROVES-NOTHING-AND-STILL-ADVANCES`.
  **It is a WAVE-level test, not a fire-level one.** Sum the three lanes across every fire at this
  `waveIndex` first — one fire can report `approved: 0` while `needs_plan` still drops 27 to 24.
  **It applies only to a FINISHED wave** — check completion BEFORE reading the lanes (wiki,
  § Trimmed rationale). **Never land an unfinished fire**; resume it, or re-emit and re-fire,
  closing a finished XS with `archive-stamp-cli ship-handoff <path> --sha <sha>`. Tripwire:
  `AN-UNFINISHED-WAVE-IS-NOT-A-WAVE-THAT-OPENED-NOTHING`.
- The usage-limit advisory has fired — fire no further wave; land the current wave through step 4,
  then report and stop with the reset time. See
  `coordinator/docs/wiki/skills-corpus/usage-limit-pause.md`; tripwire:
  `A-DRIVER-PAST-ITS-USAGE-THRESHOLD-FIRES-NOTHING-NEW`.
- `refused[]` is non-empty — report and stop.
- `surfacedToPm` is non-empty — the residue: each is `pm_only`. Carry it out; **never re-queue one.** Report `adjudicated` by count.

**What the driver escalates rather than decides:** an unresolved blocker, a cycle, a `refused` entry,
`surfacedToPm` residue, an empty wave.

---

## Rules that hold across every wave

**Review fires unconditionally; the EM gates once, at the end.** Tripwire: `A-BLITZ-WAVE-THAT-GATES-ON-THE-EM-IS-NOT-A-BLITZ`.

**Host availability on the wave's box is never a pull reason:** a plan with rows withheld behind a
declared `external_gate` is READY (withheld rows are a schedule fact); pull for properties of the PLAN. Tripwires: `A-PLANNING-GATE-IS-NOT-AN-EXECUTION-GATE`,
`THE-BOX-THE-WAVE-RAN-ON-IS-NOT-THE-BOX-THE-PLAN-RUNS-ON`.

**One reviewer-attributed option is a recommendation, not a choice or a dead end;** contested
options are arbitrated by the resolve pass. Tripwire: `A-SINGLE-REVIEWER-OPTION-IS-A-RECOMMENDATION-NOT-A-DEAD-END`.

**No reviewer is prescribed in a plan file; its `review_signals` select them** — front-end →
`senior-front-end`, data-science → `staff-data-sci`, ux-flow → `staff-ux`, cross-repo-seam →
`eng-director` — added to the sized reviewers. security/architecture/backend stay `staff-eng`.

**The readiness gate owns cross-plan seams:** an export one plan needs that its author never
promised, and sibling `writes:` collisions; a hit is a pull naming both plans and the repair. **Planners read the PM's Approve** from the roadmap OVERVIEW's `approver`/`approval_utterance`;
none means baton defaults, stated.

**`BLOCKED` and `PIVOT` are different questions, not a severity ladder.** `BLOCKED`: wrong until
fixed — the reviewer applied its findings; the fixed plan is approved the same wave. `PIVOT`: this
direction cannot proceed — no findings repair it. Tripwire: `A-BLOCKED-REVIEW-IS-NOT-A-PIVOT`.

**`PIVOT` routes, never halts:** a replan baton; the other N-1 plans finish; co-reviewer findings
carry as `Suspended (PIVOT)`.

**Never blitz a claimed or `in_flight` baton** (a live holder has it) **or open a shut gate.**

**The blitz-em never rules a PM decision.** `route: pm-decision` and XL exits go to the Adjudicate
phase (APM for scope; staff-eng or a domain reviewer for code); only `pm_only` stays in `surfacedToPm`.

**`approved` is not `mise-prepped`, and a wave never stamps one.** Body edits invalidate a stamp;
frontmatter writes do not. Never read `mise_prepped_by` for presence. Tripwire:
`A-PRESENT-MISE-PREPPED-STAMP-IS-NOT-A-CERTIFICATION`; consumer contract:
`coordinator/docs/wiki/lesson-triage/mise-prepped-attest.md`.

---

## Anti-scope

- Does not author roadmap batons (`coordinator:roadmap-planning`).
- Does not execute plans, and never opens an execution gate. It stops at *ready to execute*.
  Consumer: `skills/plan-blitz/mise-prep-entry.py`. Tripwire: `A-HANDOFF-AN-EM-RETYPES-IS-NOT-A-SEAM`.
- Does not ratify sizings on the PM's behalf.
- Does not review code — wave reviewers review **plans**.

Files in this skill

  • SKILL.md25 KB
  • emit-wave-fire.py76.2 KB
  • land-wave.py40.7 KB
  • mise-prep-entry.py26.4 KB
  • recycle-check.py27.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.