Skip to main content

Command Palette

Search for a command to run...

Your agent treats every TODO like it's blocking. Mark which ones aren't.

Agents can't tell a throwaway TODO from a blocking one. They build subsystems around comments you left for next quarter. Prefix your TODOs with intent and watch the noise drop.

Updated
•4 min read•View as Markdown

You leave a comment in the middle of a refactor:

// TODO: cache this call for the list endpoint

You meant: come back to this when the list page actually feels slow. Two days later the agent opens a branch and the diff has 400 lines: a new CacheService, a TTL config, invalidation hooks for three other endpoints, and unit tests for the edge case where the cache warms during a deploy.

You didn't ask for any of that. You wrote a note to yourself.

TODOs are not task tickets

Humans read // TODO: with a lifetime of context. We know which comments are from last sprint's cleanup pass, which ones are jokes, and which ones actually block a release. An agent reading the same file sees a flat list of open instructions. Every TODO looks equally actionable because it is, syntactically, an instruction.

The training signal is stacked against you. Code on GitHub is full of TODOs that grew into features, TODOs that were fixed in a later commit, and TODOs that an engineer meant to address next week. The pattern the agent learns is: TODOs get implemented. It doesn't learn the meta-rule that half of them should be ignored.

What gets built

The most common over-build is around error handling. A TODO like // TODO: handle null case becomes a 20-line guard block with a custom error type, a log line, and a retry wrapper. The null case happens once a month and the original author would have been fine with if (!x) return;.

The second most common is around config. // TODO: make this a setting becomes a new env var, a settings UI field, and a migration for the default value. You meant: hardcode it for now and revisit if a second deployment needs a different number.

Both of these are defensible code. That's the problem. The code isn't wrong, it's just more than you asked for, and every line of it is now something you have to review, test, and maintain.

The fix is a prefix, not a prompt

You can try to tell the agent in the system prompt "don't implement TODOs unless I ask." It works for about two sessions. Then a new model version resets the behavior, or the agent hits a context window edge and forgets the instruction.

The fix that stuck for us is mechanical: prefix every TODO with an explicit lifetime.

// TODO(later): cache this call. List page feels fine.
// TODO(now): null check crashes on the export path.
// TODO(never): this is a known limitation of the mock server.

Then the rule is one line: only touch TODO(now) comments. TODO(later) is a note for humans. TODO(never) is a documented tradeoff, not a bug.

This works because it doesn't rely on the agent remembering a preference. It's in the file, it's greppable, and it survives model switches. You can even lint it: fail the build if an agent PR adds a TODO without a prefix.

What this has to do with specs

The underlying issue is the same one that shows up in API work: the agent treats a note as a contract. When a human leaves a TODO, they're writing to themselves. When an agent reads it, it reads to a spec. The gap between "a thing I might do later" and "a thing you should build now" is exactly the gap that explicit markers close.

We ran into the same pattern when agents started generating OpenAPI specs from code. The agent saw a comment on an endpoint like // TODO: add pagination and turned it into a full query parameter, a response envelope change, and a test. The endpoint didn't need pagination. The comment was from 2023.

We ended up treating TODOs the way we treat spec comments: if it matters, it's marked. If it's not marked, it's not a requirement. The local-first flow in Powerduck is built around that principle — the spec file is the source of truth, and a stray comment in the codebase is not.

The cheap version

You don't need a whole toolchain. Before you hand an agent a task, grep the target directory for TODO and look at what's there. If the list is longer than five items, you have a problem: the agent will find all of them and try to fix all of them.

Either clean up the old TODOs first, or add the prefixes in a five-minute pass. It's faster than reviewing 400 lines of cache infrastructure you didn't want.

More from this blog

P

Powerduck Blogs

157 posts

Essays on local-first API tooling, OpenAPI contracts, MCP, and agentic coding failures. We build Powerduck, a local-first OpenAPI studio where the spec stays the source of truth. Topics: AI code review trust, testing AI-generated code, context engineering, and what actually breaks when AI writes your code.