implement-spec builds a whole Spec. It takes the Tickets that to-tickets wrote and turns them into code on one integration branch: a branch that collects every Ticket's work before any of it goes into main.
It treats the Tickets as a task graph, not a list. Some Tickets block others, so at any moment there is a frontier: the Tickets whose blockers are all done, ready to start.
For each ready Ticket it starts an implementer subagent, a helper agent with its own fresh context, in the background so several run at once. Each one:
works in its own worktree on its own branch, based on the integration branch;
merges the integration branch's latest commit into its own branch before reporting done.
A merger subagent then folds that work into the integration branch. If that frees up more Tickets, more implementer subagents start.
main
integration branchA merger subagent
each ready Ticketits own worktree
(commit counts are illustrative)
a branch that collects every Ticket's work before any of it goes into main
Messages to subagents stay short. They carry context pointers, such as links to the Spec, the Tickets, research notes and earlier commits, instead of pasted copies.
When to use it
A Spec has been split into Tickets with blocking links, and you want all of it built.
Some Tickets can be built at the same time.
You start it yourself by typing /implement-spec. The agent never picks it on its own.
When not to use it
For one Ticket, or a piece of work you describe, use its look-alike implement. That builds the one thing in the current session, with no task graph and no implementer subagents. implement-spec runs many implement-sized jobs and joins them up.
If the Tickets don't exist yet, run to-tickets first.
What it needs to start
A Spec with its Tickets in the Issue tracker, blocking links included.
The Issue tracker set up. If the agent can't find it, it tells you to run setup-matt-pocock-skills.
What it creates
The integration branch, holding the whole Spec.
A draft pull request that closes the Spec and its Tickets, if your Issue tracker closes work through pull requests. It opens after the first merge, because a branch with nothing new on it can't have one.
A code-review of the whole integration branch once every Ticket is done, with all its findings fixed by one more fresh implementer subagent.
At the end, the draft pull request is marked ready for review, or each Ticket is closed the way your Issue tracker closes work. The subagents' worktrees are cleaned up.
Going deeper
6 min read · Going deeper not read
Why it exists
In his v1.3 release notes (the page is dated 2026-10-05), Matt lists three ways to work through a set of Tickets:
The manual loop. You run one Ticket, clear the context, then run the next. "You are the for loop. It is not much fun."
The deterministic loop. A script reads each ticket and runs implement on it. Matt calls this "what I recommend for most people".
The agent loop. An agent does the babysitting instead of a human. This is implement-spec.
He is plain about the trade: "The agent loop is worse than a deterministic loop." But it is a good way to start with work you leave running, before a script is set up, and he reaches for it "much more than I thought I would". It is possible now, he says, "because subagents can spawn their own subagents".
The manual loop.
The deterministic loop.
The agent loop.
You are the for loop.
A script reads each ticket and runs implement on it.
From snapshot/skills/implement-spec/SKILL.md, line 11: “The goal is the entire spec implemented on a single integration branch, with every ticket resolved the way the issue tracker closes work.”
From snapshot/skills/implement-spec/SKILL.md, line 13: “They are a task graph with blocking relationships between them. This means there is always a frontier of tickets which are ready to be grabbed.”
The agent loop is worse than a deterministic loop.
three ways to work through a set of Tickets
On the Skill's own page, Matt says people "kept building their own versions" first. One user wanted subagents to build the Tickets instead of starting a new session for each one, "when a spec may contain over 5 tickets".
How it works underneath
The graph sets the speed. Every Ticket on the frontier runs at once. In Matt's words: "The graph's shape sets the pace, not the tickets' order on the tracker."
Merges stay easy. Because each implementer merges the integration branch's latest commit into its own branch before reporting done, "landing it is a fast-forward". Merges into the integration branch are "fast-forwards, not conflict resolutions".
Pointers keep prompts small. They keep "each subagent's prompt small" and leave "room in the orchestrator's window for the graph". The orchestrator is the session running the whole Spec.
Every subagent starts fresh. This rule is newer than Matt's pages. On 2026-10-29 Matt merged two changes:
#1341 says some Codex models fork the parent conversation when they start a subagent. A fork carries the parent's whole context, which "throws away the reason for using a subagent: a clean context that sees only its brief". The PR says that on Claude Code's default, which already starts subagents fresh, "nothing changes". The #1328 reporter adds a caveat: newer Claude Code versions can choose to fork, though that "does not mean every sub-agent is a fork".
#1342 closes a second gap. An orchestrator could send Ticket B to the implementer that built Ticket A, and "That implementer is still carrying ticket A's context." So the SKILL.md now asks for a fresh implementer for each Ticket, and for the review fixes. The merger subagent "can be reused across merges".
Matt's pages are dated 2026-10-05 and these changes 2026-10-29, so where they differ, the current SKILL.md wins.
A real example
On 2026-10-25, a user filed #1328 after running implement-spec in Codex Desktop "on a large, dependency-ordered ticket graph". The orchestrator "reused existing implementer identities across different tickets". As the report puts it, "Worktrees kept ticket branches separate, but did not prevent agent context from carrying over between tasks."
By the reporter's own count, that run logged 339 compactions across all its sessions, exploration and review sessions included. A compaction is the harness squeezing a full context into a summary, and it loses detail. In the reporter's tests, a Codex subagent copied the parent's history unless fork_turns was set to "none".
Matt replied the same day: "add a single little line saying that each subagent should start with a fresh context window." Three days later the reporter posted a second run. They told Codex never to fork, then built a different pair of Specs, 25 Tickets in all, with 64 fresh subagents. They counted 11 compactions: "two coordinator compactions and nine across subagents". These are the reporter's numbers from two different jobs, so it is an observation, not a controlled test.
The line #1341 added on 2026-10-29, "Start every subagent with a fresh context window.", matches what Matt asked for there. When it was pinned on 2026-10-30, #1328 itself was still open.
Where it goes wrong
Most of these come from Matt's page, dated 2026-10-05.
Two Tickets, one name, two spellings. "Worktrees don't remove collisions; they postpone them to merge time." Each implementer sees only its own Ticket, so one user's two Tickets added the same string as blockedSince and blockedOn. Fix: add a blocking link between the two Tickets, or have the exploration notes fix the exact names.
A review that never ends. code-review only makes sense once every Ticket has landed. Run mid-way, "every unbuilt ticket reads as a failure", and each fix starts another review. Even at the end, the Skill "doesn't yet say when to stop after that fix". One user's five-Ticket feature saw "the review and fix loop took roughly four hours". If a second broad review starts, "tell it to run focused checks for the fixed findings and stop".
Blocked Tickets that never start. On GitHub, a Ticket's blocked-by count only drops when its blocker closes, and Tickets usually close when the PR merges, at the end of the run. Tell the orchestrator to track merges into the integration branch itself.
A green test that never ran. "A worktree holds only what git tracks." Tests that read gitignored fixtures, local databases or credentials "can silently skip there". Matt's fix: tell the orchestrator to run such a Ticket in the main checkout instead. Claude Code's docs add a .worktreeinclude file that copies gitignored files such as .env into new worktrees, subagent worktrees included. It copies only gitignored files.
Nobody to agree seams with. Early versions never called tdd at all (#1035, closed 2026-10-07). Matt's page says it does now, but "There is still no step where you agree seams interactively", so name the seams in the Spec or the Tickets.
Try it
In your practice project (set it up first with keeping-track's Try it step if you haven't), write a small Spec with three Tickets for api/: a classes table, an endpoint that lists classes (blocked by the table), and a health check that nothing blocks. If the api's tests read a gitignored .env, first add a .worktreeinclude file at the repo root with one line, .env. Run /implement-spec with the Spec's Issue number. Watch for two implementers running at once, each starting with a fresh context window. Then check that the table and endpoint Tickets' traces show tdd's failing test first and their Postgres tests really running, not skipped. If one skipped, have the orchestrator run that Ticket in the main checkout.
From snapshot/skills/implement-spec/SKILL.md, line 27: “If the issue tracker closes work through PRs, or the user asks for one, open a draft PR after the first merge in step 5 (a branch with no commits ahead of main can't open one), marked as closing the spec and tickets.”
From snapshot/skills/implement-spec/SKILL.md, lines 29–32: “Each implementer subagent: - confirms its worktree is based on the integration branch before starting, and resets onto it if not; - calls the Skill tool with tdd to build the ticket; - merges the integration branch tip into its own branch before reporting done”
From snapshot/skills/implement-spec/SKILL.md, line 38: “Once all tickets are complete, call the Skill tool with code-review on the integration branch. Fix all issues raised by the code review in a single fresh implementer subagent.”
From snapshot/skills/implement-spec/SKILL.md, lines 40–42: “If a draft PR exists, mark it ready for review. Otherwise, resolve each ticket the way the issue tracker closes work, and report the integration branch. 9. Clean up all implementer subagent worktrees.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 127: “Before it shipped, people kept building their own versions, and one user described the need: they wanted "subagents implement the tickets" instead of having "to individually create new session and tell them to implement a ticket one by one, when a spec may contain over 5 tickets."”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 90: “every ticket on the frontier runs at once. That is the difference from working the tickets one by one. The graph's shape sets the pace, not the tickets' order on the tracker.”
From snapshot/web/github.com/mattpocock-skills-pull-1341.md, line 31: “Some Codex models fork the parent conversation when they spawn a subagent. The fork inherits the parent's context window, which throws away the reason for using a subagent: a clean context that sees only its brief.”
From snapshot/web/github.com/mattpocock-skills-pull-1342.md, line 31: “Before: nothing stops an orchestrator from sending ticket B, or the code-review fixes, to the implementer that built ticket A. That implementer is still carrying ticket A's context.”
From snapshot/web/github.com/mattpocock-skills-issues-1328.md, line 51: “During execution, the coordinator reused existing implementer identities across different tickets and a merger identity across different ticket integrations. The archived dispatch state records the same subagent identities on multiple distinct tasks. Worktrees kept ticket branches separate, but did not prevent agent context from carrying over between tasks.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 143: “Each implementer sees only its own ticket and the shared notes, never the other's work in progress, so one user's web and mobile tickets added the same string as blockedSince and blockedOn. When two frontier tickets touch one shared file, either add a blocking edge between them so they run one after the other, or have the exploration notes fix the exact names each ticket adds.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 135: “It compares the code against the whole spec, so it only makes sense once every ticket has landed. If it runs mid-run, every unbuilt ticket reads as a failure. The agent then builds that ticket, and that triggers another review.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 147: “This is a known problem on GitHub. The tracker's blocked-by count only drops when a blocker closes, and tickets typically close when the PR merges, which is the end of the run.”
From snapshot/web/code.claude.com/docs-en-worktrees.md, line 166: “A worktree is a fresh checkout, so untracked files like .env or .env.local from your main repository are not present. To copy them automatically when Claude creates a worktree, add a .worktreeinclude file to your project root.”
From snapshot/web/aihero.dev/skills-implement-spec.md, line 139: “There is still no step where you agree seams interactively, as there is in an implement session, so name the seams in the spec or the tickets if you want them pinned.”