The ticket is the thinking
Writing the ticket is the work, and everything after it is execution. That sounds backwards, because in most workflows the ticket is a light wrapper around the real work. In mine, the ticket is where I make the design decisions, name the edge cases and write down how the result will be verified. An agent builds what the spec describes, so the quality of the spec caps the quality of what comes back: a vague brief gets vague software. Over time the tickets turn into tests, the tests become context for the agent, and that context shapes the next ticket.
Every task is a ticket before it’s a task
Before I open an editor, I write the spec as a document: what the user sees, what happens in the database, what the edge cases are and what “done” looks like. Only then do I open Claude Code. The spec forces the thinking to happen before implementation starts, and it draws a hard line around scope.
Scope drift is the real enemy. Most of the bugs I have introduced started with “while I’m in here, I should also fix X”. When something adjacent comes up mid-session, I open a new ticket for it, and the current one stays clean.
Every bug becomes its own ticket
When you find a bug, the instinct is to fix it on the spot, while you are in the codebase and can see the cause. A bug found in passing is usually not fully understood, though. You see the symptom and you have a theory. Fix it inline and you fix it under time pressure, without writing down the failure mode or thinking through how to verify the fix.
I tested a bulk order on NfcPress, an NFC business card platform I built with a friend. Every card in the bulk PDF showed the same base design instead of its own. I could see what was probably wrong, and my first impulse was to fix it there and then. Instead I opened NFC-57.
Writing the ticket forced a proper diagnosis, and it turned up two separate bugs. The card design was generated in the background after the page had already responded, and Vercel stopped that job before it finished. When cards were rebuilt, they were sorted by the time they were created instead of by their code, so the order could change from one run to the next. Both root causes were documented before a line of code changed.
The ticket also showed that no automated test covered this. As soon as NFC-57 closed, I opened NFC-58: a Playwright test with three scenarios designed to catch these failure modes if they regress. The bug became a ticket, the ticket a fix, and the fix a test that now runs before every deploy. It has not had to catch a regression yet. The proof comes the next time something breaks and this test fails first.
The kanban is a view, not the system
I have a kanban board with Backlog, In Progress and Done, and it gives me a quick read on what is moving. The system lives in the .md files behind it. Every ticket is a markdown file: frontmatter for status, then a spec with context, scope, what to build and how to verify it. A sync daemon generates the board from those files, so if the board disappeared I would lose the view and keep the knowledge. The files stay, and I can grep them, count them and reference them from other tickets.
Tickets accumulate
After a wave of features ships, I run a retro: a pass through the closed tickets to work out what they imply, taken together, about the product’s correctness. After roughly 38 NfcPress tickets had closed, I opened a ticket whose only job was to read the other 38. Its spec began like this:
As of 2026-05-22, many product behaviors have been shipped. None of these are covered by regression tests. Any future change could silently break them.
That ticket read the closed history and produced two outputs. The first was a set of new tests for evals/smoke.ts, the HTTP checks that run before every deploy. The second was a set of additions to evals/product-evals.md, a manual golden checklist for behaviour that needs a browser and human eyes to verify. A golden is a one-line statement of required behaviour that must stay true across releases.
The next retro came after NFC-39 to NFC-48, and its spec picked up where the first one stopped:
The previous evals round covered up to roughly NFC-38. Since then the following tickets shipped and are not yet covered by any test or golden…
It then listed every feature, each with the specific smoke tests and goldens to write for it. Tickets ship, a retro reads the history, and the goldens and smoke tests it writes go into the harness that protects every later ticket. Each wave makes the harness stronger, and nothing evaporates.
Evals feed back into execution
Every new ticket opens with the smoke suite and the goldens already in context. Claude implements the feature against the new spec and against everything the last 48 tickets learned. NFC-58 made this explicit: its context section carried a table inherited from NFC-57.
| Failure | Symptom | Root cause |
|---|---|---|
design_front_path = null on all cards |
Every PDF page shows identical base design | void generatePerCardDesigns() got killed before completing |
| Sharp crash (float dimensions) | Same as above, silent | qrConfig.width is a float; Math.round() missing |
| Wrong page order | Card 2 appears on PDF page 1 | Cards were sorted by creation time; now sorted by code |
Known failure modes from the bulk PDF bug are now executable specs, sitting in the context the agent reads first. Bugs teach the goldens, the goldens constrain the next implementation, and that implementation produces new bugs and new goldens.
None of this requires a methodology. It requires one discipline: write the ticket before doing the thing. After 48 NfcPress tickets, that discipline means the next ticket starts with every failure the earlier ones wrote down.
