TodoWrite No Longer Available: Claude Code's 2.1.233 Tool Gate (2026)
"TodoWrite no longer available" is not a bug. Claude Code v2.1.233 drops the five task-tracking tools on Sonnet 5 and newer unless you opt in. The gate follows the session, not the model, and the SDK opt-in line behaves differently in TypeScript and Python (2026).
Updated on September 3, 2026
On this page
Quick Answer (2026)
If Claude Code stopped writing a todo list, nothing is broken. As of Claude Code v2.1.233, TodoWrite, TaskCreate, TaskGet, TaskUpdate and TaskList are not provided on Opus 4.8, Sonnet 5, Fable 5, Mythos 5 or later versions of those families unless you opt in. Anthropic's stated reason is that those models track multi-step work without a written checklist, and that "the tools' definitions and reminders take up context".
The one-line fix everyone quotes:
CLAUDE_CODE_ENABLE_TODO_TOOLS=1 claude
That works. Three things it leaves out matter more than the fix.
The gate does not follow the model, it follows the session. A subagent running Opus 4.7, a model that would normally get the Task tools, gets nothing if the parent session is on Sonnet 5.
The gate does not apply everywhere. Background sessions and Claude Code on the web provide the tools on every model, listed or not. The same model gives you two different tool sets depending on where it runs.
In the TypeScript Agent SDK, the copy-paste opt-in line can wipe your environment. env replaces the subprocess environment rather than merging with it. The identical-looking Python call merges. Measured below from both shipped packages.
Verified against the anthropics/claude-code changelog, Anthropic's tools reference and Agent SDK docs, @anthropic-ai/claude-agent-sdk 0.3.259 and claude-agent-sdk 0.2.152, in September 2026.
What actually changed, and in which artifacts
The removal landed in three packages at once, and the version numbers are not interchangeable. People quoting only the CLI number send SDK users looking at the wrong changelog.
Scroll to see more
| Artifact | Boundary version | Evidence |
|---|---|---|
| Claude Code CLI | 2.1.233 | changelog entry, quoted below |
| TypeScript Agent SDK | 0.3.233 | tools reference, Model availability note |
| Python Agent SDK | 0.2.139 | tools reference, Model availability note |
The changelog entry reads, verbatim:
Todo/task-tracking tools (TaskCreate/Get/Update/List, TodoWrite) are no longer available on Opus 4.8, Sonnet 5, Fable 5, Mythos 5, and newer models; set CLAUDE_CODE_ENABLE_TODO_TOOLS=1 to bring them back.
claude-agent-sdk 0.2.139 was uploaded to PyPI on 2026-08-14, which independently dates the boundary rather than taking a blog's word for it.
Read literally, that entry is a statement about models. That reading is what causes the two surprises in the next two sections.
The gate follows the session, not the model
Anthropic's tools reference is explicit, and this is the sentence nobody on the first page of results quotes:
Claude Code gives a subagent the tools only when your session has them, even when the subagent runs a different model.
So the decision is made once, for your session, and inherited downward. Concretely:
Scroll to see more
| Parent session model | Subagent model | Subagent gets Task tools? |
|---|---|---|
| Sonnet 5 | Sonnet 5 | No |
| Sonnet 5 | Opus 4.7 | No |
| Opus 4.7 | Opus 4.7 | Yes |
| Opus 4.7 | Sonnet 5 | Yes |
The two bold rows are the ones a model-based reading gets backwards. If you route a subagent to an older model specifically to get task tracking back, you will not get it. And if your parent session is on an older model, a Sonnet 5 subagent does get the tools.
Agent teams split this one step further, on display mode rather than on model. An in-process teammate follows your session the same way a subagent does. A teammate in its own split pane runs as a separate Claude Code process, so its own model decides. Same feature, two behaviours, chosen by a display setting. Without the Task tools an agent coordinates through messages instead of the shared task list, which is a real behavioural difference and not only a missing UI element. If you are wiring this up, the inheritance rules are the same ones that govern how subagents are scoped and nested.
Where the gate does not apply at all
In background sessions and in Claude Code on the web, Claude Code provides the same tools on every model, listed or not.
This is the one most likely to cost someone an afternoon. If you build a parser, a hook, or a progress display and test it interactively on Sonnet 5, you will see no task tool calls and may conclude the tools are gone for good. Run the same prompt as a background session and they are there. Any code that assumes "Sonnet 5 means no TaskCreate blocks" is wrong in exactly the environment you are least likely to test in.
Four ways to opt in, and what one of them costs you
The docs enumerate four routes, not one. Every result on the first page of Google mentions only the environment variable.
Scroll to see more
| Route | Where | Note |
|---|---|---|
CLAUDE_CODE_ENABLE_TODO_TOOLS=1 | shell, before launch | provides the tools on every model and every provider |
--allowedTools TaskCreate | CLI flag | naming any one of the five is enough |
--tools ... | CLI flag | restricts the session to the tools it names |
allowedTools / tools options | Agent SDK | same semantics as the two flags |
The third row is a trap worth stating plainly. --tools is not additive. It restricts the session's built-in tools to the ones it names, so opting in this way while listing only TaskCreate removes every other built-in tool from the session. If you use it, you have to enumerate everything else you rely on alongside it.
Worth noting what is not on that list: declaring a hook matcher. The four routes above are the complete set the documentation gives, and a PreToolUse matcher on TodoWrite is not among them. So a hook written against these tools does not opt the session in; it simply never fires, silently, because the tool it matches is not present. That is an inference from the documented enumeration rather than something reproduced here, so treat it as the documented reading and not a measurement. If you maintain hooks against these tools, the relevant lifecycle is covered in the Agent SDK hooks walkthrough.
The opt-in line means two different things in the two SDKs
This is the finding worth the article. Both SDK docs give you an env option and the examples look nearly identical:
// TypeScript
options: { env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } }
# Python
options=ClaudeAgentOptions(env={"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"})
The Python version is safe. The TypeScript version is safe only because of the spread. Drop ...process.env and you spawn Claude Code with an environment containing exactly one variable.
I checked both shipped packages rather than trusting the prose.
TypeScript, @anthropic-ai/claude-agent-sdk 0.3.259, in the bundled sdk.mjs, the option is destructured with a default:
pathToClaudeCodeExecutable: a, env: c = { ...process.env }
A destructuring default applies only when the property is absent. Omit env and c becomes a copy of process.env. Pass env and c is exactly the object you passed. There is no merge step anywhere after it. The package's own type definitions state that a supplied value replaces the subprocess environment entirely rather than merging with process.env, and then name the casualties outright:
Spread process.env yourself if the subprocess still needs inherited variables like PATH, HOME, or ANTHROPIC_API_KEY. When omitted, the subprocess inherits process.env.
Python, claude-agent-sdk 0.2.152, _internal/transport/subprocess_cli.py, builds the environment explicitly:
inherited_env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}
process_env = {
**inherited_env,
"CLAUDE_CODE_ENTRYPOINT": "sdk-py",
**self._options.env,
"CLAUDE_AGENT_SDK_VERSION": __version__,
}
That is a real merge, with your env layered on top of the inherited environment. Two details fall out of the ordering that no summary mentions:
CLAUDE_CODE_ENTRYPOINTis set before yourenv, so you can override it.CLAUDE_AGENT_SDK_VERSIONis set after yourenv, so you cannot.CLAUDECODEis deliberately stripped from the inherited environment, so an SDK subprocess does not believe it is running inside a Claude Code parent.
So the same conceptual instruction, "set this variable", is a safe additive change in Python and a destructive replacement in TypeScript. The TypeScript failure mode is nasty because it is not a crash at the env line: you lose PATH and ANTHROPIC_API_KEY, and the failure surfaces later as a missing binary or an auth error that looks unrelated to the todo tools you were trying to enable.
Two environment variables, two eras
There are two similarly-named variables in circulation and they are not alternatives.
Scroll to see more
| Variable | Era | Effect |
|---|---|---|
CLAUDE_CODE_ENABLE_TASKS=0 | pre-2.1.233 | On models that are not gated, provides TodoWrite instead of the four Task tools |
CLAUDE_CODE_ENABLE_TODO_TOOLS=1 | 2.1.233 and later | Opts a gated model back in to all five |
The first one is about which tracking system you get on a model that has one. The second is about whether you get one at all. Setting CLAUDE_CODE_ENABLE_TASKS=0 on Sonnet 5 does not bring the tools back. The documentation scopes that variable explicitly to "any other model", and it is absent from the list of opt-in routes for the gated ones.
I went looking for a contradiction here, on the theory that the docs still described the pre-2.1.233 world. They do not. Both variables are documented, both are current, and they answer different questions. Recording the disconfirmation because the search-result snippets make it look like a conflict.
What breaks quietly
Nothing raises an error when a tool is simply absent, which is why this shows up as confusing downstream behaviour rather than a stack trace. Skill and plugin authors hit it first: the
obra/superpowers project tracked exactly this, with its skills depending on TodoWrite and the agent having no such tool available.
Things to check, in rough order of how quietly they fail:
- Hooks matching the five tool names. They do not fire. There is no warning.
- Permission rules and
allowedToolsentries naming them. Note the second-order effect: anallowedToolsentry is itself an opt-in route, so a leftover permission rule can silently switch the tools back on in a session you expected to be clean. - Skills and
CLAUDE.mdinstructions telling Claude to keep a todo list. The instruction stays, the tool does not, and you get prose approximating a checklist. - Stream parsers waiting for
TaskCreateorTodoWritetool_useblocks. They wait forever. - Split-pane teammates behaving differently from in-process ones.
One extra note for anyone parsing the stream on an opted-in session, straight from Anthropic's docs: Claude Code repairs some close-but-incorrect key names before execution, mapping id or task_id to taskId and active_form to activeForm, but that repair is not reflected in the stream. The block you receive carries the raw shape the model emitted. Read those fields defensively:
const taskId = input.taskId ?? input.id ?? input.task_id;
Related: TaskCreate's assigned ID is not in the TaskCreate input at all. It arrives on the paired user message as tool_use_result, so correlating a create with its later updates means keying on tool_use_id rather than reading the ID off the call.
Checklist
- Is your Claude Code at 2.1.233 or later, or your SDK at TS 0.3.233 / Python 0.2.139 or later? Below those, none of this applies.
- Is the session model in the gated set? Opus 4.8, Sonnet 5, Fable 5, Mythos 5 and later families.
- Are you actually in an interactive session? Background sessions and the web get the tools regardless.
- If you want them back, prefer the environment variable or
--allowedTools. Reach for--toolsonly if you are willing to enumerate every other built-in you use. - In the TypeScript SDK, spread
...process.env. In Python you do not need to, and doing so is harmless. - Check whether a stale
allowedToolsentry is opting you in when you did not mean to. - If a subagent is missing the tools, look at the parent session's model, not the subagent's.
Sources
- Claude Code changelog,
anthropics/claude-code, entry under 2.1.233. - Anthropic tools reference, Task tool availability, for the session inheritance, background-session and opt-in routes.
- Anthropic Agent SDK docs, Track todos, for the SDK version boundary and the key-repair note.
@anthropic-ai/claude-agent-sdk0.3.259 published tarball,sdk.mjsandsdk.d.ts.claude-agent-sdk0.2.152 source distribution,_internal/transport/subprocess_cli.py.- Release date from the claude-agent-sdk release history on PyPI.
- Downstream impact report: obra/superpowers issue 2177.
Written by
Sofia NievesSofia works on agent evaluation and reliability. She writes about measuring LLM systems before and after they reach production.
Frequently asked questions
Why did Claude Code stop showing a todo list?
As of Claude Code v2.1.233, the five task-tracking tools (TodoWrite, TaskCreate, TaskGet, TaskUpdate, TaskList) are not provided on Opus 4.8, Sonnet 5, Fable 5, Mythos 5 or later versions of those families unless you opt in. Anthropic's reason is that those models track multi-step work without a written checklist and the tool definitions consume context. Nothing is broken and there is no error.
How do I get TodoWrite back?
There are four documented routes, not one. Export CLAUDE_CODE_ENABLE_TODO_TOOLS=1 before launching Claude Code; or name one of the tools in --allowedTools; or list them in --tools; or use the allowedTools or tools options in the Agent SDK. Be careful with --tools: it restricts the session to only the tools it names, so you must enumerate every other built-in you rely on.
My subagent runs an older model. Why does it still have no task tools?
Because the gate follows the session, not the model. Anthropic's tools reference states that Claude Code gives a subagent the tools only when your session has them, even when the subagent runs a different model. So a subagent on Opus 4.7 under a Sonnet 5 parent gets nothing, and a Sonnet 5 subagent under an Opus 4.7 parent does get them.
Is CLAUDE_CODE_ENABLE_TASKS the same as CLAUDE_CODE_ENABLE_TODO_TOOLS?
No. They are from different eras and answer different questions. CLAUDE_CODE_ENABLE_TASKS=0 applies to models that are not gated and selects TodoWrite instead of the four Task tools. CLAUDE_CODE_ENABLE_TODO_TOOLS=1 opts a gated model back in to all five. Setting CLAUDE_CODE_ENABLE_TASKS=0 on Sonnet 5 does not bring the tools back.
Does setting env in the Agent SDK have any side effects?
In TypeScript, yes, and it is easy to miss. The env option replaces the subprocess environment rather than merging with it, so passing only CLAUDE_CODE_ENABLE_TODO_TOOLS drops PATH, HOME and ANTHROPIC_API_KEY. Spread process.env alongside it. The Python SDK merges your env on top of the inherited environment, so the equivalent call is safe there.
Why do the task tools appear in some sessions but not others on the same model?
Background sessions and Claude Code on the web provide the same tools on every model, listed or not. So the identical model can give you two different tool sets depending on where the session runs. Code that assumes a gated model never emits TaskCreate blocks will be wrong in those environments.
Related tutorials
Claude Code Subagents: How to Create, Scope, and Nest Them (2026)
The /agents creation wizard was removed in Claude Code v2.1.198, so almost every guide still ranking for this topic teaches a flow that no longer exists. Here is the current way to write, scope, invoke, and cap Claude Code subagents, with a version number on every claim. August 2026.
Claude Agent SDK Hooks: Block, Modify, and Audit Tool Calls (2026)
Register PreToolUse and PostToolUse hooks in the Claude Agent SDK to block dangerous tool calls, rewrite a tool's arguments, and audit every action. Copy-paste runnable Python and TypeScript, August 2026.
Claude Code Plan Mode: How It Actually Gates Your Edits (2026)
Plan mode is not a read-only state. It is a rule at step 4 of a six-step permission evaluation, which is why allow rules stop applying while you plan and why a session with bypass permissions can edit anyway. The CLI keystrokes, the settings, the Agent SDK equivalent, and a plan-then-execute pipeline in Python and TypeScript. August 2026.