|
|
|
@@ -0,0 +1,802 @@
|
|
|
|
|
---
|
|
|
|
|
name: ticket
|
|
|
|
|
description: End-to-end Jira ticket workflow — fetch a ticket into .claude/docs/epics/, write a plan, implement it with clean commits, run pre-mr-review to convergence, and write the MR doc. Use when the user gives you a Jira ticket key (e.g. KACP-11111) to work, or asks to plan/implement/wrap up a ticket.
|
|
|
|
|
disable-model-invocation: true
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Ticket Workflow
|
|
|
|
|
|
|
|
|
|
Turns a Jira ticket key into: a saved ticket record, a reviewed plan, implemented and
|
|
|
|
|
committed code, a converged `pre-mr-review` audit, and an MR doc ready to paste into
|
|
|
|
|
GitLab/GitHub. This skill is user-level (`~/.agents/skills/ticket/`) and works the same
|
|
|
|
|
way in any repo that has a `.claude/docs/` directory and a `pre-mr-review` skill.
|
|
|
|
|
|
|
|
|
|
Invoked as `/ticket KACP-11111`. The ticket key is passed as the skill's arguments. Called
|
|
|
|
|
again later with the same key, it resumes wherever it left off — see **Phase 0**.
|
|
|
|
|
|
|
|
|
|
Not to be confused with `/review-ticket`. That skill writes the *developer review* on a
|
|
|
|
|
Jira story, the estimate, risk level, and testing tables, as part of authoring a ticket
|
|
|
|
|
before anyone builds it. It has nothing to do with reviewing code. The code review in
|
|
|
|
|
this skill is Phase 2 step 5 and is performed by a dispatched agent, not by a skill.
|
|
|
|
|
|
|
|
|
|
## Directory layout this skill maintains
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
.claude/docs/epics/
|
|
|
|
|
<EPIC-KEY>/
|
|
|
|
|
epic.md # brief epic context, written once, best-effort
|
|
|
|
|
<TICKET-KEY>/
|
|
|
|
|
resources/
|
|
|
|
|
ticket.md # title, description, dev review instructions
|
|
|
|
|
<attachments...> # images, videos, other files as downloaded
|
|
|
|
|
<video>.transcript.txt # only for videos that got transcribed
|
|
|
|
|
<video>.transcript.srt
|
|
|
|
|
plan.md
|
|
|
|
|
deliverables/ # only for tickets whose output is documents, not code
|
|
|
|
|
<deliverable-slug>/
|
|
|
|
|
<deliverable-slug>.md
|
|
|
|
|
<deliverable-slug>.typ
|
|
|
|
|
<deliverable-slug>.pdf
|
|
|
|
|
proof/ # captured working feature proof, uploaded to Jira by the user
|
|
|
|
|
mr.md # the MR description only, written once pre-mr-review says Ready to Open MR
|
|
|
|
|
tickets/
|
|
|
|
|
<TICKET-KEY>/ # same shape, for tickets with no epic
|
|
|
|
|
resources/...
|
|
|
|
|
plan.md
|
|
|
|
|
deliverables/...
|
|
|
|
|
mr.md
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Scripts this skill uses
|
|
|
|
|
|
|
|
|
|
- `~/.agents/skills/ticket/scripts/jira-fetch-issue.sh <KEY> <OUT.json>` — fetches one
|
|
|
|
|
issue (`fields=*all`, rendered HTML description, field-name map) via `JIRA_BASE_URL` /
|
|
|
|
|
`JIRA_CREDENTIALS`.
|
|
|
|
|
- `~/.agents/skills/ticket/scripts/jira-download-attachments.sh <issue.json> <resources-dir>`
|
|
|
|
|
— downloads every attachment on that issue into the given directory, printing
|
|
|
|
|
`filename<TAB>mimeType<TAB>bytes` per file.
|
|
|
|
|
- `~/.agents/skills/ticket/scripts/transcribe.sh <media-file> <output-dir> [model]` —
|
|
|
|
|
transcribes via whisper.cpp in podman, auto-detecting NVIDIA/AMD/Vulkan acceleration
|
|
|
|
|
and falling back to CPU on failure. Requires `podman`; uses host `ffmpeg` if present.
|
|
|
|
|
|
|
|
|
|
Both Jira scripts require `JIRA_CREDENTIALS` (`[email protected]:api-token`, Basic auth)
|
|
|
|
|
to already be exported in the environment. `JIRA_BASE_URL` defaults to
|
|
|
|
|
`https://ksense-tech.atlassian.net` if unset.
|
|
|
|
|
|
|
|
|
|
Each Bash tool call runs in a fresh shell that does not inherit state from previous
|
|
|
|
|
calls, so a plain `export` the user ran earlier in their own terminal will not show up
|
|
|
|
|
here. Before calling either Jira script, always run `source ~/.bashrc 2>/dev/null` in
|
|
|
|
|
the same Bash call (chained with `&&` or on the line before), then check the var is
|
|
|
|
|
actually set. Only if it's still missing after that should you stop and tell the user
|
|
|
|
|
to export it (or point you at wherever it's actually set, e.g. a dotfiles repo) rather
|
|
|
|
|
than guessing or prompting for a token inline.
|
|
|
|
|
|
|
|
|
|
### AMD Vulkan acceleration
|
|
|
|
|
|
|
|
|
|
`transcribe.sh` uses the whisper.cpp Vulkan image when `/dev/dri` and `vainfo` are
|
|
|
|
|
available. On a host with more than one AMD or Intel GPU, select the intended render
|
|
|
|
|
node explicitly instead of exposing every DRI device and trusting enumeration order:
|
|
|
|
|
|
|
|
|
|
1. Identify the GPU PCI address with `lspci | rg -i 'vga|display|3d'`.
|
|
|
|
|
2. Map it to a render node with `ls -l /dev/dri/by-path` and resolve the matching
|
|
|
|
|
`pci-<address>-render` symlink with `readlink -f`.
|
|
|
|
|
3. Run the helper with the resolved node, for example:
|
|
|
|
|
`WHISPER_VULKAN_DEVICE=/dev/dri/renderD128 ~/.agents/skills/ticket/scripts/transcribe.sh <media-file> <output-dir> [model]`.
|
|
|
|
|
4. Verify the runtime log. `Selected acceleration: vulkan` only confirms the intended
|
|
|
|
|
path. Require `ggml_vulkan: Found ...`, the exact requested GPU name, and
|
|
|
|
|
`use gpu = 1` before claiming hardware acceleration worked.
|
|
|
|
|
|
|
|
|
|
The current whisper.cpp images declare `bash -c` as their container entrypoint. The
|
|
|
|
|
helper overrides it with `/app/build/bin/whisper-cli`. An older helper without this
|
|
|
|
|
override can fail before Whisper starts with `-f: line 1: /models/...: Permission
|
|
|
|
|
denied` and then fall back to CPU.
|
|
|
|
|
|
|
|
|
|
The accelerated paths remain best-effort on other hosts. The helper falls back to the
|
|
|
|
|
CPU image after an accelerated runtime failure. If the user explicitly requested GPU
|
|
|
|
|
acceleration, CPU fallback does not satisfy the request. Diagnose the accelerated path,
|
|
|
|
|
rerun it, and verify the device log instead of accepting the fallback transcript.
|
|
|
|
|
|
|
|
|
|
## House style (applies to everything this skill writes or commits)
|
|
|
|
|
|
|
|
|
|
- No code comments unless the user explicitly asks for one in that spot.
|
|
|
|
|
- No em dashes, en dashes, semicolons, or arrow glyphs in commit messages, `ticket.md`,
|
|
|
|
|
`plan.md`, or `mr.md`. Plain punctuation only.
|
|
|
|
|
- Commits are `git commit -m "<short imperative message>"` only — no body, no
|
|
|
|
|
co-author line, no `Claude` / `Codex` / `AI` trailer of any kind.
|
|
|
|
|
- Never `git push`. Never open an MR/PR. This skill prepares everything needed to open
|
|
|
|
|
one by hand; opening it is the user's call.
|
|
|
|
|
- Don't check a checklist box (in `mr.md` or anywhere else) unless you actually verified
|
|
|
|
|
it. Leave it unchecked and say why in the notes rather than guessing.
|
|
|
|
|
|
|
|
|
|
## Verification tools available
|
|
|
|
|
|
|
|
|
|
The goal isn't "a plausible-sounding plan" or "code that compiles" — it's a plan and
|
|
|
|
|
an implementation that are actually correct, checked against the real system rather
|
|
|
|
|
than assumed from the ticket text. Use whichever of these actually verify the thing
|
|
|
|
|
in question, before writing `plan.md` (Phase 1) and again whenever Phase 2's
|
|
|
|
|
implementation makes a claim that's checkable:
|
|
|
|
|
|
|
|
|
|
- **The codebase itself.** Don't take the ticket's description of "how things work
|
|
|
|
|
today" at face value. Read the actual models, routes, and components involved and
|
|
|
|
|
reconcile any mismatch. If the ticket says a field works one way and the code says
|
|
|
|
|
otherwise, say so in the plan rather than silently trusting either source.
|
|
|
|
|
- **Jira, beyond the single ticket.** Many tickets assume Jira's own data model (custom
|
|
|
|
|
fields, issue types, workflow states) or context that lives on linked issues,
|
|
|
|
|
comments, or the epic rather than on the ticket itself. Search related issues
|
|
|
|
|
(`searchJiraIssuesUsingJql`, issue links, other children of the same epic) and check
|
|
|
|
|
the real field list (the `names` map `jira-fetch-issue.sh` already pulls, or
|
|
|
|
|
`/rest/api/3/field` for the full set) instead of guessing at a custom field's shape.
|
|
|
|
|
- **Staging**, via Infisical (see the `infisical-api` / `infisical-user-setup-guide`
|
|
|
|
|
skills for pulling secrets). Staging is fair game to probe directly whenever it
|
|
|
|
|
would settle something real, no need to ask first, that's what it's for.
|
|
|
|
|
- **Prod and CI env vars**, at `.claude/docs/env/prod/.env` and
|
|
|
|
|
`.claude/docs/env/ci/.env`. Ask the user for permission before every use, even if
|
|
|
|
|
they granted it last time, say what you want to verify and why. Once granted: use
|
|
|
|
|
the values (e.g. source them for a one-off read-only command) without printing the
|
|
|
|
|
raw file contents or individual secret values into your output. Read-only, always —
|
|
|
|
|
never run anything that writes, mutates, or deletes against prod or CI. If what you
|
|
|
|
|
actually need is a prod database query, that's exactly the kind of thing to ask
|
|
|
|
|
about explicitly rather than assume the file's DB credential is fair game by default.
|
|
|
|
|
|
|
|
|
|
If something would need access you don't have (a different repo, a system you can't
|
|
|
|
|
reach), say so explicitly in `plan.md`'s Open questions instead of silently skipping
|
|
|
|
|
the check.
|
|
|
|
|
|
|
|
|
|
**How to write what you found, in a deliverable.** State it as a plain confirmed
|
|
|
|
|
fact: "Confirmed in prod: 67 of 70 companies have `hourlyRate` set." Never describe
|
|
|
|
|
the verification method itself, no "a read-only pull," "a read-only pass," "read-only
|
|
|
|
|
query," or similar plumbing language. The reader doesn't know or care that you ran a
|
|
|
|
|
SQL query, they care what's true. This applies to prod, staging, Jira, and the
|
|
|
|
|
codebase equally.
|
|
|
|
|
|
|
|
|
|
## Deliverable documents (spikes, proposals, anything whose output is a document)
|
|
|
|
|
|
|
|
|
|
Some tickets (spikes, research, migration proposals, the KACP-22764 kind of ticket)
|
|
|
|
|
don't produce code, they produce documents for a PM or another engineer to read. When
|
|
|
|
|
a `plan.md` Step produces a document rather than a code change, it becomes its own
|
|
|
|
|
subfolder under `<target-dir>/deliverables/<deliverable-slug>/` with three files:
|
|
|
|
|
|
|
|
|
|
- `<slug>.md` — the source of truth for content. Write this first, get the content
|
|
|
|
|
right before worrying about layout.
|
|
|
|
|
- `<slug>.typ` — a Typst version of the same content, laid out for an actual printed
|
|
|
|
|
or PDF-read document, not a mechanical markdown-to-typst conversion. Real headings,
|
|
|
|
|
`table()` for tabular data, and a diagram (via the `cetz` package,
|
|
|
|
|
`#import "@preview/cetz:VERSION"`) wherever a diagram would genuinely communicate
|
|
|
|
|
faster than prose — entity relationships, hierarchies, flows. Don't force a diagram
|
|
|
|
|
in where a bullet list would do. Style is engineering-oriented and readable: nothing
|
|
|
|
|
colorful or flashy, this goes to a technical PM and other engineers.
|
|
|
|
|
- `<slug>.pdf` — compiled from the `.typ` file.
|
|
|
|
|
|
|
|
|
|
**Write for the actual audience, not for yourself.** The reader is a PM or another
|
|
|
|
|
engineer who has never seen `.claude/docs/`, doesn't know what `plan.md` or
|
|
|
|
|
`ticket.md` are, and doesn't have this repo (or any other local repo) checked out.
|
|
|
|
|
Never reference `.claude/docs/` or any local file path in a deliverable's content.
|
|
|
|
|
Never say "see plan.md" or "see ticket.md", those are personal working files, not
|
|
|
|
|
things a reader can open. Refer to "this ticket" or a plain Jira link, not a local
|
|
|
|
|
path. If a fact came from another repo on this machine, state the fact, don't cite
|
|
|
|
|
the local checkout path it came from.
|
|
|
|
|
|
|
|
|
|
**Structure mirrors the ticket, not a narrative.** The PM reads a deliverable to
|
|
|
|
|
verify that everything they asked for is in it, and to come back later and re-find
|
|
|
|
|
one specific answer. Build the document from the ticket's own structure:
|
|
|
|
|
|
|
|
|
|
- If the ticket asks direct questions (a spike's "Questions to Answer" table), the
|
|
|
|
|
first section is `Questions and answers`: every ticket question in ticket order,
|
|
|
|
|
each with its priority, a direct two or three sentence answer, and a pointer to
|
|
|
|
|
the section holding the detail. This page is how the reader checks all
|
|
|
|
|
acceptance criteria without reading the rest.
|
|
|
|
|
- One section per named deliverable or requested topic, titled with the ticket's
|
|
|
|
|
own words. If the ticket says "status-weighting approach" there is a section
|
|
|
|
|
called "Status weighting"; if it asks how the datamodel changes, the section is
|
|
|
|
|
"Datamodel". Plain flat headings, one level below the title, in roughly the
|
|
|
|
|
ticket's order of importance (schema and calculations early).
|
|
|
|
|
- Each section is the artifact, not prose about it: schema changes as real schema
|
|
|
|
|
code in the repo's conventions (e.g. Prisma model blocks), math as formula code
|
|
|
|
|
blocks, mappings as tables, UI as the real mockup screenshots. Current-state
|
|
|
|
|
context earns a sentence or two inside the section that needs it; the section
|
|
|
|
|
states the decision, not the investigation that produced it.
|
|
|
|
|
- Sections are short. Cover every question and requirement, spend few words each.
|
|
|
|
|
Depth lives in the code blocks and tables, not in longer paragraphs.
|
|
|
|
|
- The voice is a dry engineering spec. Plain declarative sentences, no scene
|
|
|
|
|
setting, no flourishes ("the heart of the model", "the honest story"). A
|
|
|
|
|
correct document that reads glossy costs the reader's trust in it.
|
|
|
|
|
|
|
|
|
|
**State final decisions, don't narrate the journey.** A deliverable answers "what
|
|
|
|
|
goes where and why," not "here's what we used to think, here's what turned out to be
|
|
|
|
|
wrong, here's what's resolved now versus still open." No "Corrections made" section
|
|
|
|
|
listing earlier mistakes, no "Resolved" / "Still open" split, no "first draft said
|
|
|
|
|
X, that was wrong" asides. Figure out the right answer (including asking the user
|
|
|
|
|
directly, mid-task, for anything you can't determine yourself) before or while
|
|
|
|
|
writing the deliverable, then write the resolved shape as plain fact, the same way
|
|
|
|
|
the very first version of a proposal document should read: a clean "stays here,
|
|
|
|
|
moves there, and why" description, nothing else. If something genuinely can't be
|
|
|
|
|
resolved without more input and truly must ship as an open question, keep it to the
|
|
|
|
|
smallest possible list, phrase it as a direct question, and ask the user about it
|
|
|
|
|
directly (don't just leave it sitting in the document) rather than defaulting to
|
|
|
|
|
"flag everything as open" as a way to look thorough.
|
|
|
|
|
|
|
|
|
|
**Describe the mock, not how far the implementation went.** A mockup deliverable
|
|
|
|
|
should say that a quick UI mockup was made by updating the relevant screens, then
|
|
|
|
|
explain what the mock demonstrates. A schema deliverable should present the proposed
|
|
|
|
|
schema and migration direction. Never tell the deliverable's audience that the mock
|
|
|
|
|
was fully coded, built as a real feature, production-ready, implemented end to end,
|
|
|
|
|
or created on a working branch. The code-based mock workflow below is an internal
|
|
|
|
|
method for producing accurate screenshots, not part of the deliverable's story.
|
|
|
|
|
|
|
|
|
|
Process, per deliverable:
|
|
|
|
|
|
|
|
|
|
1. Write `<slug>.md`.
|
|
|
|
|
2. Write `<slug>.typ` from it, per the styling notes above.
|
|
|
|
|
3. Compile: `typst compile <slug>.typ <slug>.pdf`. `typst` should already be on PATH;
|
|
|
|
|
if it isn't, tell the user rather than silently skipping the PDF.
|
|
|
|
|
4. Actually look at the compiled PDF using the Read tool (it reads PDFs directly, page
|
|
|
|
|
by page for longer documents). Check every page for real layout problems: text or
|
|
|
|
|
a table overflowing a page, an awkward page break splitting a table or diagram,
|
|
|
|
|
cramped or excessive spacing, a diagram that rendered wrong. A successful compile
|
|
|
|
|
only means valid Typst, not that it looks right — actually look.
|
|
|
|
|
5. If anything looks wrong, fix `<slug>.typ` and go back to step 3. Repeat until the
|
|
|
|
|
PDF genuinely looks right, not just until it compiles without erroring.
|
|
|
|
|
|
|
|
|
|
If `.claude/docs/` is tracked by git in this repo (check with
|
|
|
|
|
`git check-ignore .claude/docs` — no output means it's tracked), commit a
|
|
|
|
|
deliverable's three files together as one commit, same as any other step. If it's
|
|
|
|
|
gitignored (as in command-center), these files never show up in git at all, which is
|
|
|
|
|
expected and fine — they're meant to be shared manually (Slack, attached to the Jira
|
|
|
|
|
ticket, however this team actually hands off docs), not through the MR. Don't try to
|
|
|
|
|
force-add gitignored files to work around this without asking first, that's an
|
|
|
|
|
existing deliberate house rule, not an oversight.
|
|
|
|
|
|
|
|
|
|
If a deliverable is a UI mock, capture the UI mock described in **Mocks and datamodel
|
|
|
|
|
changes** below rather than drawing a separate wireframe. In the deliverable itself,
|
|
|
|
|
describe it only as a quick UI mockup.
|
|
|
|
|
|
|
|
|
|
## Mocks and datamodel changes: build them for real
|
|
|
|
|
|
|
|
|
|
When a ticket calls for mocks or datamodel changes (a spike proposing new screens or a
|
|
|
|
|
new schema, for instance), don't stop at wireframes or a schema proposal document.
|
|
|
|
|
Build it for real, on the ticket's branch. Mark these steps `(mock)` in `plan.md`.
|
|
|
|
|
|
|
|
|
|
A mock deliverable is **two artifacts**, not one, and they answer different questions.
|
|
|
|
|
The code proves the thing is buildable and surfaces the problems a picture hides. The
|
|
|
|
|
visual mocks show what it should look like once it's built properly, unconstrained by
|
|
|
|
|
what was quick to wire up. Ship both, and don't let either stand in for the other.
|
|
|
|
|
|
|
|
|
|
- **Datamodel changes**: make the actual schema change (e.g. edit
|
|
|
|
|
`packages/db/prisma/schema.prisma` and generate a migration the normal way for this
|
|
|
|
|
repo) rather than only describing it in a document. The proposal document from
|
|
|
|
|
Deliverable documents above can and should still exist, but it now describes
|
|
|
|
|
something that's actually in the branch, not just a plan for something that might
|
|
|
|
|
be built later.
|
|
|
|
|
- **UI mocks**: build the actual screens/components in the app, wired up enough to
|
|
|
|
|
navigate to and look real, not a static image or a markdown wireframe. Where it
|
|
|
|
|
isn't much more work, prefer making it an actually working proof of concept (real
|
|
|
|
|
data flowing through, not a placeholder-filled shell) over a purely cosmetic mock —
|
|
|
|
|
that's almost always more informative for close to the same effort.
|
|
|
|
|
MVP quality is the bar for this half, not polish: real data flowing and a screen you
|
|
|
|
|
can navigate to is what matters, and rough or ugly is fine, because the visual mocks
|
|
|
|
|
below are what carry the intended look.
|
|
|
|
|
- **Visual mocks alongside the code, one or two of them.** The built version is
|
|
|
|
|
deliberately rough, so on its own it under-sells the idea to anyone reviewing it.
|
|
|
|
|
Produce one or two polished mocks that aren't constrained by what was cheap to build:
|
|
|
|
|
the layout, spacing, and density as they should actually be. In Claude Code the
|
|
|
|
|
`design` skill produces a canvas of artboards for exactly this; in a harness without
|
|
|
|
|
it, a self-contained HTML page does the same job. These are design intent, not
|
|
|
|
|
implementation promises, so call out anything a mock shows that the code doesn't do
|
|
|
|
|
yet.
|
|
|
|
|
- **Scope discipline still applies.** This is a proof of concept, not a production
|
|
|
|
|
feature. Don't chase every edge case and don't fix unrelated pre-existing bugs you
|
|
|
|
|
happen to notice along the way, just implement enough of the real thing to be
|
|
|
|
|
screenshotted and evaluated. If doing it for real would take significantly longer
|
|
|
|
|
than a static mock would, say so in `plan.md` rather than silently scoping it down
|
|
|
|
|
without mentioning the tradeoff.
|
|
|
|
|
- **Screenshot the real thing.** Once it's built and running, use the `run` skill to
|
|
|
|
|
get the app up and a browser automation tool (e.g. `claude-in-chrome`) to capture
|
|
|
|
|
the actual screens, instead of drawing a wireframe. Save screenshots under
|
|
|
|
|
`deliverables/<slug>/screenshots/` and the visual mocks under
|
|
|
|
|
`deliverables/<slug>/mocks/`, and embed both in `<slug>.typ` via `image()` when
|
|
|
|
|
building the mockups deliverable. Label which is which. A reader who can't tell a
|
|
|
|
|
built screen from a design mock will read the mock as a promise of what already
|
|
|
|
|
works.
|
|
|
|
|
- **Same rigor as any other code.** This is real work on the ticket branch like any
|
|
|
|
|
other implementation step: same commit discipline, included in Phase 2's
|
|
|
|
|
verification pass, and not exempt from `pre-mr-review` just because the ticket is a
|
|
|
|
|
spike.
|
|
|
|
|
|
|
|
|
|
The `prototype` skill is a different job, not this one. It makes throwaway code for
|
|
|
|
|
settling which direction to take, parked on a branch out of main and thrown away after.
|
|
|
|
|
Reach for it when the spike's real open question is which of several directions to
|
|
|
|
|
build. Once a direction is settled, the deliverable is the two artifacts above, and both
|
|
|
|
|
ship with the ticket.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Branch setup — run this before any repo work in Phase 1 or Phase 2
|
|
|
|
|
|
|
|
|
|
Every ticket gets its own branch, prefixed with the ticket key
|
|
|
|
|
(`<KEY>-Title-Case-Hyphenated-summary`, matching this org's existing convention, e.g.
|
|
|
|
|
`KACP-22823-Fix-Invalid-Date-In-Retainer-Datagrid`). Do this unconditionally as the
|
|
|
|
|
first thing in Phase 1, before fetching or writing anything, not just in Phase 2 —
|
|
|
|
|
spikes and plans can turn into real code (prototypes, mockup components) partway
|
|
|
|
|
through, and the branch needs to already exist when that happens.
|
|
|
|
|
|
|
|
|
|
1. Determine the repo's default branch (`main` here; if genuinely unsure, check
|
|
|
|
|
`git symbolic-ref refs/remotes/origin/HEAD`).
|
|
|
|
|
2. Find candidate branches for this ticket, local and remote:
|
|
|
|
|
`git branch --list "<KEY>-*"` and `git branch -r --list "origin/<KEY>-*"`.
|
|
|
|
|
3. **No matches** — fresh ticket branch:
|
|
|
|
|
- Run `git status`. If there are uncommitted changes, stop and ask before doing
|
|
|
|
|
anything — don't risk carrying unrelated work onto a new branch.
|
|
|
|
|
- If not already on the default branch, check it out.
|
|
|
|
|
- Update it: `git pull --ff-only`. If that fails (local default branch has
|
|
|
|
|
diverged from `origin`), stop and ask rather than forcing anything.
|
|
|
|
|
- Create the new branch off the now up-to-date default branch, named from the
|
|
|
|
|
ticket title (2-6 words, Title-Case-Hyphenated, prefixed with `<KEY>-`).
|
|
|
|
|
`git checkout -b <name>`.
|
|
|
|
|
4. **Exactly one match** — this ticket already has a branch:
|
|
|
|
|
- If not already on it: check `git status` first. If there are uncommitted changes
|
|
|
|
|
that don't look like they belong to this ticket, stop and ask before switching.
|
|
|
|
|
Otherwise check it out (`git checkout <branch>`, or
|
|
|
|
|
`git checkout -t origin/<branch>` if it only exists remotely).
|
|
|
|
|
- Compare it to the default branch: `git merge-base <branch> <default>` vs
|
|
|
|
|
`git rev-parse <default>`. If they match, the branch is current off the default
|
|
|
|
|
branch — proceed normally.
|
|
|
|
|
- If the default branch has moved on since the branch's merge-base, don't silently
|
|
|
|
|
merge or rebase anything. Tell the user how many commits the branch is behind
|
|
|
|
|
(and how many commits of ticket work are already on it), then ask
|
|
|
|
|
(AskUserQuestion) what they want: merge the default branch in, rebase onto it,
|
|
|
|
|
proceed as-is, or abandon it and cut a fresh branch instead. Do whichever they
|
|
|
|
|
pick.
|
|
|
|
|
5. **More than one match** — don't guess which one is "the" branch. List them (last
|
|
|
|
|
commit date and subject each) and ask the user which to use.
|
|
|
|
|
|
|
|
|
|
Once this resolves you're on the correct branch, and Phase 1/Phase 2 work happens
|
|
|
|
|
there. `.claude/docs/` itself is gitignored in this repo, so which branch you're on
|
|
|
|
|
doesn't affect `ticket.md`/`plan.md`/`mr.md` directly — this is about making sure any
|
|
|
|
|
actual code (mockup prototypes, spike code, real implementation) lands in the right
|
|
|
|
|
place from the start.
|
|
|
|
|
|
|
|
|
|
## Phase 0 — figure out where this ticket stands
|
|
|
|
|
|
|
|
|
|
1. Validate the ticket key looks like `[A-Z]+-[0-9]+`. If not, ask the user for a
|
|
|
|
|
correct key.
|
|
|
|
|
2. Look for an existing directory for this ticket without hitting the network:
|
|
|
|
|
`find .claude/docs/epics -mindepth 2 -maxdepth 2 -type d -name "<KEY>"`
|
|
|
|
|
(this matches both `epics/<EPIC>/<KEY>` and `epics/tickets/<KEY>`).
|
|
|
|
|
3. Branch on what you find:
|
|
|
|
|
- **Nothing found** — this is a fresh ticket. Go to **Phase 1**.
|
|
|
|
|
- **Directory exists, no `plan.md`** — a previous run was interrupted before writing
|
|
|
|
|
a plan. Go to **Phase 1** and regenerate from scratch (re-fetch, overwrite
|
|
|
|
|
`ticket.md`, re-check attachments); it's idempotent and cheap.
|
|
|
|
|
- **`plan.md` exists, no `mr.md`** — ask the user (AskUserQuestion) what they want:
|
|
|
|
|
- Re-fetch the ticket and rewrite the plan from scratch (they want to start over)
|
|
|
|
|
- Proceed to implementing the existing `plan.md` as-is (they reviewed and approved it)
|
|
|
|
|
- Resume implementation (some plan steps are already checked off / some commits
|
|
|
|
|
already exist on the ticket branch — pick up from the first unchecked step)
|
|
|
|
|
- Run `pre-mr-review` now (implementation looks done, just need the audit + MR doc)
|
|
|
|
|
Route to **Phase 1** or **Phase 2** accordingly.
|
|
|
|
|
- **Both `plan.md` and `mr.md` exist** — this ticket looks finished. Tell the user
|
|
|
|
|
`mr.md` already exists at its path and ask whether they want you to refresh it
|
|
|
|
|
(e.g. they made more changes since) or leave it alone. Only re-enter Phase 2's
|
|
|
|
|
verification/pre-mr-review loop if they say the code changed since `mr.md` was
|
|
|
|
|
written. Also fetch the ticket and check whether its type's Jira fields (Phase 2
|
|
|
|
|
step 9) are actually filled; an `mr.md` from before this skill filled Jira
|
|
|
|
|
directly may mean the fields were never written, offer to fill them.
|
|
|
|
|
|
|
|
|
|
## Phase 1 — fetch, scaffold, and plan
|
|
|
|
|
|
|
|
|
|
1. Do **Branch setup** above first, unconditionally.
|
|
|
|
|
2. Run `jira-fetch-issue.sh <KEY> <tmp-path>` (a scratch path is fine here — you don't
|
|
|
|
|
yet know the final directory). Read the resulting JSON.
|
|
|
|
|
3. Determine the epic: `fields.parent.key`, if present. If absent, this ticket has no
|
|
|
|
|
epic.
|
|
|
|
|
4. Resolve the target directory:
|
|
|
|
|
- With epic: `.claude/docs/epics/<EPIC-KEY>/<KEY>/`
|
|
|
|
|
- Without epic: `.claude/docs/epics/tickets/<KEY>/`
|
|
|
|
|
Create it and its `resources/` subdirectory.
|
|
|
|
|
5. Move/copy the fetched JSON to `<target-dir>/resources/issue.raw.json` for your own
|
|
|
|
|
reference while writing `ticket.md` — this raw file is scratch, not part of the
|
|
|
|
|
deliverable; feel free to leave it (it's harmless context for later) or delete it
|
|
|
|
|
once `ticket.md` is written, your call.
|
|
|
|
|
6. If there's an epic and `.claude/docs/epics/<EPIC-KEY>/epic.md` doesn't already exist:
|
|
|
|
|
best-effort fetch the epic issue too (`jira-fetch-issue.sh <EPIC-KEY> <tmp>`) and
|
|
|
|
|
write a short `epic.md` (title + description, converted to markdown, a couple
|
|
|
|
|
paragraphs at most). If this fetch fails for any reason, skip it and continue — it's
|
|
|
|
|
context, not a blocker.
|
|
|
|
|
7. Write `resources/ticket.md` by reading the fetched issue JSON yourself:
|
|
|
|
|
- Title, type, status, priority, assignee, epic key (or "None"), and a link
|
|
|
|
|
(`<JIRA_BASE_URL>/browse/<KEY>`).
|
|
|
|
|
- Description: convert `renderedFields.description` (HTML) to clean markdown. If
|
|
|
|
|
empty, say so.
|
|
|
|
|
- Developer review instructions: the field name varies by project and isn't a fixed
|
|
|
|
|
custom field ID. Look at the `names` map in the response for any field whose name
|
|
|
|
|
matches something like "dev review instructions" / "review instructions"
|
|
|
|
|
(case-insensitive substring match), then render that field's value the same way as
|
|
|
|
|
the description. If nothing matches, write "None provided" — don't guess a field.
|
|
|
|
|
- Test cases: same approach for any field whose name matches something like
|
|
|
|
|
"test cases" / "test table" / "working feature proof" / "qa" (case-insensitive
|
|
|
|
|
substring match), e.g. KACP's "Test Cases & Working Feature Proof" field. This
|
|
|
|
|
is part of the ticket's testing section and MUST be captured into `ticket.md`
|
|
|
|
|
whenever it holds anything beyond an empty template. Often it's just the bare
|
|
|
|
|
instruction panel and empty table, note that and move on. But when it has real
|
|
|
|
|
content, that content is part of the implementation and has to be known from
|
|
|
|
|
the start: render every row verbatim as a markdown table under its own
|
|
|
|
|
`## Test cases and working feature proof` heading, keeping the ticket's own
|
|
|
|
|
column headers, and carry any prose or instructions in the field alongside the
|
|
|
|
|
table. These are the scenarios the developer must prove, so Phase 1's plan must
|
|
|
|
|
already say how each row gets proven, Phase 2's verification must actually
|
|
|
|
|
prove each row, and Phase 2 step 9 fills the proof column back into the Jira
|
|
|
|
|
field itself. If nothing matches, write "None provided".
|
|
|
|
|
- Risk mitigation: same approach for any field whose name matches something like
|
|
|
|
|
"risk mitigation" / "risk management" / "risks" (case-insensitive substring
|
|
|
|
|
match), e.g. KACP's "Risk Mitigation" field. Same rule as test cases: an empty
|
|
|
|
|
template gets noted, real content gets captured in full because it shapes the
|
|
|
|
|
implementation from the start. Render it as a markdown table under its own
|
|
|
|
|
`## Risk mitigation` heading, keeping the ticket's own column headers and
|
|
|
|
|
every row verbatim. The PM and Lead Developer write the risks and mitigation
|
|
|
|
|
strategies; implementing those strategies and proving each one is the developer's
|
|
|
|
|
job, so every row needs a real mitigation in the code and its proof filled into
|
|
|
|
|
the Jira field in Phase 2 step 9. If nothing matches, write "None provided".
|
|
|
|
|
- Developer fill-in tables, in general: any ticket table with a column the developer
|
|
|
|
|
is meant to complete (Working Feature Proof, Mitigation Proof, and the like) is
|
|
|
|
|
copied into `ticket.md` in full, with that column left showing where its answer
|
|
|
|
|
goes rather than dropped. `ticket.md` is the record of what the ticket actually
|
|
|
|
|
asks for. Never substitute your own invented test cases or risks for the ticket's,
|
|
|
|
|
in `ticket.md` or in the Jira fields. Your own additional cases are welcome, but
|
|
|
|
|
they go alongside the ticket's rows, clearly marked as additional, never in place
|
|
|
|
|
of them.
|
|
|
|
|
- Sweep for anything else populated: list every key in the `names` map whose field
|
|
|
|
|
actually has a non-null, non-empty value on this issue (jq over `.fields` joined
|
|
|
|
|
with `.names`), and skim any populated field not already captured above. Capture
|
|
|
|
|
the ones relevant to implementing or verifying the ticket; ignore workflow
|
|
|
|
|
plumbing (ranks, sprints boards, reviewer assignments, rich-field duplicates).
|
|
|
|
|
This exists because real content sometimes hides in per-project custom fields
|
|
|
|
|
with unpredictable names — a name-pattern miss must not silently drop content.
|
|
|
|
|
- Any other fields on the ticket that look clearly relevant to implementing it
|
|
|
|
|
(acceptance criteria field, story points, labels, components) are worth a short
|
|
|
|
|
line each; don't dump every custom field verbatim.
|
|
|
|
|
8. Run `jira-download-attachments.sh <issue.raw.json> <target-dir>/resources/`. For each
|
|
|
|
|
attachment with a `video/*` mime type, check whether another attachment already looks
|
|
|
|
|
like its transcript (same base filename with `.txt`/`.srt`/`.vtt`, or a filename
|
|
|
|
|
containing "transcript"). Collect any videos with no matching transcript.
|
|
|
|
|
9. If there are untranscribed videos, ask the user (AskUserQuestion, one question,
|
|
|
|
|
multiSelect if more than one video) whether to transcribe them now. For each they
|
|
|
|
|
approve, run `transcribe.sh <video-path> <target-dir>/resources/`. Note in `ticket.md`
|
|
|
|
|
under Attachments which videos have a transcript and which were skipped.
|
|
|
|
|
For every video that gets transcribed, also extract frames — ticket videos are
|
|
|
|
|
almost always screen recordings, and the transcript alone misses what was on
|
|
|
|
|
screen (the UI being pointed at, the annotation, the row that's wrong). Extract to
|
|
|
|
|
`<target-dir>/resources/<video-basename>.frames/` with scene detection plus a time
|
|
|
|
|
floor, for example:
|
|
|
|
|
`mkdir -p <frames-dir> && ffmpeg -i <video> -vf "select='gt(scene,0.1)+isnan(prev_selected_t)+gte(t-prev_selected_t\,15)'" -fps_mode vfr <frames-dir>/frame-%03d.png`
|
|
|
|
|
Tune the scene threshold or floor so a typical video yields tens of frames, not
|
|
|
|
|
hundreds (raise the floor for long recordings). Then actually look at the frames
|
|
|
|
|
with the Read tool during research, cross-referencing the transcript's timestamps,
|
|
|
|
|
and treat what's visible on screen as part of the ticket's content the same way
|
|
|
|
|
the transcript is. Skip frame extraction only when the video is confirmed
|
|
|
|
|
audio-only or the user says the visuals don't matter.
|
|
|
|
|
10. Now actually understand the ticket in the context of this codebase: read whatever
|
|
|
|
|
source files, tests, or docs are relevant to what's being asked. Use Explore/grep
|
|
|
|
|
as needed — this is normal engineering research, not scripted. Use the
|
|
|
|
|
**Verification tools available** above to check the ticket's own claims against
|
|
|
|
|
reality (codebase, Jira, staging, and prod/CI env with permission) rather than
|
|
|
|
|
taking the ticket's description at face value — this is what makes the plan
|
|
|
|
|
trustworthy instead of just plausible-sounding.
|
|
|
|
|
11. Write `plan.md` in `<target-dir>/plan.md` (a sibling of `resources/`, not inside
|
|
|
|
|
it). Structure:
|
|
|
|
|
```
|
|
|
|
|
# Plan: <KEY> — <short title>
|
|
|
|
|
|
|
|
|
|
## Acceptance criteria
|
|
|
|
|
- [ ] <criterion from the ticket, restated precisely>
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
## Open questions
|
|
|
|
|
<Anything genuinely blocking or ambiguous that needs the user's answer before or
|
|
|
|
|
during implementation. "None" if there really aren't any — don't manufacture
|
|
|
|
|
questions to look thorough.>
|
|
|
|
|
|
|
|
|
|
## Approach
|
|
|
|
|
<Narrative: what you're going to do and why, which files/modules/functions are
|
|
|
|
|
involved, how it fits the existing patterns in this codebase.>
|
|
|
|
|
|
|
|
|
|
## Steps
|
|
|
|
|
- [ ] <step 1, roughly one commit's worth of work — mark it `(deliverable)` if it
|
|
|
|
|
produces a document via the Deliverable documents process instead of code, or
|
|
|
|
|
`(mock)` if it's a real schema/UI change built to demonstrate a mock rather than
|
|
|
|
|
ship a finished feature, see Mocks and datamodel changes>
|
|
|
|
|
- [ ] <step 2>
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
## Risks and edge cases considered
|
|
|
|
|
- <edge case> — <how the plan handles it>
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
## Test plan
|
|
|
|
|
- <how you'll verify each acceptance criterion, including existing test suites to
|
|
|
|
|
run and any new tests to add>
|
|
|
|
|
```
|
|
|
|
|
Be thorough: address every acceptance criterion, resolve as many open questions as
|
|
|
|
|
you reasonably can by reading the code first, and don't leave logic gaps. Steps
|
|
|
|
|
should be concrete enough that Phase 2 can execute them without re-deriving the
|
|
|
|
|
approach. The Test plan must name every test case `ticket.md` captured and say how
|
|
|
|
|
that exact case gets proven, and the Risks section must name every risk
|
|
|
|
|
`ticket.md` captured and say which code enforces its mitigation. Read the notes
|
|
|
|
|
column of a ticket test case as part of the case, not as commentary: a note like
|
|
|
|
|
"confirm the certificate matches the emailed version" is its own thing to prove.
|
|
|
|
|
|
|
|
|
|
**Wide refactors are the exception to one-commit steps.** A wide refactor is a single
|
|
|
|
|
mechanical change whose blast radius fans across the codebase (renaming a column,
|
|
|
|
|
retyping a shared symbol), so one edit breaks thousands of call sites at once and no
|
|
|
|
|
single step can land green. Don't force it into one. Sequence it as expand, then
|
|
|
|
|
migrate, then contract: first add the new form beside the old so nothing breaks, then
|
|
|
|
|
migrate the call sites in batches sized by blast radius (per package, per directory)
|
|
|
|
|
with each batch its own step, then delete the old form once no caller remains. Every
|
|
|
|
|
step stays green because the old form still exists until the last one. Say in the
|
|
|
|
|
Approach that this is what you're doing and why, since the step count looks inflated
|
|
|
|
|
otherwise.
|
|
|
|
|
12. Stop here. Tell the user `plan.md` is ready at its path, summarize the approach in
|
|
|
|
|
a couple of sentences, and mention any open questions that need their input before
|
|
|
|
|
you'd implement it. Do not start implementing in this same run — wait for them to
|
|
|
|
|
review the plan (editing it directly if they want) and invoke `/ticket <KEY>` again.
|
|
|
|
|
|
|
|
|
|
## Phase 2 — implement, verify, and hand off
|
|
|
|
|
|
|
|
|
|
Entered only when the user has confirmed (per Phase 0) that the plan is approved.
|
|
|
|
|
|
|
|
|
|
1. Do **Branch setup** above first, unconditionally — even if Phase 1 already did this
|
|
|
|
|
for the same ticket earlier, confirm you're still actually on that branch now (the
|
|
|
|
|
user may have switched branches between runs).
|
|
|
|
|
2. Read `plan.md` fresh — the user may have hand-edited it.
|
|
|
|
|
3. Work through `plan.md`'s Steps checklist in order. For each step: implement it (a
|
|
|
|
|
step marked `(deliverable)` follows the **Deliverable documents** process above
|
|
|
|
|
instead of writing code; a step marked `(mock)` follows **Mocks and datamodel
|
|
|
|
|
changes** — real schema/UI work, not a static wireframe), then check it off
|
|
|
|
|
(`- [x]`) in `plan.md`, then make one commit for it (or a few, if the step
|
|
|
|
|
naturally splits into independent units). Commit messages are short and imperative,
|
|
|
|
|
describing what changed, following House style above.
|
|
|
|
|
|
|
|
|
|
If a step fails in a way `plan.md` didn't predict, and the cause isn't obvious within
|
|
|
|
|
a couple of minutes, call the Skill tool with "diagnosing-bugs" rather than trying
|
|
|
|
|
fixes to see what sticks. Note anything it turns up that changes the plan.
|
|
|
|
|
4. Do not run the full verification suite after every commit (checks-at-the-end mode).
|
|
|
|
|
Once every step is implemented and checked off, find and run this project's standard
|
|
|
|
|
verification (check `package.json` scripts for something like `ci:check`,
|
|
|
|
|
`typecheck`, `lint`, `test`, or fall back to whatever the repo's README documents).
|
|
|
|
|
Fix anything broken, committing fixes as their own commits, until it's clean. If you
|
|
|
|
|
can't find any verification command at all, say so explicitly later in `mr.md`
|
|
|
|
|
rather than claiming a build/lint/test pass that never happened. Beyond the standard
|
|
|
|
|
suite, use the **Verification tools available** above for anything the suite
|
|
|
|
|
wouldn't actually catch, e.g. confirming behavior against real staging data via
|
|
|
|
|
Infisical, or a specific prod/CI config question, when that's genuinely what it
|
|
|
|
|
takes to be confident the change works as intended rather than just "looks right."
|
|
|
|
|
5. Get an independent code review, from a FRESH agent, before running `pre-mr-review`.
|
|
|
|
|
|
|
|
|
|
This step exists because `pre-mr-review` cannot do it. That skill is constitutionally
|
|
|
|
|
read-only: it may not run tests, execute code, probe a database, or run any
|
|
|
|
|
experiment, and its own rules tell it to mark anything unprovable as "Needs
|
|
|
|
|
verification" rather than proving it. So it cannot catch a claim that is plausible on
|
|
|
|
|
the page and false in reality. A reviewer that can actually run things can. It has
|
|
|
|
|
already caught a mitigation that was proven by construction to be wrong, on a branch
|
|
|
|
|
whose own audit had blessed it.
|
|
|
|
|
|
|
|
|
|
Order matters and is not just convenience. `pre-mr-review`'s output is a readiness
|
|
|
|
|
verdict that gets pasted verbatim into `mr.md`. Anything that runs after it
|
|
|
|
|
invalidates that verdict by construction, and you end up rerunning it and rewriting
|
|
|
|
|
the handoff. Review first, fix, commit, and only then run `pre-mr-review` over the
|
|
|
|
|
final tree.
|
|
|
|
|
|
|
|
|
|
- **Skip this step for genuinely trivial changes**: a copy tweak, a styling fix, a
|
|
|
|
|
one line correction with no logic in it. Run it whenever the change adds or
|
|
|
|
|
modifies a procedure, touches schema or migrations, touches permissions or
|
|
|
|
|
auth, involves concurrency, or has a risk table in its ticket. When unsure, run it.
|
|
|
|
|
- **Always dispatch a NEW agent.** Never reuse an agent from earlier in this ticket
|
|
|
|
|
and never review your own work in your own context. The value here is entirely in
|
|
|
|
|
the reviewer not being the author, so an agent that helped implement or plan the
|
|
|
|
|
change cannot provide it.
|
|
|
|
|
- **Give the reviewer its reading order explicitly**, or it produces noise about
|
|
|
|
|
conventions the project already settled: the epic summary if there is one
|
|
|
|
|
(`.claude/docs/epics/<EPIC-KEY>/summary.md`), then this ticket's `resources/` and
|
|
|
|
|
`plan.md`, then `AGENTS.md`, and only then the diff. Give it the exact commit range.
|
|
|
|
|
- **Tell it to verify rather than suspect**, to try to refute its own findings before
|
|
|
|
|
reporting them, to mark each finding CONFIRMED or PLAUSIBLE, and to give exact
|
|
|
|
|
`file:line` plus a concrete failure scenario. Tell it explicitly not to write,
|
|
|
|
|
commit, push, or run anything destructive.
|
|
|
|
|
- **Point it at the claims already made.** Every "proven by X" already written into
|
|
|
|
|
the ticket's risk or test tables must be re-derived, not taken on trust. A false
|
|
|
|
|
proof claim in Jira is worse than an unproven one, because it stops anyone else
|
|
|
|
|
from checking.
|
|
|
|
|
- **Ask the spec questions explicitly**, or the review only finds bugs in what you
|
|
|
|
|
did write and never notices what you didn't. Three questions, each answered against
|
|
|
|
|
`ticket.md` and `plan.md` rather than the diff alone: what the ticket asked for that
|
|
|
|
|
is missing or only partly done; what behavior is in the diff that nothing asked for;
|
|
|
|
|
and what looks implemented but is implemented wrongly. Have it quote the AC ID or
|
|
|
|
|
the `plan.md` line each finding traces to.
|
|
|
|
|
|
|
|
|
|
Then respond to the review, in writing:
|
|
|
|
|
|
|
|
|
|
- **Findings are not automatically true.** Verify each one against the codebase
|
|
|
|
|
before acting on it. Reviewers do produce confident wrong answers. Say plainly
|
|
|
|
|
which findings you rejected and why, rather than quietly accepting all of them.
|
|
|
|
|
- **Fix everything real**, each meaningful fix as its own commit. Do not defer a
|
|
|
|
|
known hole to a follow-up ticket unless the user decides that.
|
|
|
|
|
- **When a fix changes a mechanism rather than a line**, write a test that fails
|
|
|
|
|
against the old behavior and passes against the new one, and actually confirm it
|
|
|
|
|
fails by reverting the fix. A test that passes either way proves nothing.
|
|
|
|
|
- **If a finding invalidates something already written into Jira or a deliverable,
|
|
|
|
|
correct it there too.** The code being fixed does not fix the false claim.
|
|
|
|
|
- **Terminate deliberately.** Run the reviewer ONCE on the branch. `pre-mr-review`
|
|
|
|
|
then reviews the whole diff including your fixes and serves as the second pass.
|
|
|
|
|
Only dispatch a second reviewer if a fix changed a mechanism, not for line level
|
|
|
|
|
fixes, and never loop "review until clean."
|
|
|
|
|
|
|
|
|
|
6. Confirm this project actually has a `pre-mr-review` skill (`.claude/skills/pre-mr-review/`
|
|
|
|
|
in the current repo). If it doesn't, stop here, tell the user implementation and
|
|
|
|
|
local verification are done but this repo has no `pre-mr-review` skill to run, and
|
|
|
|
|
let them decide how to proceed.
|
|
|
|
|
7. Invoke the `pre-mr-review` skill. Read its verdict.
|
|
|
|
|
- **Ready to Open MR**: continue to step 8.
|
|
|
|
|
- **Almost Ready / Not Ready Yet**: fix what it flagged (each meaningful fix as its
|
|
|
|
|
own commit), then invoke `pre-mr-review` again. Repeat until the verdict is Ready
|
|
|
|
|
to Open MR. Don't write `mr.md` before that verdict is reached.
|
|
|
|
|
8. Read `~/.agents/skills/ticket/templates/mr.md` — this is the org's MR template,
|
|
|
|
|
copied into this skill so it still works even though the original
|
|
|
|
|
`.claude/docs/mr/template.md` no longer exists in the command-center repo. `mr.md`
|
|
|
|
|
is ONLY the MR description: the filled template plus the pasted pre-MR handoff.
|
|
|
|
|
Jira ticket fields are not written here, they go straight into Jira in step 9.
|
|
|
|
|
Fill it in for real:
|
|
|
|
|
- H1: from the ticket and the actual work done, not the ticket title verbatim if the
|
|
|
|
|
real change ended up narrower/broader.
|
|
|
|
|
- Summary: one short paragraph max. High level only, what changed, not how. This
|
|
|
|
|
is not the place for a list of every file touched.
|
|
|
|
|
- Issue Link: `<JIRA_BASE_URL>/browse/<KEY>`.
|
|
|
|
|
- New ENVs: list any env vars actually introduced; "None" if none.
|
|
|
|
|
- Additional Notes: a bulleted checklist of the changes you actually made, not a
|
|
|
|
|
dumping ground. Between Summary and this section, every acceptance criterion from
|
|
|
|
|
`plan.md` (or, for a bug ticket, the bug itself) needs to be directly addressed,
|
|
|
|
|
not just gestured at. If there's genuinely unrelated work worth mentioning (e.g.
|
|
|
|
|
an incidental fix along the way), it goes after everything ticket-relevant, still
|
|
|
|
|
as short bullets. Five bullet points max total, ticket-relevant and incidental
|
|
|
|
|
combined. If it doesn't fit in five, it's too much detail for this section, trim
|
|
|
|
|
it rather than running long.
|
|
|
|
|
- Checklist: check only boxes you actually verified (e.g. only check "Build
|
|
|
|
|
verified" if you actually ran a build and it passed).
|
|
|
|
|
- Replace `<!-- Paste the Pre-MR handoff here -->` with the exact content of the
|
|
|
|
|
latest `pre-mr-review` handoff file (the one with verdict Ready to Open MR) —
|
|
|
|
|
paste it verbatim, don't summarize it.
|
|
|
|
|
|
|
|
|
|
The handoff section of `mr.md` is GENERATED OUTPUT, not something you author.
|
|
|
|
|
It is the block that states whether the branch is ready to merge, so it must be
|
|
|
|
|
the audit's own words, not a retelling of them. Concretely:
|
|
|
|
|
|
|
|
|
|
- Never hand-write a handoff section, and never edit one in place. If it is
|
|
|
|
|
wrong, thin, or stale, fix the handoff file by rerunning `/pre-mr-review`,
|
|
|
|
|
then re-paste.
|
|
|
|
|
- On EVERY rerun, replace the whole existing handoff block with the whole
|
|
|
|
|
regenerated one. Do not patch the copy sitting in `mr.md` to match the new
|
|
|
|
|
head — that is how the two silently diverge, and the version the reviewer
|
|
|
|
|
reads stops being the version the audit actually produced.
|
|
|
|
|
- After pasting, verify the tail of `mr.md` is byte-identical to the handoff
|
|
|
|
|
file. If it isn't, you edited it.
|
|
|
|
|
- The handoff file itself must follow `templates/handoff.md` in the repo's
|
|
|
|
|
`pre-mr-review` skill. If real content doesn't fit that structure, the fix is
|
|
|
|
|
to write it into the handoff file under the right heading, not to bolt an
|
|
|
|
|
extra section onto `mr.md`.
|
|
|
|
|
- Developer responsibilities: if the ticket's dev review instructions impose their
|
|
|
|
|
own deliverables on the developer (e.g. KACP's standing "document three to five
|
|
|
|
|
additional edge cases discovered during implementation, each with its handling
|
|
|
|
|
and test, or its deferral and follow-up story"), satisfy them EXPLICITLY, under a
|
|
|
|
|
heading that uses the requirement's own words, in the JIRA FIELD that owns them —
|
|
|
|
|
not in `mr.md`. In command-center that is the engineer-facing patch notes field
|
|
|
|
|
(`customfield_10260`, "For The Engineer: Patch Notes"). Step 9 writes it.
|
|
|
|
|
Scattered coverage across notes does not count as having answered a named
|
|
|
|
|
requirement, and neither does burying it in the MR description.
|
|
|
|
|
Save this as `<target-dir>/mr.md` (next to `plan.md`, not under `resources/`).
|
|
|
|
|
|
|
|
|
|
**`mr.md` is the template plus the pasted handoff, and NOTHING ELSE.** This is a
|
|
|
|
|
hard shape, not a starting point. Its only headings are the template's own numbered
|
|
|
|
|
sections and the handoff's. Do not add narrative sections, however well justified
|
|
|
|
|
they feel: no "how I built it", no per-ticket deep dives, no edge-case writeups, no
|
|
|
|
|
"Jira Ticket Fields" section, no test tables, no root cause analysis. Those live in
|
|
|
|
|
Jira and step 9 puts them there.
|
|
|
|
|
|
|
|
|
|
Anything you are tempted to add as a section belongs in **Additional Notes**, as one
|
|
|
|
|
tight bullet. If it will not compress to a bullet, it is Jira content, not MR
|
|
|
|
|
content. A reviewer should be able to read the whole file in about a minute; if it
|
|
|
|
|
has grown past roughly 120 lines including the handoff, it has drifted.
|
|
|
|
|
9. Fill the Jira ticket fields directly, by issue type. Rich text fields are ADF:
|
|
|
|
|
render markdown with `python3 ~/.agents/skills/review-ticket/scripts/review2adf.py
|
|
|
|
|
render <file.md>` and PUT via `{"fields": {...}}` to `/rest/api/3/issue/<KEY>`.
|
|
|
|
|
After every PUT, re-fetch and verify the field landed (compare extracted text,
|
|
|
|
|
treating empty `attrs` objects and `localId`/`colwidth`/`width` as noise). The
|
|
|
|
|
field-to-type map below is verified against the project's edit screens, don't PUT
|
|
|
|
|
a field to a type that doesn't carry it.
|
|
|
|
|
|
|
|
|
|
**Proof first.** Before filling any proof column, capture working feature proof
|
|
|
|
|
yourself wherever possible: run the app (`run` skill) and screenshot the real
|
|
|
|
|
feature with browser automation, or capture test output for behavior with no UI.
|
|
|
|
|
Save artifacts under `<target-dir>/proof/` with names that match the test-case
|
|
|
|
|
rows they prove. A proof cell references its artifact by filename plus "attached"
|
|
|
|
|
(Gib uploads every attachment, this skill NEVER uploads files to Jira) or names
|
|
|
|
|
the passing test. When proof genuinely can't be captured here (needs prod, a real
|
|
|
|
|
inbox, a flag flip), the cell says exactly what's needed and step 10 lists it for
|
|
|
|
|
Gib. A row with no proof and no named gap is missing work, not a documentation
|
|
|
|
|
gap: go run the check first.
|
|
|
|
|
|
|
|
|
|
**Cap the proof at five files, and aim for two or three.** Gib uploads every
|
|
|
|
|
attachment by hand, so each file has a real cost and a wall of near-duplicate
|
|
|
|
|
screenshots buries the two that matter. Before filling the proof column, pick the
|
|
|
|
|
smallest set that actually carries the evidence and delete the rest from `proof/`.
|
|
|
|
|
|
|
|
|
|
- One screenshot can prove several rows at once. A company page that shows the
|
|
|
|
|
navigation, the tabs, and the absent section proves three criteria in one image,
|
|
|
|
|
so prefer it over three separate captures.
|
|
|
|
|
- Prefer text over images wherever the evidence is textual. Command output, a
|
|
|
|
|
config diff, a grep result, or a list of rendered labels all belong in a single
|
|
|
|
|
`.txt` file, which is cheaper to attach and easier to read than a screenshot of
|
|
|
|
|
the same thing. Fold what a dropped screenshot proved into that file rather than
|
|
|
|
|
losing the evidence.
|
|
|
|
|
- Capture as many as you like while working. The cap applies to what survives in
|
|
|
|
|
`proof/` when you fill the Jira fields, not to what you take along the way.
|
|
|
|
|
- Never reference a file in a proof cell that is not in `proof/`, and never leave a
|
|
|
|
|
file in `proof/` that no proof cell references. The two lists match exactly.
|
|
|
|
|
|
|
|
|
|
**Bug** (fields on the Bug edit screen):
|
|
|
|
|
- `customfield_10259` For the Engineer: Root Cause Analysis: the actual diagnosed
|
|
|
|
|
cause as a short narrative naming the real files and mechanism, not the ticket's
|
|
|
|
|
theory.
|
|
|
|
|
- `customfield_10263` Precipitating Event: what introduced or exposed the bug and
|
|
|
|
|
when (the commit, upgrade, or change that made it start happening).
|
|
|
|
|
- `customfield_10260` For The Engineer: Patch Notes: changelog-style statement of
|
|
|
|
|
the fix.
|
|
|
|
|
- `customfield_10142` Working Feature Proof: the test-case table (Summary, Steps,
|
|
|
|
|
Expected Results, Working Feature Proof, Notes) with the real scenarios verified
|
|
|
|
|
and the proof column filled.
|
|
|
|
|
|
|
|
|
|
**Story** (fields on the Story edit screen):
|
|
|
|
|
- `customfield_10253` Test Cases & Working Feature Proof: ALWAYS fetch and read
|
|
|
|
|
this field, whoever wrote the dev review, and no matter what state it's in.
|
|
|
|
|
Whatever rows it carries are the scenarios to prove: fill the empty Working
|
|
|
|
|
Feature Proof cells of the existing rows in place, never duplicate rows. If the
|
|
|
|
|
field is still a bare template with no rows, add the real scenarios verified as
|
|
|
|
|
new rows. New rows go through `review2adf.py tables <field.json> <rows.md>`,
|
|
|
|
|
which preserves the instruction panels and headers.
|
|
|
|
|
- `customfield_10129` Risk Mitigation: same in-place treatment for the Mitigation
|
|
|
|
|
Proof column.
|
|
|
|
|
- `customfield_10260` Engineer Patch Notes: changelog-style, what changed. This is
|
|
|
|
|
also where the dev review instructions' own developer deliverables go, under a
|
|
|
|
|
heading in the requirement's own words. For KACP that is the standing "three to
|
|
|
|
|
five additional edge cases discovered during implementation", each with how it was
|
|
|
|
|
handled and what covers it. Deliver the number asked for, not more, and pick the
|
|
|
|
|
ones a reviewer most benefits from. This field, not `mr.md`.
|
|
|
|
|
- `customfield_10261` User Story Patch Notes: the same change in user-facing words.
|
|
|
|
|
- `customfield_10142` Working Feature Proof: ALWAYS fill this on a Story, never
|
|
|
|
|
leave it empty. It renders as its own panel in the ticket's testing section, so
|
|
|
|
|
an empty field reads as unfilled testing even when every test-table cell is
|
|
|
|
|
complete (this happened on KACP-23143). At minimum it lists the files staged in
|
|
|
|
|
`proof/` for Gib to attach, one line each saying what the artifact shows, plus a
|
|
|
|
|
pointer that per-row proof lives in the Test Cases table. A headline artifact (a
|
|
|
|
|
demo capture, a before/after pair) leads the list when one exists.
|
|
|
|
|
|
|
|
|
|
**Spike** (deliverables, not code): no test or proof fields to fill. The output is
|
|
|
|
|
the deliverables directory, and step 10 tells Gib which files to upload where (the
|
|
|
|
|
ticket, Drive, or both, per the ticket's instructions). Fill `customfield_10260`
|
|
|
|
|
only if the spike actually shipped code.
|
|
|
|
|
|
|
|
|
|
Before moving on, re-read `ticket.md` row by row: every test case and every risk
|
|
|
|
|
the ticket carries now has its developer column filled in Jira. Leave none
|
|
|
|
|
unanswered.
|
|
|
|
|
10. Tell the user: implementation is committed on `<branch>`, `pre-mr-review` verdict is
|
|
|
|
|
Ready to Open MR, the Jira fields are filled (name which), and `mr.md` is ready at
|
|
|
|
|
its path. Then the manual list, which should only ever be:
|
|
|
|
|
- push the branch, open the MR, and paste `mr.md` in as the description
|
|
|
|
|
- upload the named proof or deliverable files (from `proof/` or `deliverables/`)
|
|
|
|
|
to the ticket, plus anything flagged as proof only Gib can capture
|
|
|
|
|
Remind them nothing was pushed, no MR was opened, and no attachments were uploaded.
|
|
|
|
|
|
|
|
|
|
## Resuming mid-implementation
|
|
|
|
|
|
|
|
|
|
If Phase 0 routes here because some steps in `plan.md` are already checked off: check
|
|
|
|
|
`git log` on the current branch against the plan's steps to sanity-check they actually
|
|
|
|
|
match reality (a checked-off step should have a corresponding commit), then continue
|
|
|
|
|
from the first unchecked step. If the plan and the git history disagree, stop and ask
|
|
|
|
|
the user rather than guessing which one is right.
|