One Claude Code Tip a Day: Keep a Running Acceptance Checklist

Use Claude Code more safely by keeping a visible acceptance checklist: define proof before edits, update it after each command, and refuse to close the session until every item has evidence.

Abstract developer workstation with code editor, terminal checks, and a visual acceptance checklist

This post is part of the “One Claude Code Tip a Day” series — a daily guide to using Claude Code more effectively.

The real failure: “done” without an agreement

A Claude Code session can fail even when the patch is technically reasonable. The common pattern is not dramatic: you ask for a small bug fix, Claude edits three files, a test passes, and the summary says the issue is resolved. Ten minutes later you notice the settings page still has the old empty state, or the API error is handled only on the happy path. The problem was not that Claude could not code. The problem was that nobody kept the definition of done visible while the session moved.

Today's habit is to keep a running acceptance checklist inside the conversation. It is not a project-management document. It is a compact contract that says what must be true before you accept the patch: user-visible behavior, commands run, logs inspected, diff reviewed, and anything intentionally not covered. Claude Code is much better when it has to update that contract after every pass.

Start by making Claude write the checklist

Do this before the first edit. Give Claude the task, but ask for proof criteria first:

`We need to fix the billing export button. Do not edit yet. Read the route, component, API client, and existing tests. Then create a short acceptance checklist: user-visible behavior, edge cases, commands to run, logs or network responses to inspect, and the exact files likely to change.`

A useful checklist might say: button disabled while exporting, successful CSV download preserves filters, 401 shows a login message, export errors do not leave the spinner running, `npm test -- billing-export` passes, and `git diff` contains no unrelated formatting. That is already more valuable than a vague implementation plan because it tells both you and Claude how the session will end.

Turn the checklist into the session dashboard

After Claude proposes the checklist, make it carry the list forward:

`Proceed with the smallest patch. After each tool run, update the checklist with one of: proven, failed, not run, or changed. Do not mark an item proven unless you have command output, code evidence, browser evidence, or a log line.`

This changes the tone of the session. Instead of a polished paragraph claiming success, you get a working dashboard. Maybe the unit test is proven, the browser download is not run because the dev server failed, and the network error case changed because the code uses a shared toast helper. That is exactly the kind of friction you want. It keeps the model from treating a passing command as permission to ignore the rest of the behavior.

A realistic loop: export bug, tests, and a diff review

Imagine the first patch adds a `finally` block to stop the spinner and a catch branch for failed exports. Claude runs `npm test -- billing-export` and the test passes. Without the checklist, the session might end there. With the checklist, you can ask:

`Update the acceptance checklist. Then inspect git diff and tell me whether every changed line supports one checklist item. If any item is still not proven, give me the next verification step, not a success summary.`

Now the diff becomes evidence. Claude may notice that it changed a shared `Button` component while trying to fix one page. Or it may see that the 401 case is covered in code but not in tests. The next step is no longer ‘make it better’; it is specific: add a failing test for the 401 branch, run it, patch only that path, and re-run the same command.

Second-pass correction: when a checkbox lies

The most useful moment is when a checklist item looks proven but is not. Suppose Claude marks ‘CSV preserves filters’ as proven because a unit test checks the query object. You manually try the browser and the downloaded file ignores the date range. Feed that observation back precisely:

`Checklist correction: CSV preserves filters is not proven. Browser result: request URL contains status=paid but not startDate or endDate. Re-read the filter serialization path. Explain why the test missed this before editing.`

This forces a second-pass diagnosis instead of a random patch. Claude may discover the component state uses `dateRange`, while the API client expects `startDate` and `endDate`. The fix is now anchored in a failed acceptance item, an observed request URL, and a known gap in the test. That is a much safer loop than asking the model to ‘try again.’

Failure modes to watch for

First, avoid checklists that are just tasks: ‘edit component, run tests, update docs’ is not acceptance. Each item should describe evidence or behavior.

Second, do not let Claude mark something proven from intention. ‘Added error handling’ is not proof; a test, log, manual browser result, or inspected code path is proof.

Third, keep the list short. Five to eight items is enough for a small feature or bug. If the checklist becomes a wall of text, ask Claude to split the task or reduce scope before editing more files.

Rule of thumb

Before Claude Code edits, make it define what would count as done. During the work, make it update that checklist with evidence. At the end, accept the patch only when the checklist, the command output, and the git diff tell the same story. The checklist is not bureaucracy; it is the memory of the session made explicit.