Skill pipelines
Last updated
May be stale
This page was last updated ago, on 6 October 2026. Check what it says against the code before relying on it.
The engineering skills in .claude/skills/ are built to chain: each one leaves an artifact the next one starts from. This file names the chains, what each stage hands on, and the labels an issue carries between stages. The skills themselves own the detail of each step; this is the map between them.
Every handoff between stages is a durable artifact (an issue, a checklist, a dependency edge), never the transcript. A later session, or a different person, can pick up any stage cold from the tracker. Where the artifact lives is set by artifacts.md.
Idea to shipped code
/grilling → /to-spec → /to-tickets → /wave
For a change whose destination is clear enough to specify. When the destination itself is unclear,
use /wayfinder instead: it maps decisions toward a destination rather than slicing known work.
| Stage | Starts from | Leaves behind | Issue state after |
|---|---|---|---|
/grilling |
An idea or plan in conversation | A shared understanding in the conversation, plus any GLOSSARY.md terms or ADRs /domain-modeling wrote along the way |
No issue yet |
/to-spec |
The grilled conversation | One spec issue | type/spec, priority, status/awaiting-review |
/to-tickets |
The spec issue | Either the spec converted into a task, or the spec as an epic with a ## Tickets checklist and one ticket issue per slice, wired with native dependencies |
Spec: type/task or type/epic, status/triaged. Tickets: type/task, priority, effort, status/triaged |
/wave |
The triaged task, epic or initiative | One session per child that can move, each running the skill that advances it | Each dispatched child: assigned |
The first two stages have a one-session form. /grill-to-spec runs the grilling and then writes the
spec out of it without stopping in between, which is the route for a subject that has to be
interrogated before it can be written up — an accepted but undesigned suggestion, most often, which /triage leaves at status/awaiting-review
with a condensed brief, or a
type/stub. A stub is an idea filed by hand as a placeholder, often one of several under an
initiative. /grill-to-spec writes the spec into a suggestion or a stub itself rather than a new
issue, so it becomes the type/spec that stage 3 breaks down; a suggestion keeps the player's text
and its Synced from: line below the spec.
/grill-to-tickets runs all three in one session: /grill-to-spec, then /to-tickets on the spec
it published, putting the testing seams and the breakdown to the user in one check-in, so the spec
moves straight on to type/epic or type/task at status/triaged. A stub or a suggestion carries
through both in-place conversions. It is a route a person chooses; /wave dispatches to
/grill-to-spec, not to it.
1. Grill
/grilling works the design tree in rounds until nothing is left silently assumed, with
/domain-modeling loaded so glossary terms and ADRs are written as they settle. It offers to raise
those as a docs PR once grilled; /grill-with-docs raises it without asking, and /grill-me is
/grilling under its other name. No issue comes out of it, so the conversation it leaves is the
input to the next stage: run /to-spec in the same session, before the context is lost.
2. Spec
/to-spec synthesises the conversation into a spec and publishes it as type/spec at
status/awaiting-review. It does not size the work. A spec is input to a breakdown, not something
to build directly, and it isn't triaged because it has no acceptance criteria
(triage-labels.md). /grill-to-spec ends here too, having
done the grilling itself.
A spec nobody has broken down yet is findable with q type/spec.
3. Tickets
/to-tickets <spec> is the one place that sizes. It proposes tracer-bullet slices and quizzes you on
them, then does one of two things:
- One slice: converts the spec in place. It appends acceptance criteria and blockers, re-types
it
type/taskwith an effort, and moves it tostatus/triaged. There is no child issue, and the waves stage is a single/deliveron that issue. - Several slices: publishes one
type/taskticket per slice in dependency order, each openingPart of #<spec>., wires blockers as native dependencies, then re-types the spectype/epic, appends the## Ticketschecklist, and moves it tostatus/triaged.
4. Waves
The tickets are a task graph, not a list. A wave is the frontier of that graph: every child
that can move right now. /wave <issue>… walks that graph and
launches one wave:
- Resolve the frontier.
frontier.pyreads the tree the arguments reach — descending through every## Ticketschecklist, at any depth — and buckets each child on its state, its assignees, its open pull requests and itsdependencies(gitea-issues). - Claim the whole wave by assigning each frontier ticket before any session starts, so a parallel run doesn't take the same ones.
- Dispatch each one to the skill that advances it, in its own session:
/deliverfor a triaged ticket, but also/triagefor a new report,/grill-to-specfor a suggestion that passed triage or a stub,/to-ticketsfor a spec or an unbroken-down epic,/researchfor a question. One run moves each child one rung./wave --inlineclaims only the earliest frontier ticket and works it in the same session instead. To land a whole epic as one pull request rather than one per ticket,/deliver-epic <epic>builds every ticket in dependency order on one branch instead, once all of them are triaged. - Land them. As each ticket's work merges, close the ticket; the next run ticks its line in the parent's checklist.
- Run it again. Closing tickets unblocks the ones that depended on them, and answering a parked
session's questions moves that child on. Repeat until every checklist is ticked, then close the
epic yourself —
/wavenever closes anything.
A wave doesn't have to wait for its slowest ticket: a ticket unblocked by an early merge can start straight away. Batching into waves is the minimum; starting each ticket as soon as it is unblocked is the same graph worked faster.
Tickets in a wave can still touch the same files. Merge conflicts between siblings are expected, and are resolved when the second one lands, not avoided by serialising the wave.
A UI feature on one branch
/build-ui → (/grilling) → /ux-design → /ux-review → spec issue → /to-tickets → sub-PRs → one main PR
For a panel, a flow or the HUD built end to end by the UI agents. It is the chain above with one
difference that changes the mechanics: everything lands on one feature branch
(dev/<person>-<agent>/<feature>) and reaches master through one main PR. The skill owns the
detail; these are the parts that differ from waves, so they are not read off the section above.
| Stage | Leaves behind |
|---|---|
| Grill, only when starting from an idea | A shared understanding in the conversation, which the spec is written from |
| Spec | The UX spec as the feature branch's first commit, and the main PR open as a draft |
| Spec review | /ux-review verdicts as comments on the main PR, repeated until approved |
| Publish | A pointer spec issue: the document stays the source of truth, so /to-spec's template is not used |
| Break down | The epic and its tickets, exactly as /to-tickets leaves them |
| Build | One sub-PR per ticket, built by /deliver's stages in a worktree of its own, cut from the feature branch and merged back into it |
| Land | The main PR, out of draft, carrying the closers and the ## Changelog section |
- A sub-PR references its ticket and never closes it. The closers (
Closes #<n>.for every ticket and the epic) go in the main PR's body, so the tickets close when the feature reaches master and not before. - The frontier is read from ticks, not from closed issues. Tickets stay open until the main PR
merges, so "every blocker is closed" is never true here. A ticket is ticked in the epic's
## Ticketschecklist when its sub-PR merges into the feature branch, and the frontier is the unticked tickets with no open sub-PR whose blockers are all ticked. - A sub-PR merges only when its reviews are clean and its CI is green, one at a time, with the next ticket's branch updated onto the feature branch first.
public=appears nowhere until the main PR's merge message. Sub-PR merges are merge commits that reach master with the feature. The one exception is a Feedback close message, which goes at the end of the main PR's body when that PR closes a feedback-synced issue; a sub-PR never carries one, because it closes nothing.- Resume from the epic number. Every stage's state is on the tracker or in git, so
/build-ui <epic>picks a feature up cold.