◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-04-24Intermediate

Claude Code's TodoList Quality Comes Down to Task Granularity — Patterns That Actually Worked

The TodoList tool in Claude Code can backfire when used carelessly. Three field-tested patterns — task granularity, verification steps, and update timing — that shift the output from 'looks organized' to 'actually delivered'.

Claude Code264TodoListtask managementworkflow41agent design

Have you ever noticed that Claude Code's TodoList looks well-organized, yet the underlying work still feels sloppy? I went through the same phase. Early on, I was fixated on filling the TodoList with neat bullets, and in the process the actual craftsmanship behind each item kept slipping.

What I eventually realized is that what matters is not whether you write a TodoList, but how granular each item is, when you update them, and whether you build verification into the list itself. Drawing from the automation I run across my four sites, here are three patterns that have made a real difference.

Why "I wrote a TodoList" is not the same as "I'll do quality work"

The TodoList is undeniably useful. It breaks down complex tasks, gives you visible progress, and reassures both humans and agents. But there is a subtle trap.

A TodoList is a tool for visualizing a plan, not a tool for guaranteeing execution quality. When items are too coarse, the details of each item stay ambiguous, and the work ends up being cut-to-fit on whatever feels convenient. Consider this list:

  • [ ] Refactor the component
  • [ ] Write tests
  • [ ] Update documentation

It looks tidy, but the moment the agent starts, "which file" and "how" are left to improvisation. You end up with a change set that fixes the files that happened to be open, then calls it done.

Pattern 1: Slice tasks into "verifiable units"

The biggest win for me was treating each TodoList item as something whose completion you can verify objectively. The item itself should make it unambiguous what "done" looks like.

Compare bad and good examples:

❌ Unverifiable
- [ ] Improve API response caching
- [ ] Harden error handling

✅ Verifiable
- [ ] Implement a Map-based cache with a 5-minute TTL in src/lib/api-cache.ts
- [ ] In src/app/api/checkout/route.ts, branch on Stripe's StripeCardError in the try/catch and return a user-facing message
- [ ] Add Vitest tests in tests/api-cache.test.ts covering cache hit, miss, and expiration

In the good example, each item carries its own acceptance criteria. Does the cache use a Map? Is the TTL five minutes? Does the handler branch on StripeCardError? You can answer those by reading the diff.

A simple rule of thumb I use: write items as "verb + target file + completion criterion." When all three are present, the granularity tends to land in the right zone.

Pattern 2: Always end with a verification step

The next pattern is to close every TodoList with an explicit verification step. Without this, agents treat "all items checked = done," and subtle breakage slips through.

My template looks like this:

- [ ] (work item 1)
- [ ] (work item 2)
- [ ] (work item 3)
- [ ] [VERIFY] tsc --noEmit passes on all touched files
- [ ] [VERIFY] vitest run stays green on the existing suite
- [ ] [VERIFY] Manually open /, /en/articles/... and two related pages to confirm nothing is visually broken

Adding a verification step visibly lifts final quality. The reasoning is simple: the agent knows it cannot close the list until verification is also done, which kills the urge to cut corners at the finish line.

For higher-stakes work, I delegate the verification to a separate subagent via Claude Code's Task tool. A fresh agent checking the work removes the author bias that creeps in when the same agent verifies itself.

Pattern 3: Pin update timing to "one item at a time, in real time"

The third pattern is about update timing. The official docs recommend it, but whether you actually enforce it in practice changes everything.

The rule is simple: flip an item to in_progress immediately before you start it, and flip it to completed immediately after you finish it. No batching.

Why batching updates hurts you

I once tried "do five items, then mark them all completed at the end." It felt efficient, but in practice:

  • When an error surfaced mid-batch, I had no idea which items had genuinely finished
  • If the session disconnected, the saved state no longer reflected reality
  • Verification had to cover all five items, making triage slow

Switching to one-at-a-time updates made mid-task recovery radically easier. Claude Code can pick up a previous session's TodoList, so as long as the state is accurate it can resume naturally from the right spot.

Implementation: a TodoWrite-aware prompt

Here is the skeleton of a prompt I use for article automation. Treat it as a typical shape for a TodoWrite-driven workflow:

# Task: write one article and push it
 
Before starting, register the following TodoList via TodoWrite.
 
1. [pending] Pick today's topic from GSC data and confirm the slug is not duplicated
2. [pending] Create the Japanese MDX in content/articles/ja/claude-code/ (>=3,000 characters, consistent polite voice)
3. [pending] Create the English MDX in content/articles/en/claude-code/ (>=1,500 words)
4. [pending] [VERIFY] Confirm find content/articles/ja -name "*.mdx" | wc -l matches the English count
5. [pending] [VERIFY] Grep the new MDX for internal links and confirm every target article exists
6. [pending] Run git add, commit, and push
7. [pending] Append an entry to _updated_article_log/
 
Update each item one at a time: flip to in_progress when you start, completed when you finish.
If a verification step surfaces an issue, add a new pending item before fixing it.

The key is that verification is an explicit item, and the branch for "what to do when something fails" is also governed by the TodoList. That habit alone reduces the number of issues that slip through.

When not to use TodoList

Finally, a few situations where TodoList is not the right tool. It is not a universal hammer.

  • Conversational Q&A: "What does this function do?" or "Why is this erroring?" does not need a TodoList. It only increases cognitive load and buries the actual answer.
  • Tiny single-file edits: For a typo fix or a few-line change, creating a TodoList costs more than it saves. Go straight to Edit.
  • Exploration: While you are still figuring out how to implement something, the investigation is fluid by nature. Freezing it into a TodoList kills flexibility. Explore first, decide the direction, then TodoList it.

Personally, the sweet spot is tasks that will take at least 15 minutes and span multiple files or multiple verification points. That is where the TodoList truly earns its keep.

Going deeper

If you want to see how TodoList fits into the broader picture of agent design, pair this article with Using Claude Code's Plan Mode to isolate the design phase and Solving Claude Code's long-running task failures through operational design. Together they cover planning, execution, and recovery.

Your next step

Pick one task in your day that will take more than 15 minutes, and turn only that one into a TodoList. Add at least one explicit verification item at the end. That small commitment alone will change how the final output feels. Once you are comfortable, graduate to delegating verification to a separate subagent — that is where truly stable automation starts.

A concrete walkthrough: a two-hour refactor with TodoList

To make these patterns tangible, here is a condensed version of an actual session I ran last week — a two-hour refactor where I had to move a payment flow from a single Next.js route into a set of shared helpers.

The initial TodoList looked like this:

1. [pending] Extract the Stripe session creation into src/lib/stripe/checkout.ts with named exports
2. [pending] Extract the webhook signature verification into src/lib/stripe/webhook.ts
3. [pending] Update src/app/api/checkout/route.ts to import the new helpers
4. [pending] Update src/app/api/webhook/route.ts to import the new helpers
5. [pending] Add unit tests in tests/stripe/ for both helpers (minimum: happy path + one failure case each)
6. [pending] [VERIFY] tsc --noEmit passes across the project
7. [pending] [VERIFY] vitest run is green
8. [pending] [VERIFY] Manually walk through a test checkout on localhost to confirm end-to-end behavior

Halfway through item 3, I hit a subtle issue: the old route was logging metadata in a format the new helper did not yet preserve. Rather than quietly patching it, I added a new pending item before continuing:

3.5 [pending] Preserve the existing checkout-metadata logging format in the new helper

That one-line discipline — never make an unplanned fix without first adding it to the list — is what keeps long sessions honest. When I reviewed the commit later, every change had a traceable origin.

The mental shift: from "listing" to "contracting"

Looking back, the biggest change in how I think about TodoList is this: I used to treat it as a list of things to do. Now I treat it as a contract I am handing to the agent, including the acceptance criteria.

When each item reads like a small contract — "complete X in file Y, verified by Z" — you stop needing to supervise the agent line by line. You can step away, let it work, and audit the outcome against the contract when you come back. That is what unlocks the real productivity gain of Claude Code.

The patterns in this article are not about making the list longer. They are about making each item trustworthy. Once that click happens, a five-line TodoList can carry a two-hour task reliably, and you spend your attention where it actually matters.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Claude Code2026-04-02
Running Claude Code Per Worktree: Notes From Actual Use
Implementation notes on splitting branches into Git worktrees and launching Claude Code per directory. What is shared and what is isolated, measured on a real repository, plus the untracked files nobody warns you about.
⟐ Claude Code2026-10-15
The Hook That Was Meant to Guard My Japanese Folder Never Blocked Anything — Python Was Reading stdin as cp932
A PreToolUse hook guarding folders like 経理 or 議事録 silently lets edits through when Python's stdin defaults to cp932. How I reproduced it, the three-line fix, and one command to check your own hooks.
⟐ Claude Code2026-10-14
I Set onFailure to block, and the Docs' rm -rf Guard Still Let Everything Through Without jq
When a PreToolUse guard hook fails, does the action go ahead or stop? The docs' own rm -rf example exits 0 and waves everything through when jq is missing. Ten failure modes run for real, the fix, and a script that finds fail-open guards in settings.json.