Split a plan into small, end-to-end tasks with acceptance criteria and explicit blocking dependencies.
Install and prepare
Prepare Node.js 22.20.0 or newer and npm/npx, as required by the current skills@latest package. Run the following in your project terminal, then use the prompt below in Claude Code. This installs editable, project-scoped skill files.
npx skills@latest add mattpocock/skills --skill to-tickets --skill setup-matt-pocock-skills --agent claude-code
For Codex, replace claude-code with codex in the command and /to-tickets with $to-tickets in the prompt. With the complete Claude Code plugin, select /mattpocock-skills:to-tickets instead; avoid installing the same skills twice.
Prepare a specification, issue link or sufficiently detailed conversation. After installation, run /setup-matt-pocock-skills in the agent conversation for the same project; use $setup-matt-pocock-skills in Codex or /mattpocock-skills:setup-matt-pocock-skills with the complete Claude Code plugin. For a first run, you can choose Local Markdown, review and save the proposed configuration, then run to-tickets.
GitHub mode needs an installed and authenticated gh; GitLab mode needs an installed and authenticated glab. Describe your workflow for Linear or another custom tracker. If you also use triage, install it first so setup includes the triage-label configuration.
Your first task
Adapt the scenario and paths to your project, then enter this in the agent conversation:
/to-tickets specs/team-purchases.md
Show the proposed tickets and blocking relationships first. Each ticket should demonstrate a complete behavior, rather than splitting all database work, all APIs and all pages. Write local tickets after we agree.
Work through the task
Slice by demonstrable behavior
A first ticket might let an administrator allocate one seat and grant learner access across the required data, API, UI and tests. Later tickets can add bulk allocation or seat recovery. Each finished ticket should deliver an independently explainable result.
Check real dependencies
Seat recovery may depend on allocation, while help copy may not block implementation. Review each Blocked by field and remove dependencies added only to produce a neat sequence. Unblocked work can proceed in parallel when it has its own acceptance conditions.
Publish the agreed breakdown
The workflow presents numbered tickets, delivered behavior and dependencies for you to refine. After agreement, local mode writes one file per ticket under .scratch/<feature>/issues/; a remote tracker receives issues in dependency order, using native blocking links where supported and issue numbers in the body otherwise.
Check the result
Each ticket needs a concrete deliverable, acceptance conditions and blockers. Pick an unblocked ticket and check that a fresh agent could start from it and the linked spec without guessing the missing conversation.
In remote mode, open every created issue to confirm its body and acceptance criteria are complete, and check in the tracker UI that supported native blocking relationships actually exist; a Blocked by line in the body does not substitute for a native edge.
If the input was an existing GitHub spec issue, also check that the new tickets appear in its sub-issue list: mentioning the parent is not the same as attaching a sub-issue. Ask the agent to add missing links to the existing tickets while preserving the parent’s body, labels and state; you do not need to create the tickets again.
Common questions
How should a repository-wide rename be split? The workflow supports expanding the new form, migrating callers in batches and removing the old form afterward.
Does implementation start automatically? Start that separately after ticket creation.
I got one combined local document. Ask for one file per ticket so the work can be assigned independently.
Quiz the split before publishing tickets
For every ticket, ask: what new behavior can I demo when this is done? If the answer is only that all database tables or APIs exist, it lacks an observable result; merge it with adjacent work or rewrite it as a vertical slice. A fresh session should be able to finish each ticket from its inputs, expected behavior, acceptance check, blockers, and linked spec. File line numbers become stale and should not carry the requirement. Review the numbered list and adjust granularity before it is sent to the tracker.
Challenge the blocker graph too. Reclaiming a seat may depend on assigning one, while help text need not wait. The first startable ticket should have no blockers; only genuinely independent tickets can run in parallel. If a tiny change becomes a dozen tickets, the tool may be unnecessary or the slices too small: one-session work can go straight to implementation. A wide mechanical migration is an exception; expand the new form, migrate uses in batches, and remove the old form last instead of forcing it into ordinary feature slices.
Use notification preferences to test vertical slicing
Suppose the spec lets users control email and in-app notifications separately. Ask: “Use to-tickets to produce independently demoable work. The first ticket lets a user turn off email alerts and retain that choice after signing in again, including necessary persistence, API, settings UI, and tests. Show the dependency graph before publishing.” A later ticket can add in-app alerts; do not start with an “all database work” ticket.
For each ticket, name an acceptance check that fails at the base commit and a behavior a fresh session can demonstrate when done. Remove edges added merely to make a tidy sequence. If a wide mechanical change truly cannot stay green as separate slices, consider the documented expand–migrate–contract exception. Review the list before publishing so a small change does not become a dozen issues.
Map every spec invariant to a ticket
For a large spec, run a reverse-coverage check: list every invariant and read/write path on one side, then identify its owning ticket and end-to-end acceptance test on the other. In one migration, an initial set of 16 tickets covered producer jobs and cutover but omitted hydration of the full model consumed by old read APIs. Ticket-level proxy checks passed while some UI paths were empty. Give “preserve existing behavior” a read-side test, not just a job-success check. After publishing tickets remotely, read their bodies back to ensure the acceptance criteria did not become empty or placeholders.