# Implement Queue

> Implement an entire folder of tickets in dependency order, each in a fresh subagent context, with preflight, per-ticket external verification, one commit per ticket, retry-once, and a circuit breaker — running to completion without pausing. Use this whenever the user wants a whole ticket queue or backlog folder worked through in one go: "implement all the tickets in tickets/", "run the queue", "work through the backlog", "burn down tickets/", "start the implementation queue", or when they ask to triage or resume a queue run that halted. Do NOT use this for implementing a single named ticket or for open-ended feature work.

- Skill: `anarefin/implement-queue` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add anarefin/implement-queue`
- Raw SKILL.md: https://api.skillmd.com/api/skills/anarefin/implement-queue/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: anarefin (https://skillmd.com/u/anarefin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/anarefin/implement-queue

---


# implement-queue

Implement every ticket in the folder the user names, in order, each in an isolated
context. Run to completion. A developer is watching but WILL NOT be asked for anything.

Throughout, `$Q` is the ticket folder the user named (default `tickets/`) and
`$S` is `~/.claude/skills/implement-queue/scripts`. Every script below is invoked
from that absolute path — nothing needs to exist in the project except `$Q`.

## THE ONE RULE THAT KEEPS THIS RUN ALIVE

You persist across ~25 iterations. Your context is the scarce resource.

NEVER:
- run the test suite yourself (`verify-ticket.sh` does it)
- read, cat, tail, or grep any file in `logs/`
- read a diff, a commit, or a source file
- paste ticket contents into a dispatch prompt (pass the PATH; the worker reads it)
- summarize, narrate, or reflect on completed tickets
- hold the ticket list, the graph, or progress in your head

Every command you run returns ONE line. If something returns more, you called the
wrong thing. All state lives in `$Q/.queue-state.json`. Re-read it via `queue.py`;
never rely on memory. If your context compacts mid-run, the next `queue.py next`
call tells you exactly where you are — just keep looping.

The gap between following this section and ignoring it is roughly 16k tokens versus
150k. It is the difference between a run you can watch and a run that compacts at
ticket 14.

## Phase 0 — Bootstrap (once, cheap)

The project only has to supply tickets. Fill in the rest without asking:

1. If `docs/CONVENTIONS.md` is missing: copy
   `~/.claude/skills/implement-queue/assets/CONVENTIONS.template.md` to it, and say
   in one line that a starter file was created and is worth editing before a real run.
2. Check for the starter marker — one grep, one line of output, no file reading:
   `grep -c QUEUE-STARTER-UNEDITED docs/CONVENTIONS.md`
   If the count is 1, announce exactly:
   `WARNING :: CONVENTIONS.md is still the unedited starter — expect more BLOCKED tickets`
   Then continue. Do not stop, do not offer to fill it in, do not ask. The user knows
   what a warning means, and a generic conventions file degrades quality rather than
   breaking the run.
3. If `docs/IMPLEMENTATION_CONTEXT.md` is missing: create it with the single line
   `# Implementation context`.
4. Do not read either file yourself. The workers read them.

## Phase 1 — Preflight (abort cheaply)

1. `$S/preflight.sh` → abort on FAIL, report the line, stop.
   The OK line ends with `test_cmd=<...>`. Capture that string; it is the project's
   detected test command and you pass it on in step 3. Do not detect it yourself.
2. `BASE=$(git rev-parse HEAD)`, `BRANCH=$(git rev-parse --abbrev-ref HEAD)`
3. `python3 $S/queue.py plan "$Q" --base-sha $BASE --branch $BRANCH --test-cmd "<detected>"`
   Non-zero exit means the graph is invalid (missing or forward `blocked_by`,
   duplicate prefix, id/filename mismatch). Report the errors and STOP — do not
   attempt to fix tickets yourself. Exit 2 means a state file from an earlier run
   disagrees with the folder; tell the user to rerun with `--force` and stop.
4. Print the plan and the count. Then BEGIN IMMEDIATELY. Do not ask for
   confirmation; the user already confirmed by asking for the queue to be run.

## Phase 2 — The loop

Repeat until `queue.py next` exits 10:

1. `python3 $S/queue.py next "$Q"`
   exit 10 → queue exhausted, go to Phase 3.
   Output is `<ticket-id><TAB><abs-path>`.
2. `PREV=$(git rev-parse HEAD)`
3. `python3 $S/queue.py mark "$Q" <id> running`
4. Announce one line: `=== <id> (attempt 1)`
5. Dispatch the `ticket-implementer` subagent via Task. The prompt contains ONLY:
   ```
   TICKET: <abs-path>
   TICKET-ID: <id>
   CONVENTIONS: docs/CONVENTIONS.md
   CONTEXT-LOG: docs/IMPLEMENTATION_CONTEXT.md
   BRANCH: <branch>
   BASE-SHA: <PREV>
   ```
   On a retry, add `RETRY-LOG: logs/<id>.verify.log` — pass the PATH. Do NOT read
   that file yourself; a stack trace in your context is hundreds to thousands of
   tokens at the worst possible moment, and the worker can read it in its own
   disposable context for free.
6. `$S/verify-ticket.sh <id> $PREV "$Q"` → one line, OK or FAIL.
   Trust THIS, never the subagent's return. The return is a claim; this is evidence.
7. Branch on the result:
   - **OK** → `python3 $S/queue.py mark "$Q" <id> done --sha <short-sha>`; reset the
     consecutive-failure counter to 0; next iteration.
   - **Subagent returned BLOCKED** → `git reset --hard $PREV && git clean -fdq`;
     `python3 $S/queue.py mark "$Q" <id> blocked --reason "<the BLOCKED clause>"`.
     Do NOT retry a genuine BLOCKED — it is the worker's considered judgment that the
     ticket is defective, so a retry burns 20k tokens to receive the same answer.
     Increment consecutive failures. Continue to the next ticket.
   - **FAIL and attempt 1** → `git reset --hard $PREV && git clean -fdq`;
     announce `=== <id> (attempt 2)`; re-dispatch once with RETRY-LOG. Go to 6.
     A FAIL is often a flake or a half-finished edit, and a second fresh context
     frequently fixes it.
   - **FAIL and attempt 2** → `git reset --hard $PREV && git clean -fdq`;
     `python3 $S/queue.py mark "$Q" <id> blocked --reason "<the FAIL line>"`.
     Increment consecutive failures. Continue.

Always reset before a retry and after a failure. Attempt 2 starting from attempt 1's
wreckage is strictly worse than starting clean — the model spends its fresh context
reverse-engineering a mess instead of implementing.

The reset is safe to run in the user's own checkout because preflight refused to start on
a dirty tree: every `$PREV` is either the base commit or a commit this run made, and
`git clean -fdq` (no `-x`) leaves gitignored files alone. Never add `-x`, and never reset
to anything other than the `$PREV` you captured in step 2 of this iteration.

`queue.py next` automatically marks the transitive dependents of any blocked ticket
as `skipped`. You do not compute this. You do not reason about the graph.

## Circuit breaker

Two CONSECUTIVE blocked tickets → STOP the loop and go to Phase 3.
One failure is information about a ticket. Two in a row is information about the
run — a broken environment, a wrong convention, an unusable base. Burning 20 tickets
of tokens against a systemic fault is the expensive mistake here.

## Phase 3 — Finalize

1. Run the project's test command once, redirecting to a log:
   `<test_cmd> > logs/final.log 2>&1 && echo GREEN || echo RED`
   (one line — do not read the log). Get `<test_cmd>` from
   `python3 $S/queue.py test-cmd "$Q"` if you no longer have it.
2. `python3 $S/queue.py report "$Q" | tee logs/REPORT.md`
3. Print the report table and stop. If anything is blocked or skipped, say only:
   "Ask me to triage the queue when you want to work through those." Do not begin
   triaging.

## If the developer interrupts

They may hit Esc and talk to you mid-run. Answer them. When they say continue,
resume Phase 2 from step 1 — `queue.py next` re-derives position from the state file.
Do not try to reconstruct where you were from the conversation.

## Triage mode (only when explicitly asked)

When the user asks to triage or recover a halted run, do not restart the loop.
Instead:
1. `python3 $S/queue.py report "$Q"` — read the blocked reasons from the table.
2. For each blocked ticket, state the reason and what decision would unblock it.
   Reasons that are questions belong to the user; reasons that are FAIL lines mean
   reading `logs/<id>.verify.log` — now safe, because the run is over.
3. Edit the tickets only when the user agrees to the fix.
4. Re-running the queue afterwards is `queue.py plan ... --force` followed by a
   normal run; already-done tickets are re-run from scratch, so prefer branching
   from the last good commit.

## Reference

`references/ticket-format.md` — the exact ticket frontmatter and section layout the
graph validator expects. Read it only if the user asks about ticket structure or if
`queue.py plan` rejects their files.

