Drive the ticket skill through the live ticket page
This commit is contained in:
+156
-230
@@ -1,14 +1,14 @@
|
||||
---
|
||||
name: ticket
|
||||
description: End-to-end Jira ticket workflow — fetch a ticket into .claude/docs/epics/, write a plan and its plan.html review page, implement it with clean commits, drive the pre-mr-review audit to convergence (the user runs it themselves from their work Claude account), 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.
|
||||
description: End-to-end Jira ticket workflow — fetch a ticket into a live ticket page under .claude/docs/epics/, plan it, implement it with clean commits, drive the pre-mr-review audit to convergence (the user runs it themselves from their work Claude account), 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
|
||||
Turns a Jira ticket key into: a live ticket page carrying the ticket, a reviewed plan,
|
||||
progress, and proof, 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
|
||||
@@ -19,38 +19,48 @@ Jira story, the estimate, risk level, and testing tables, as part of authoring a
|
||||
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.
|
||||
|
||||
## The ticket page
|
||||
|
||||
Every ticket gets a **ticket page**, a web page Gib keeps open while you work: the ticket as
|
||||
Jira has it, the plan with its mocks, live progress, proof beside the mocks, and the review.
|
||||
Every epic gets an **epic index** listing its stories in build order. Both render from data
|
||||
files that only `ticket-page` writes, and both update themselves as it writes.
|
||||
|
||||
**Read [SITE.md](SITE.md) before the first write of every run.** It holds the command for each
|
||||
moment the phases below name, the plan's JSON shape, how to draw mocks, and how the epic order
|
||||
is seeded. Record each moment when it happens, not in a batch at the end, because Gib is
|
||||
watching the page change.
|
||||
|
||||
## Directory layout this skill maintains
|
||||
|
||||
```
|
||||
.claude/docs/epics/
|
||||
_site/ # the shared renderer, refreshed by ticket-page
|
||||
<EPIC-KEY>/
|
||||
epic.md # brief epic context, written once, best-effort
|
||||
index.html, epic.data.js # the epic index
|
||||
<TICKET-KEY>/
|
||||
index.html, ticket.data.js # the ticket page
|
||||
resources/
|
||||
ticket.md # title, description, dev review instructions
|
||||
issue.raw.json # the fetched issue, kept for re-imports
|
||||
<attachments...> # images, videos, other files as downloaded
|
||||
<video>.transcript.txt # only for videos that got transcribed
|
||||
<video>.transcript.srt
|
||||
plan.md
|
||||
plan.html # the plan as a page, with mocks when a step changes what a user sees
|
||||
deliverables/ # only for tickets whose output is documents, not code
|
||||
<video>.frames/
|
||||
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
|
||||
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
|
||||
plan.html
|
||||
deliverables/...
|
||||
mr.md
|
||||
<TICKET-KEY>/ # same shape, for tickets with no epic, and no index
|
||||
```
|
||||
|
||||
## Scripts this skill uses
|
||||
|
||||
- `~/.agents/skills/ticket/scripts/ticket-page <command> <KEY> ...` — the only writer of the
|
||||
ticket page and epic index. See [SITE.md](SITE.md), or `ticket-page help`. Runs under bun.
|
||||
- `~/.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`.
|
||||
@@ -101,8 +111,8 @@ 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.
|
||||
- No em dashes, en dashes, semicolons, or arrow glyphs in commit messages, the ticket page,
|
||||
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
|
||||
@@ -161,19 +171,18 @@ the document.** Being aligned first is the point, and the writing should read as
|
||||
you always were.
|
||||
|
||||
This governs `mr.md`, `customfield_10260` and `10261`, every other Jira field, and PM
|
||||
deliverables. It does not govern files only he reads. `plan.md`, `bugs.md`, audits and
|
||||
deliverables. It does not govern files only he reads. The ticket page, `bugs.md`, audits and
|
||||
working notes can name him and record who decided what, because that history is useful.
|
||||
|
||||
The House style punctuation rule above is the stricter one where the two overlap. Keep
|
||||
it. Personal working files (`plan.md`, `plan.html`, `ticket.md`) are exempt, nobody else
|
||||
reads them.
|
||||
it. The ticket page is a personal working file and exempt, nobody else reads it.
|
||||
|
||||
## 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
|
||||
in question, before writing the plan (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
|
||||
@@ -199,7 +208,7 @@ implementation makes a claim that's checkable:
|
||||
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
|
||||
reach), say so explicitly in the plan's open questions instead of silently skipping
|
||||
the check.
|
||||
|
||||
**How to write what you found, in a deliverable.** State it as a plain confirmed
|
||||
@@ -213,7 +222,7 @@ codebase equally.
|
||||
|
||||
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
|
||||
a plan 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
|
||||
@@ -228,11 +237,10 @@ subfolder under `<target-dir>/deliverables/<deliverable-slug>/` with three files
|
||||
- `<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
|
||||
engineer who has never seen `.claude/docs/` or the ticket page, 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 point the reader at the ticket page or the
|
||||
plan, 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.
|
||||
|
||||
@@ -318,7 +326,7 @@ describe it only as a quick UI mockup.
|
||||
|
||||
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`.
|
||||
Build it for real, on the ticket's branch. Give these steps `"kind": "mock"` in the plan.
|
||||
|
||||
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
|
||||
@@ -351,7 +359,7 @@ what was quick to wire up. Ship both, and don't let either stand in for the othe
|
||||
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
|
||||
than a static mock would, say so in the plan's approach 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
|
||||
@@ -372,41 +380,6 @@ Reach for it when the spike's real open question is which of several directions
|
||||
build. Once a direction is settled, the deliverable is the two artifacts above, and both
|
||||
ship with the ticket.
|
||||
|
||||
## The plan page (`plan.html`)
|
||||
|
||||
`plan.md` is the plan. `plan.html` is the same plan as a page, saved beside it, so Gib
|
||||
reads the plan in a browser before approving it instead of scrolling a markdown file. It
|
||||
opens from `file://`, ticks acceptance criteria and steps as he reviews them, and shows
|
||||
the mocks in place. It is the review artifact, and it exists to be opened.
|
||||
|
||||
- **Fill the template.** Copy `~/.agents/skills/ticket/templates/plan.html` to
|
||||
`<target-dir>/plan.html` and fill every slot its header comment lists, in the order
|
||||
`plan.md` carries them: the same criteria, the same open questions, the same Approach,
|
||||
the same steps with the same `(mock)` and `(deliverable)` marks as badges, the same
|
||||
risks, the same test plan. Fill the slots only. The CSS and script ship as they are, so
|
||||
every plan page looks and behaves the same. Done when a reader of either file learns
|
||||
nothing the other omits.
|
||||
- **Mocks, when a step changes what a user sees.** A new screen, a changed layout, a new
|
||||
control, or copy a user reads means the page keeps its Mocks section: one artboard per
|
||||
screen state the plan introduces, drawn in plain HTML and CSS inside its own
|
||||
`<template>`, with the app's real navigation and density around it rather than a
|
||||
wireframe of boxes. When the direction is Gib's call, draw each candidate as its own
|
||||
artboard (Option A, Option B) and name the choice in Open questions, pointing at the
|
||||
artboards. When the direction is settled, one artboard per screen. Each artboard's
|
||||
`data-note` states what it shows that the implementation will not do. This is how the
|
||||
house rule about several static mocks before touching real components is satisfied
|
||||
inside the ticket flow, so no separate mock server is needed. When no step changes
|
||||
what a user sees, delete the Mocks section and its nav link.
|
||||
- **Open it.** After saving, run `xdg-open <target-dir>/plan.html` so it lands in the
|
||||
browser, and give both paths in the Phase 1 wrap-up.
|
||||
- **`plan.md` stays the source of truth.** When Phase 0 routes to rewriting the plan,
|
||||
rewrite `plan.html` with it. Phase 2 checks steps off in `plan.md` only. The page is a
|
||||
snapshot for the review and is left alone once the plan is approved.
|
||||
- **Relation to spike mocks.** The plan page's artboards are design intent drawn before
|
||||
any code exists. A deliverable's polished `mocks/` (see Mocks and datamodel changes)
|
||||
can start from the approved artboard, and the built screens are still screenshotted
|
||||
for real.
|
||||
|
||||
---
|
||||
|
||||
## Branch setup — run this before any repo work in Phase 1 or Phase 2
|
||||
@@ -450,7 +423,7 @@ through, and the branch needs to already exist when that happens.
|
||||
|
||||
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
|
||||
doesn't affect the ticket page or `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.
|
||||
|
||||
@@ -460,21 +433,23 @@ place from the start.
|
||||
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>`).
|
||||
(this matches both `epics/<EPIC>/<KEY>` and `epics/tickets/<KEY>`). If it holds a
|
||||
`plan.md` but no `ticket.data.js`, it predates the ticket page: convert it first, as
|
||||
[SITE.md](SITE.md) describes under **Tickets from before the page**, then continue.
|
||||
`ticket-page show <KEY>` says where the ticket stands.
|
||||
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 (`plan.md` and `plan.html`) 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)
|
||||
- **A page with no plan** — a previous run was interrupted before writing a plan. Go
|
||||
to **Phase 1** and regenerate from scratch (re-fetch, re-import, re-check
|
||||
attachments); it's idempotent and cheap.
|
||||
- **A plan, 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 as-is (they reviewed and approved it)
|
||||
- Resume implementation (some steps are already done on the page / some commits
|
||||
already exist on the ticket branch — pick up from the first open step)
|
||||
- Move to the pre-mr-review stage (implementation looks done, just need the audit + MR doc; the user runs the audit from their work account, see Phase 2 step 7)
|
||||
Route to **Phase 1** or **Phase 2** accordingly.
|
||||
- **Both `plan.md` and `mr.md` exist** — this ticket looks finished. Tell the user
|
||||
- **A plan and `mr.md`** — 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
|
||||
@@ -485,83 +460,39 @@ place from the start.
|
||||
## 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
|
||||
2. Run `jira-fetch-issue.sh <KEY> <tmp-path>` (a scratch path is fine here — the next
|
||||
step knows the final directory). Read the resulting JSON.
|
||||
3. Import it: `ticket-page init <KEY> --issue <tmp-path>`. This files the ticket under its
|
||||
epic (or `tickets/` without one), imports every rich-text field verbatim as sanitized
|
||||
HTML, writes the page, and prints the ticket folder. Copy the fetched JSON to
|
||||
`<target-dir>/resources/issue.raw.json`, which later re-imports and the attachment
|
||||
script read. Record the branch from **Branch setup** with `ticket-page meta`, then open
|
||||
the page with `ticket-page open <KEY>` so Gib can follow from here on.
|
||||
4. `init` ends by listing populated Jira fields the page does not show. Read each one and
|
||||
add any that bear on implementing or verifying the ticket as a note. This sweep exists
|
||||
because real content sometimes hides in per-project custom fields with unpredictable
|
||||
names, and a name-pattern miss must not silently drop it.
|
||||
5. Read what the Ticket tab now holds, and treat its tables as the ticket's contract.
|
||||
- **Test cases** (KACP's "Test Cases & Working Feature Proof") and **risk mitigation**
|
||||
are imported with every row verbatim. Often a field is just the bare instruction
|
||||
panel and an empty table, which needs no further thought. When it has real rows,
|
||||
those are the scenarios the developer must prove and the mitigations the developer
|
||||
must implement: the plan names each one (`"fromTicket": true`), Phase 2 proves each
|
||||
one, and Phase 2 step 9 fills its proof column back into the Jira field. The PM and
|
||||
Lead write the risks. Implementing and proving each is the developer's job.
|
||||
- Never substitute your own invented test cases or risks for the ticket's, in the plan
|
||||
or in the Jira fields. Your own additional cases are welcome alongside the ticket's
|
||||
rows, never in place of them.
|
||||
6. If the ticket has an epic, seed or refresh its epic index as [SITE.md](SITE.md)
|
||||
describes under **The epic index**. This is best-effort context: if the epic search
|
||||
fails, say so and continue.
|
||||
7. 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,
|
||||
8. 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.
|
||||
approve, run `transcribe.sh <video-path> <target-dir>/resources/`.
|
||||
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
|
||||
@@ -574,6 +505,10 @@ place from the start.
|
||||
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.
|
||||
9. Run `ticket-page scan <KEY>` so the page carries the attachments, each video with its
|
||||
transcript and frames. When a video, spreadsheet, or linked document holds the
|
||||
ticket's real requirements, write what it says as a note (`ticket-page note`), the
|
||||
way "What the video says" summarizes a recording point by point.
|
||||
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
|
||||
@@ -588,54 +523,33 @@ place from the start.
|
||||
**architectural** is a new subsystem, a schema change other stories depend on, or
|
||||
anything that alters an interface neighbouring work relies on. Bounded is the common
|
||||
case and goes straight to step 11. For architectural, call the Skill tool with
|
||||
"grilling" and resolve its frontier with Gib BEFORE writing `plan.md` — those
|
||||
"grilling" and resolve its frontier with Gib BEFORE writing the plan — those
|
||||
questions get answered in conversation, not deferred into the plan's Open questions
|
||||
section, because an architectural plan built on a wrong assumption is the expensive
|
||||
one to discover in Phase 2. Bounded measures the repo, not your familiarity: if the
|
||||
flow being changed isn't already there to read, it isn't bounded. In doubt, take the
|
||||
heavier path.
|
||||
11. Write `plan.md` in `<target-dir>/plan.md` (a sibling of `resources/`, not inside
|
||||
it). Structure:
|
||||
```
|
||||
# Plan: <KEY> — <short title>
|
||||
heavier path. Either way, record the classification with `ticket-page meta`.
|
||||
11. Write the plan as `plan.json` in a scratch path, in the shape [SITE.md](SITE.md) gives,
|
||||
and load it with `ticket-page plan <KEY> --file plan.json`. Its parts: acceptance
|
||||
criteria restated precisely from the ticket, each naming the steps that satisfy it;
|
||||
open questions that genuinely need Gib's answer, empty if there really aren't any
|
||||
(don't manufacture questions to look thorough); the approach, meaning what you're
|
||||
going to do and why, which files, modules and functions are involved, and how it fits
|
||||
the existing patterns; decisions already settled with Gib; steps, each roughly one
|
||||
commit's worth of work, with `"kind": "deliverable"` for a step that produces a
|
||||
document via **Deliverable documents** and `"kind": "mock"` for a real schema or UI
|
||||
change built to demonstrate a mock (see **Mocks and datamodel changes**); risks and
|
||||
edge cases, each with how the plan handles it; and the test plan, meaning how each
|
||||
criterion gets verified, the existing suites to run, and any new tests.
|
||||
|
||||
## 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.
|
||||
approach. The test plan must name every test case on the Ticket tab and say how
|
||||
that exact case gets proven, and the risks must name every risk on the Ticket tab
|
||||
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.
|
||||
|
||||
**Where the shape is in question, borrow the vocabulary.** When the plan has to
|
||||
decide how deep a module should be, where a seam belongs, or what an interface
|
||||
@@ -645,7 +559,7 @@ place from the start.
|
||||
written for real.
|
||||
|
||||
**The Test plan is a design decision, not a formality.** Beyond the cases
|
||||
`ticket.md` already captured, call the Skill tool with "tdd" to decide which
|
||||
the ticket already carries, call the Skill tool with "tdd" to decide which
|
||||
additional tests are worth writing, where the seam under test goes, and whether a
|
||||
mock is warranted. That judgment is what keeps this section focused instead of
|
||||
padded: a test plan listing one case per changed file is slop, and three tests that
|
||||
@@ -662,13 +576,14 @@ place from the start.
|
||||
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. Write `plan.html` beside it, per **The plan page** above, and open it with
|
||||
`xdg-open`.
|
||||
13. Stop here. Tell the user `plan.md` and `plan.html` are ready at their paths and that
|
||||
the page is open in the browser, 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
|
||||
`plan.md` directly if they want) and invoke `/ticket <KEY>` again.
|
||||
12. When a step changes what a user sees, draw its mock artboards with `ticket-page mock`,
|
||||
as [SITE.md](SITE.md) describes under **Mocks**.
|
||||
13. Stop here. Tell the user the plan is on the ticket page, give its path from
|
||||
`ticket-page path <KEY>`, 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 and invoke
|
||||
`/ticket <KEY>` again. They change the plan by asking, and you rewrite it with
|
||||
`ticket-page plan`.
|
||||
|
||||
## Phase 2 — implement, verify, and hand off
|
||||
|
||||
@@ -677,14 +592,16 @@ 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.
|
||||
2. Read the plan fresh with `ticket-page md <KEY>`, then mark it approved with
|
||||
`ticket-page approve <KEY>`.
|
||||
3. Work through the plan's steps in order. For each step: implement it (a
|
||||
`deliverable` step follows the **Deliverable documents** process above instead of
|
||||
writing code; a `mock` step follows **Mocks and datamodel changes** — real schema/UI work, not a static wireframe), and 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. Mark the step
|
||||
running on the page when you start it and done with its commits when they exist, and
|
||||
mark each acceptance criterion met the moment it is (SITE.md has the commands). A step
|
||||
is done when `ticket-page show <KEY>` lists its commit.
|
||||
|
||||
**Write the test first for steps that carry real logic**, meaning a router
|
||||
procedure, a derivation, a permission or authorization check, a migration, or a
|
||||
@@ -696,11 +613,13 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
House style rejects. When unsure whether a step qualifies, ask whether the test could
|
||||
ever fail for a reason worth knowing about. If it couldn't, skip it.
|
||||
|
||||
If a step fails in a way `plan.md` didn't predict, and the cause isn't obvious within
|
||||
If a step fails in a way the plan 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.
|
||||
fixes to see what sticks. Note anything it turns up that changes the plan as an event on
|
||||
the page. When it changes the steps, amend the plan as [SITE.md](SITE.md) describes, which
|
||||
keeps the progress already made.
|
||||
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
|
||||
Once every step is implemented and marked done, 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
|
||||
@@ -736,8 +655,9 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
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.
|
||||
(`.claude/docs/epics/<EPIC-KEY>/summary.md`), then the ticket and plan as
|
||||
`ticket-page md <KEY>` prints them, then this ticket's `resources/`, 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,
|
||||
@@ -748,12 +668,13 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
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
|
||||
the ticket and the plan 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.
|
||||
the plan step each finding traces to.
|
||||
|
||||
Then respond to the review, in writing:
|
||||
Then respond to the review, in writing, and put each finding on the page as you judge
|
||||
it: added, then fixed with its commit or rejected with the reason.
|
||||
|
||||
- **Findings are not automatically true.** Verify each one against the codebase
|
||||
before acting on it. Reviewers do produce confident wrong answers. Say plainly
|
||||
@@ -785,7 +706,7 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
skill prints the exact paths). Check the `last_reviewed_head` in the audit
|
||||
header matches the current HEAD; if the branch moved after their run, say so
|
||||
and ask them to rerun before acting on a stale audit.
|
||||
3. Read the verdict.
|
||||
3. Read the verdict, and record it on the page with `ticket-page 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 ask the user to rerun the review from the work
|
||||
@@ -811,8 +732,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
Make each one count:
|
||||
- **Feed it context on the first run.** It reviews the diff, and left alone it
|
||||
re-derives intent from the branch name and re-raises decisions that are
|
||||
already settled. Ask the user to point it at the ticket's
|
||||
`resources/ticket.md` and `plan.md`. This is the cheapest thing that reduces
|
||||
already settled. Ask the user to point it at the ticket's `ticket.data.js`, or give
|
||||
them the output of `ticket-page md <KEY>` to paste in. This is the cheapest thing that reduces
|
||||
repeat findings.
|
||||
- **Answer its decisions explicitly in the rerun.** When it parks a finding
|
||||
under "Decide before opening", write the decision and its reasoning into the
|
||||
@@ -836,7 +757,7 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
- 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,
|
||||
the plan (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
|
||||
@@ -876,7 +797,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
(`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/`).
|
||||
Save this as `<target-dir>/mr.md` (next to `index.html`, not under `resources/`), and
|
||||
record it with `ticket-page mr <KEY>`.
|
||||
|
||||
**`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
|
||||
@@ -897,7 +819,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
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,
|
||||
After every PUT, re-fetch and verify the field landed, then record it with
|
||||
`ticket-page jira <KEY> "<field name>"` (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.
|
||||
@@ -910,7 +833,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
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"
|
||||
rows they prove, and put each on the page with `ticket-page proof`, naming the
|
||||
criteria it proves and the mock it answers. 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
|
||||
@@ -920,7 +844,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
**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/`.
|
||||
smallest set that actually carries the evidence, delete the rest from `proof/`, and
|
||||
drop them from the page with `ticket-page unproof`.
|
||||
|
||||
- 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,
|
||||
@@ -976,12 +901,13 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
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
|
||||
Before moving on, re-read the Ticket tab's test case and risk tables 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:
|
||||
Ready to Open MR, the Jira fields are filled (name which), `mr.md` is ready at its
|
||||
path, and the ticket page shows the finished work beside its mocks. 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
|
||||
@@ -989,8 +915,8 @@ Entered only when the user has confirmed (per Phase 0) that the plan is approved
|
||||
|
||||
## 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
|
||||
If Phase 0 routes here because some steps are already done on the page: check
|
||||
`git log` on the current branch against the page's step commits 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
|
||||
from the first open step. If the plan and the git history disagree, stop and ask
|
||||
the user rather than guessing which one is right.
|
||||
|
||||
Reference in New Issue
Block a user