Skip to content
Back to skills

To Tickets

ASecurity

Cut a spec into tracer-bullet tickets, each naming the tickets that block it, and publish them to the Tracker.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 20, 2026
developmentgobashrefactoringgitapi

Works with

  • api

Security analysis

A100/100

Scanned October 20, 2026

npx -y skills add MalcolmMcNeely/skillworks --skill to-tickets --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of To Tickets?

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

Security grade badge for To Tickets
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/malcolmmcneely-to-tickets/badge)](https://www.skillsdirectory.com/skills/malcolmmcneely-to-tickets)

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: to-tickets
argument-hint: "<spec number, issue URL or spec path>"
description: Cut a spec into tracer-bullet tickets, each naming the tickets that block it, and publish them to the Tracker.
disable-model-invocation: true
---

# To Tickets

Break a spec into a set of **tickets** — tracer-bullet vertical slices, each declaring the tickets that **block** it.

Read `docs/agents/issue-tracker.md`. Its section "The ticket shape" is the team's taste in tickets: their size, their title and the template each one fills. Read it before step 3, and shape every ticket by it.

If `docs/agents/issue-tracker.md` or `docs/agents/domain.md`, which step 2 reads, is missing, or the tracker docs hold no section "The ticket shape", stop. Tell the user which is missing, the file or the section, that `/skillworks:skillworks-setup` writes it, and that no ticket was made. Under the spec loop this is work you cannot do, so begin your last message with a line that starts with `BLOCKED` and holds that message: the driver reads that line and stops the loop at once.

## Process

### 1. Gather context

Work from whatever is already in the conversation context. If the user passes a reference (a spec path, an issue number or URL, or a spec number with the files Tracker) as an argument, fetch it and read its full body and comments. With the files Tracker, the tracker docs say where a spec's `spec.md` is read from.

### 2. Explore the codebase

Read `docs/agents/domain.md`: it says where this repo keeps its glossary and its ADRs. Then, if you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions use the glossary's vocabulary, and respect the ADRs in the area you're touching.

Look for opportunities to prefactor the code to make the implementation easier. "Make the change easy, then make the easy change."

### 3. Draft vertical slices

Break the work into **tracer bullet** tickets.

<vertical-slice-rules>

- Each slice cuts a narrow but complete path through every layer (schema, API, UI, tests) — vertical, not a horizontal slice of one layer
- A completed slice is demoable or verifiable on its own
- Each slice is sized as the ticket shape says
- Any prefactoring should be done first

</vertical-slice-rules>

Give each ticket its **blocking edges** — the other tickets that must complete before it can start. A ticket with no blockers can start immediately.

**Keep each Surface in step, ticket by ticket.** A Surface is a place a change can have to reach besides the code that does the work, such as the README or the user docs. The spec's Surfaces section names each Surface the change touches, with what it has to say once the change Lands. Place each Surface's work inside the ticket whose change needs it, and name the Surface and its requirement in that ticket's body, so every ticket that Lands leaves each Surface in step. No ticket only updates a Surface: a Surface would be wrong between the ticket that changed the behaviour and the one that described it. A spec whose Surfaces section says "None", or that has none, adds nothing here.

**Wide refactors are the exception to vertical slicing.** A **wide refactor** is one mechanical change — rename a column, retype a shared symbol — whose **blast radius** fans across the whole codebase, so a single edit breaks thousands of call sites at once and no vertical slice can land green. Don't force it into a tracer bullet; sequence it as **expand–contract**. First expand: add the new form beside the old so nothing breaks. Then migrate the call sites over in batches sized by blast radius (per package, per directory), each batch its own ticket blocked by the expand, keeping CI green batch to batch because the old form still exists. Finally contract: delete the old form once no caller remains, in a ticket blocked by every migrate batch. When even the batches can't stay green alone, make them one ticket, and say in the breakdown why it is larger than the ticket shape allows: the loop Lands a ticket only when the checks are green, so a batch that is red alone would never Land.

### 4. Show the breakdown

Present the proposed breakdown as a numbered list. For each ticket, show:

- **Title**: short descriptive name
- **Blocked by**: which other tickets (if any) must complete first
- **What it delivers**: the end-to-end behaviour this ticket makes work

Show it every time, whoever invoked you. Even where nobody is asked to approve it, the user reads the slices while the work runs.

**When you were told to skip the approval questions, skip them and go straight to step 5.** Only an unattended run asks for that, and the person who started it consented then.

Otherwise ask the user:

- Does the granularity feel right? (too coarse / too fine)
- Are the blocking edges correct — does each ticket only depend on tickets that genuinely gate it?
- Should any tickets be merged or split further?

Iterate until the user approves the breakdown.

### 5. Publish the tickets to the configured tracker

Publishing needs a spec on the Tracker, because `tracker-publish` takes the spec's number and every ticket hangs from that spec. When the work has no spec there, such as a plan that lives only in this conversation, publish nothing. Tell the user that no ticket was made, and that `/skillworks:grill` ends in a spec these tickets can be cut from.

Publish the tickets you showed, with the same files and the same command for both Trackers. Write one file per ticket with the Write tool, to the folder `.spec-loop/<spec>/tickets/` in this checkout, named `<NN>-<slug>.md` and numbered from `01` in dependency order, blockers first. Each file opens with the frontmatter the tracker docs show: `status: open`, `blocked-by` listing the numbers of the tickets that block it, such as `blocked-by: [1, 2]`, and `claimed-by` left empty, because the loop sets it. The ticket shape's title and body follow, the title as a `# ` heading. Then publish every file in one call:

```bash
tracker-publish tickets <spec> <file>...
```

Git ignores `.spec-loop/`, so the files leave the checkout clean. Write nowhere outside the checkout, and make no temp folder: the loop's Cut runs this skill in a Session that has no permission for either, and nobody is there to give it.

Before it writes anything, it turns down a set the loop could not follow: a file with no number, two files with one number, a ticket not `open`, a `claimed-by` already set, a blocker that is not a ticket before it, or two tickets with one title. The refusal names the file and the fault, so mend that file and run the command again.

- **`files`**: it pushes the files into the spec's `tickets/` folder, on the spec's branch in `spec` mode. The folder is the parent relationship, so nothing more links a ticket to its spec. It turns down a spec that already has tickets, so a second run adds nothing.
- **`github`**: it files each ticket blockers first as an issue with the `ready-for-agent` label, makes it a sub-issue of the spec, turns its `blocked-by` into blocking links, and prints each issue number. `/skillworks:spec-loop` reads a spec's sub-issues to find its own work, so the link is what keeps two people's loops off each other's tickets. It is safe to run again: a rerun files only the tickets still missing and adds only the missing links, and after a full success it changes nothing and says so. When it stops on a failed `gh` call, run it again.

If the command stops a second time on the same fault, stop. Quote what it printed, and say which tickets were made and which were not. Under the spec loop, begin your last message with a line that starts with `BLOCKED` and names the command, as for a missing file, so the loop does not build a spec that is half cut.

The work is done when the command has printed one line for each ticket: an issue number with `github`, a file path with `files`. The tickets are then the loop's to pick and build.

**Leave the parent issue open**, or with `files` the spec's `status: open`. It is the loop's anchor and the drift check reads it at the end. With `github` the human closes it when the work merges, and with `files` the loop closes it.

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.