Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{
"name": "colormath",
"source": "./plugin",
"description": "Skills for the colormath gates + review pipeline: /colormath:ship takes a branch through PR, gates, review, and the PR's generated test plan — which it executes against the running stack — fixes the findings, then decides once: auto-merge when clean, or hold for a human; /colormath:qa QAs a focus area against the running stack then hands the fixes to ship; /colormath:bugfix turns a specific bug report into a merged fix — reproducing it before touching code, fixing at the layer the invariant belongs, remediating already-corrupted data, then handing off to ship. /colormath:refine-ticket grooms a ticket until it can be worked — investigating the code before it asks anything, then writing back a description, a file-anchored implementation plan, and an executable QA plan. /colormath:refine-initiative designs an initiative before it is built — investigating the architecture and decision records its features land in, interviewing until the picture is complete, then rewriting the initiative and its feature definitions, stopping short of code-level plans. /colormath:plan-initiative plans a whole initiative by running refine-ticket over each of its tickets in build order, injecting each one's place in the sequence and what the earlier plans decided."
"description": "Skills for the colormath gates + review pipeline: /colormath:ship takes a branch through PR, gates, review, and the PR's generated test plan — which it executes against the running stack — fixes the findings, then decides once: auto-merge when clean, or hold for a human; /colormath:qa QAs a focus area against the running stack then hands the fixes to ship; /colormath:bugfix turns a specific bug report into a merged fix — reproducing it before touching code, fixing at the layer the invariant belongs, remediating already-corrupted data, then handing off to ship. /colormath:refine-ticket grooms a ticket until it can be worked — investigating the code before it asks anything, then writing back a description, a file-anchored implementation plan, and an executable QA plan. /colormath:refine-initiative designs an initiative before it is built — investigating the architecture and decision records its features land in, interviewing until the picture is complete, then rewriting the initiative and its feature definitions, stopping short of code-level plans. /colormath:plan-initiative plans a whole initiative by running refine-ticket over each of its tickets in build order, injecting each one's place in the sequence and what the earlier plans decided. /colormath:implement-ticket takes a groomed ticket the rest of the way — checking its plan still matches the code, building it, executing its QA plan against the running stack, then handing off to ship."
}
]
}
30 changes: 29 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ changes may land in any release.

## Unreleased

MINOR when cut. Two new plugin skills are additive per
MINOR when cut. Three new plugin skills are additive per
[LIFECYCLE.md](LIFECYCLE.md), and the skill rename below — while a real break
for anyone with the old command in their fingers — cannot turn a consumer's CI
red, which is the test that makes a release MAJOR.
Expand Down Expand Up @@ -79,6 +79,34 @@ red, which is the test that makes a release MAJOR.
`refine-ticket` skill itself — the two ship together and a change to either's
contract is a change to both.

- **`/colormath:implement-ticket`** (`plugin/skills/implement-ticket/`) — takes
a groomed ticket from its plan to a shipped PR, closing the chain the other
skills start: `refine-initiative` designs, `plan-initiative` plans every
ticket, `refine-ticket` plans one, this one builds it.

It executes the plan rather than rewriting it, and the step that earns its
keep is the one before any code: **the plan was written against the codebase
as it was**, so every step is walked against the repo first. Where it no
longer holds, that is a finding for the user — silently improving a plan is
how a reviewed decision gets replaced by an unreviewed one, and sometimes the
right outcome is "this plan no longer holds" rather than a PR.

Then: build on a branch at the layer the plan names, execute the ticket's **QA
plan against the running stack** (every item observed, `⚠️` when a UI item has
no browser, failures fixed and re-run rather than shipped with the document
claiming they passed), `make preflight`, and hand off to `/colormath:ship`.
Deviations land in the PR body and a ticket comment; the `plan` and `qa_plan`
fields are left alone as the record of intent. It does not move tickets
between lanes, because lane meaning is per board.

A ticket with no plan is sent back to `refine-ticket` rather than planned and
implemented in one breath, which would mean nobody ever reviewed the plan. A
**task** is refused: that type carries no plans by design and is not code work.

**Contract surfaces** (Abacus MCP): `get_ticket` returning `type`, `plan`,
`qa_plan` and the parent initiative; `add_comment`. Plus `/colormath:ship` and
`/colormath:qa`'s recon discipline.

## v3.0.0 — 2026-08-01

**MAJOR — the gates could not fail. They can now.** Every gate command is
Expand Down
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,16 @@ stopping short of code-level plans and never starting the build; and
**`/colormath:plan-initiative`** closes the loop between the two — running
`refine-ticket` over every ticket in an initiative, in build order, injecting
each ticket's place in the sequence and what the earlier plans decided, so the
seams line up instead of seven independent groomings contradicting each other.
Each skill's behavior, prerequisites, and contract dependencies are documented
in [plugin/README.md](plugin/README.md).

`refine-ticket`, `refine-initiative` and `plan-initiative` need the
[Abacus](https://github.com/ColorMath/abacus) MCP server connected — the
plugin's one tracker dependency.
seams line up instead of seven independent groomings contradicting each other;
and **`/colormath:implement-ticket`** takes a groomed ticket the rest of the way
— checking its plan still matches the code before touching anything, building at
the layer the plan names, executing the ticket's QA plan against the running
stack, then handing off to `ship`. Each skill's behavior, prerequisites, and
contract dependencies are documented in [plugin/README.md](plugin/README.md).

`refine-ticket`, `refine-initiative`, `plan-initiative` and
`implement-ticket` need the [Abacus](https://github.com/ColorMath/abacus) MCP
server connected — the plugin's one tracker dependency.

Install manually:

Expand Down
41 changes: 41 additions & 0 deletions plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,47 @@ building.
`refine-ticket` call does a real code pass), and an initiative that has already
started building. Nothing else.

## `/colormath:implement-ticket` — build a planned ticket and ship it

Takes a ticket key (`/colormath:implement-ticket CM-00012`) and takes a groomed
ticket the rest of the way. The thinking already happened in `refine-ticket`;
this is where it meets the code:

1. **Read it and check it can be built** — no implementation plan means back to
`refine-ticket`, because a plan written by the same run that implements it has
never been read by anyone. A **task** carries no plans by design and is not
code work; an **initiative** is the wrong altitude. Reads the parent
initiative too when there is one, so the build doesn't collide with the ticket
next to it.
2. **Check the plan against the code before touching anything** — the plan was
written against the codebase as it *was*: files move, adjacent changes land,
assumptions expire. Every step is walked against the repo, and where it no
longer holds that is a **finding for the user**, not something to route around
silently. Sometimes the most valuable outcome here is "this plan no longer
holds, here's why" rather than a PR.
3. **Ask only what actually blocks** — by this point there is usually nothing;
grooming's whole job was to remove it. One round, and wanting several rounds
means the ticket isn't groomed and should go back.
4. **Build it at the layer the plan names**, on a branch, in the idiom of the
surrounding code, with tests at the layer the change lives at. Deviations from
the plan are recorded in chat, the PR body and a ticket comment — never by
rewriting the plan field, which would erase the difference between what was
intended and what happened.
5. **Execute the QA plan against the running stack** — every item gets an
observation, `⚠️` when no browser is reachable for a UI item, and a failure is
fixed and re-run rather than shipped with the document claiming it passed.
6. **Ship** — `make preflight`, then `/colormath:ship` for PR, gates, review,
test plan and the merge decision. Comments the outcome back onto the ticket.

It leaves the ticket's own fields alone: `plan` and `qa_plan` are the record of
intent, the comment is the record of what happened. It does not move tickets
between lanes — one board's "In Review" is another's "Staging", and guessing at
somebody's workflow is worse than leaving it where they put it.

**Prerequisites:** the **Abacus MCP server**, a checkout with the stack runnable
(step 5 is real QA, not a test run), and `/colormath:ship`'s own prerequisites,
since it hands off there.

## Adding a skill

One directory per skill: `skills/<name>/SKILL.md` with frontmatter
Expand Down
177 changes: 177 additions & 0 deletions plugin/skills/implement-ticket/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
name: implement-ticket
description: Take a planned ticket all the way to a shipped PR — check its plan still matches the code, ask only what genuinely blocks, build it at the layer the plan names, execute its QA plan against the running stack, then hand off to /colormath:ship. Use this when someone says to implement, build, do, or work a ticket that has already been groomed, or names a ticket key and says "go". Not for grooming (that's /colormath:refine-ticket) and not for a defect report (that's /colormath:bugfix).
argument-hint: [ticket key, e.g. CM-00012]
allowed-tools: Bash Read Edit Write Grep Glob Skill AskUserQuestion mcp__abacus__get_ticket mcp__abacus__add_comment mcp__abacus__list_boards mcp__abacus__list_tickets
---

Implement the ticket in "$ARGUMENTS", QA it, and ship it.

The ticket has already been groomed — `/colormath:refine-ticket` wrote a
description, an implementation plan whose steps name real files, and a QA plan
someone could execute. **Your job is to execute that, not to redo it.** The
thinking happened; this is where it meets the code.

The one thing that makes this more than typing: **the plan was written against
the codebase as it was.** Between grooming and now, files moved, an adjacent
change landed, an assumption expired. A plan executed blindly produces a diff
that satisfies the letter of a document and breaks the thing it was for. So the
first act here is checking the plan still describes reality, and the most
valuable outcome is sometimes "this plan no longer holds, here's why" rather
than a PR.

## 1. Read the ticket and check it is ready to build

Call `mcp__abacus__get_ticket`. It takes the key directly; case and padding
don't matter. If "$ARGUMENTS" is a title fragment, resolve it with
`list_boards` / `list_tickets` and confirm which ticket you landed on.

Read all of it — description, **implementation plan**, **QA plan**, every
comment, type, and the initiative it belongs to if it has one. Comments carry
decisions made after the plan was written, and they win.

Then check it can be implemented at all:

- **No implementation plan** — stop. This skill executes a plan; it does not
write one. Send them to `/colormath:refine-ticket <key>` and say why: a plan
written by the run that implements it has never been read by anyone.
- **No QA plan** — say so and ask whether to continue. You can implement without
one, but nothing will check the result the way a groomed ticket intends, and
the honest thing is to let them choose rather than inventing acceptance
criteria at the moment they'd be most convenient.
- **A task** — that type carries no plans by design. It is not code work; it is
a chore somebody does. Say so and stop.
- **An initiative** — the wrong altitude. Its tickets are what get implemented;
`/colormath:plan-initiative` plans them, then this skill takes them one at a
time.

If the ticket belongs to an initiative, read that too. The initiative says what
the whole thing is for and what the neighbouring tickets are doing, which is how
you avoid building something that collides with the ticket after it.

## 2. Check the plan against the code before you touch anything

Walk the plan step by step with the repo open. For each step:

- **Does the file still exist, at that path?** A renamed module means the plan
is describing a codebase that no longer exists.
- **Does the surrounding code still look like the plan assumes?** The function
it says to extend, the layer it says to add to, the caller it says will pick
the change up.
- **Has any of it already been done?** By the ticket next to it in the
initiative, or by an unrelated PR that passed through.
- **Do the repo's conventions still allow it?** `AGENTS.md` / `CLAUDE.md`, the
ADRs, the rules files. A plan that was fine in March can violate a decision
recorded in April, and the decision wins.

Where the plan holds, say so briefly and move on. Where it does not, that is a
**finding**, and it goes to the user in step 3 rather than being quietly
routed around. Silently improving a plan is how a reviewed decision gets
replaced by an unreviewed one.

## 3. Ask only what actually blocks you

By this point there usually is nothing to ask — grooming's whole job was to
remove these, and a skill that reopens settled questions has wasted the
grooming. Ask only when you genuinely cannot proceed:

- the plan no longer matches the code and there is a real choice about what to
do instead;
- two readings of a step produce materially different, user-visible results;
- the plan needs something the repo cannot give itself — a credential, a vendor
account, a decision that belongs to someone else.

One round, `AskUserQuestion`, concrete options, recommendation first. Anything
you can settle from the ticket, the initiative, the ADRs or the conventions is
not a question. And if you find yourself wanting several rounds, the ticket is
not groomed and should go back to `/colormath:refine-ticket` — say that instead
of interviewing your way to a design.

## 4. Build it, at the layer the plan names

Branch first — `feat/<ticket-key-slug>` or the repo's own convention — never the
default branch.

Then implement, in the idiom of the surrounding code: its conventions, its
layering, its naming, its comment density. Follow the plan's ordering when it
has one; it usually encodes a dependency.

Three things worth more than speed:

- **Tests at the layer the change lives at**, not one layer up where they are
easier to write. Where the plan or the repo names a coverage or gate
expectation, meet it here rather than discovering it in CI.
- **Deviations get recorded, not hidden.** If implementing shows the plan was
wrong — a step that cannot work, a better layer, a case the plan missed —
say so in chat as you go, and put it in the PR body and in a ticket comment
at the end. The plan stays as the record of what was intended; the comment
records what actually happened and why. Never rewrite the plan field to match
what you did: that erases the difference between the two, which is the only
interesting part.
- **Scope discipline.** Build the ticket, not the ticket plus the thing next to
it that is obviously also wrong. Note the neighbour, finish the ticket. If it
belongs to an initiative, the neighbour may literally be the next ticket.

## 5. Execute the QA plan against the running stack

The QA plan is a list of claims about a running system, and an item counts only
when you have watched the system agree. A passing test suite is not the QA plan
— it is one of the things the QA plan usually says to check.

Bring the stack up the way the repo does it (`make up-dev` or its equivalent),
and follow `/colormath:qa`'s recon discipline for identities and seeded data —
authorization items need the *wrong* role as well as the right one, and one
admin account proves nothing about access control.

Work every item and record what you observed: the request and response, the row
you read back, the screen state. Drive UI items through a browser if one is
reachable; if none is, mark them `⚠️` unverified and say so plainly rather than
inferring them from the code you just wrote — which is the least trustworthy
possible source for whether the UI works.

Anything that fails is yours to fix now, then re-run the item. A QA plan item
that fails and gets shipped anyway is worse than one nobody ran, because the
document now says it passed.

Restore what you mutated: rows you created, config you flipped, credentials you
minted. Local state is yours to change and yours to put back.

## 6. Ship it

Run the repo's full local gate mirror once (`make preflight`) so an avoidable
failure does not cost a CI round trip. Then invoke `/colormath:ship`, which
takes it the rest of the way: PR, gates, the review and its generated test plan
executed against the running stack, fixes for what turns up, and either an
auto-merge when the PR is genuinely clean or a hold with the reason.

Give ship a title naming the change in the ticket's own terms, and a body that
carries what a reviewer cannot reconstruct: **the ticket key and what it asked
for**, **where the plan held and where it did not**, **the QA plan's results
including anything unverified**, and any deviation you made and why.

When ship comes back, `add_comment` on the ticket with the outcome — the PR
link, whether it merged or is held, and the deviations. That comment is how the
ticket stops being a plan and becomes a record. Leave the ticket's own fields
alone: `plan` and `qa_plan` are what was intended, and the comment is what
happened.

Do not move the ticket between lanes. Lane meaning is per board — one team's
"In Review" is another's "Staging" — and guessing at somebody's workflow is
worse than leaving it where they put it. Say what you would have moved it to, if
it seems useful, and let them.

## Rules

- **Execute the plan; don't rewrite it.** No re-grooming, no "improving" the
plan silently. Where it is wrong, say so and decide with the user.
- **A ticket with no plan goes back to `/colormath:refine-ticket`.** Writing the
plan and implementing it in the same breath means nobody ever reviewed the
plan.
- **Never work on the default branch**, and never merge by hand — `ship` owns
that decision and has the gates to make it.
- **QA is executed, not asserted.** Every item gets an observation. Unverified
is a legitimate result and gets marked; assumed is not.
- **One ticket.** Don't implement its neighbours, don't fix adjacent bugs beyond
what the change requires, don't create tickets. Note them and move on.
- **Record what actually happened** in a ticket comment at the end,
deviations included, and leave the planned fields as the record of intent.