Claude Agent SDK Python | TodoWrite Deprecation and Migration to Task Tools
If you run pip install --upgrade without pinning your version and suddenly TodoWrite disappears, leaving your bot stopped with an ImportError — that's a serious problem. This article covers everything you need to know about the Task tools migration in Claude Agent SDK Python v0.2.82: a 30-second impact checklist, step-by-step replacement instructions, and rollback procedures.
Anthropic removed TodoWrite in v0.2.82, released on 2026-05-15, splitting its responsibilities into four tools: TaskCreate / TaskUpdate / TaskGet / TaskList. Code that depends on the return values or side effects of TodoWrite needs immediate updates, and teams running headless sessions should assess their exposure first.
Start the migration by swapping the imports, then reorganize your logic into: TaskCreate for creation, TaskUpdate for updates, TaskGet for retrieval, and TaskList for listing. You should also check the permission_suggestions type and the separation of stderr callbacks at the same time. The biggest pitfall is CancelledError handling inside eager-flush completion callbacks.
For a staged migration, an opt-in flag via environment variable CLAUDE_CODE_ENABLE_TASKS=1 is available. Roll out in order: dev → staging → production, with a two-stage rollback option using SDK downgrade plus flag removal if issues arise. Using the newly public EffortLevel type will keep things stable during the transition period.
目次 (17)
- Conclusion — TodoWrite Is Deprecated in Claude Agent SDK Python v0.2.82; Migration to Task Tools Is Required
- Impact Checklist — Determine in 30 Seconds Whether Your Code Needs Migration
- Check Your SDK Version in One Command
- Categorize Impact by How You Used the Return Value
- Implementation Mapping — How to Replace TodoWrite with TaskCreate / TaskUpdate / TaskGet / TaskList
- Step-by-Step Replacement Template — 5 Steps from Import to Return Value Handling
- Pitfall — stderr Callback Separation and CancelledError
- The CLAUDE_CODE_ENABLE_TASKS=1 Flag and How to Roll Out in Stages
- Use Partial Enablement to Run an A/B Comparison
- Recommended Rollout Phases for Your Team
- Rollback Procedure — Two-Stage Recovery
- Best Practices and Tips After Migration — Stable Headless Session Operations
- Use the Public EffortLevel Type for Type Safety
- Watch Out When Combining with MCP Server Background Connections
- Diffs Caused by the Bundled Claude CLI v2.1.142 Auto-Update
- Claude Code v2.1.143: Enforced Plugin Dependencies and the New worktree.bgIsolation: "none" Setting
- Sources
Conclusion — TodoWrite Is Deprecated in Claude Agent SDK Python v0.2.82; Migration to Task Tools Is Required
According to the Claude Agent SDK Python release notes, v0.2.82 was released at 03:47 UTC on 2026-05-15, and TodoWrite — which had previously handled all Todo-based progress tracking — was completely removed. In its place, four new tools were introduced: TaskCreate (create), TaskUpdate (update), TaskGet (retrieve), and TaskList (list), with CRUD responsibilities now explicitly separated. As announced in Anthropic's official Claude Agent SDK Python documentation and Todo Tracking guide, this is a deliberate step toward long-term API stability and alignment with Managed Agents.
The code most affected includes: tool definitions that call TodoWrite directly, operational logic that custom-parses its return values, and in-house bots that automatically pick up the latest SDK version from Anthropic. Teams running headless sessions in particular risk hitting an ImportError the moment pip install --upgrade runs, if they haven't pinned the Python package version. The safest approach is to pin the SDK at ==0.2.81 first and then migrate in a controlled manner.
Impact Checklist — Determine in 30 Seconds Whether Your Code Needs Migration
The first thing to do is figure out whether your code falls within the scope of the breaking change. Work through the table below from top to bottom, answering YES or NO. If even one answer is YES, migration work is required. If all are NO, simply upgrading the SDK should be enough to keep things running.
| Check Item | If YES, Action Required |
|---|---|
TodoWrite is registered directly in a Tool list |
Replace the tool definition with the 4 new Task tools |
The todos return value from TodoWrite is saved separately |
Re-parse using the TaskList return value schema |
Fields of type permission_suggestions are referenced |
Update type annotations to match the new signature |
| Headless sessions are running with auto-upgrade enabled | Pin the version and validate in a test environment first |
| Todo state is flushed in an eager-flush completion callback | Review CancelledError handling and retry conditions |
Check Your SDK Version in One Command
Before assessing impact, make sure you know exactly which version your environment is using. With your Python virtual environment activated, run the following. If the Version line shows 0.2.82 or later, you've already switched to the new API and are within the scope of the breaking change. If it shows 0.2.81 or earlier, the old API is still available — but since you never know when an upgrade might run, you should start preparing for migration now.
pip show claude-agent-sdk
# Name: claude-agent-sdk
# Version: 0.2.82
Categorize Impact by How You Used the Return Value
The amount of work required depends heavily on how you handled the TodoWrite return value. If you completely ignored the return value, you can get away with just renaming the API. If you pulled the latest Todo list for display purposes, you'll need to adapt to the TaskList return value schema. If you persisted data to a database or similar, you'll need to account for the fact that the field name changed from todos to tasks, a task_id field was added, and the allowed values for status were standardized to pending / in_progress / completed / cancelled.
Implementation Mapping — How to Replace TodoWrite with TaskCreate / TaskUpdate / TaskGet / TaskList
Let's look at the concrete code changes. First, we'll review the mapping between the old and new APIs, then walk through a step-by-step replacement template. Anthropic's official Todo Tracking guide (Japanese) covers the same ground, so reading it alongside this article will help reduce confusion.
| Old API (v0.2.81 and earlier) | New API (v0.2.82 and later) | Key Differences |
|---|---|---|
TodoWrite(todos=[...]) for bulk overwrite |
Call TaskCreate(title, description) individually |
Created one at a time; a task_id is issued |
TodoWrite(todos=[...]) for partial updates |
TaskUpdate(task_id, status, notes) |
task_id is required; status is now a strict enum |
Get the latest list from TodoWrite return value |
TaskList(filter=None) |
Supports filtering by status |
| Reload the previous Todo state | TaskGet(task_id) |
Returns only the latest state of a single task |
Step-by-Step Replacement Template — 5 Steps from Import to Return Value Handling
Applying a breaking change all at once bloats the diff and makes review unmanageable. The following order, with commits split at each step, is the safe approach.
- Fix imports: Replace
from claude_agent_sdk import TodoWritewithfrom claude_agent_sdk import TaskCreate, TaskUpdate, TaskGet, TaskListand make sure the build passes first. - Update the tool list: Remove
TodoWritefrom the array passed totools=in your agent, add the four new tools, and setCLAUDE_CODE_ENABLE_TASKS=1as an environment variable before verifying behavior. - Replace call sites: Decompose existing
TodoWrite(todos=...)calls into sequentialTaskCreatecalls, and store the returnedtask_idvalues in a dictionary ordataclass. - Adapt return value handling: Update any code that previously read
todos[i].statusto use the return value schema ofTaskList()orTaskGet(task_id). - Update tests: Snapshot tests and VCR-based tests (which record and replay API responses) still hold the old API response JSON, so update those fixed values to the new schema.
The most error-prone step of the five is Step 4. Because the allowed values for status were standardized to pending / in_progress / completed / cancelled, any data saved under the old API with in-progress (hyphen) will fail to match. Writing a one-off migration script to normalize the status column in existing data to underscore-separated values is the safe move.
Pitfall — stderr Callback Separation and CancelledError
As discussed in claude-agent-sdk-python issue #309, v0.2.82 separates the stderr callback from the Task tool completion callback. If your old code used "Todo completion timing to also flush stderr," those two events now fire through separate paths in the new API, which can cause logs to appear out of order. Additionally, if you silently swallow asyncio.CancelledError inside an eager-flush completion callback, TaskUpdate can be left in a partially completed state, causing TaskList to return ghost tasks (empty tasks with no corresponding entity that persist in the TaskList). Fix your callback code to re-raise CancelledError.
The CLAUDE_CODE_ENABLE_TASKS=1 Flag and How to Roll Out in Stages
The new Task tools are introduced as an opt-in flag rather than being forced on immediately. The design lets you safely try the new API in a test environment before deploying to production. Enable the flag with the environment variable CLAUDE_CODE_ENABLE_TASKS=1.
# 1. Temporarily enable from the shell (for testing)
export CLAUDE_CODE_ENABLE_TASKS=1
python my_agent.py
# 2. Persist via a .env file
echo "CLAUDE_CODE_ENABLE_TASKS=1" >> .env
# 3. Pass explicitly when starting a headless session
CLAUDE_CODE_ENABLE_TASKS=1 python -m claude_agent_sdk.session start
Use Partial Enablement to Run an A/B Comparison
Since the flag can be toggled per session, you can run the same input through both the old and new paths and observe the differences — an effective A/B setup. Running this step once before production deployment lets you catch mismatches in return value schemas or missing status column normalization from real environment logs. In particular, leveraging the publicly available EffortLevel type documented in Anthropic's Agent SDK Python documentation lets you pipe type information directly into A/B comparison logs, improving clarity during review.
Recommended Rollout Phases for Your Team
A realistic rollout takes about one week and should proceed in the following order. Deploying to production all at once risks silently killing operational bots due to return value schema mismatches.
- Dev environment (Day 1-2): Set
CLAUDE_CODE_ENABLE_TASKS=1locally and in CI, then run tests and sample operation logs. - Staging (Day 3-4): Run headless sessions with production-equivalent data for 24 hours and compare
TaskListsnapshot diffs morning and evening. - Production canary (Day 5): Enable the flag for 10–20% of sessions and compare error rates, latency, and token usage against the old path.
- Full production rollout (Day 6-7): Enable the flag for all sessions and switch the SDK version pin to
==0.2.82. - Remove old API (Day 8+): Completely remove all
TodoWriteimports and related tests from the codebase.
Rollback Procedure — Two-Stage Recovery
If a problem surfaces after full rollout, use a two-stage rollback. Stage one is "remove the flag only." Stage two is "downgrade the SDK version itself to ==0.2.81." If removing the flag alone restores stability, recovery doesn't depend on the SDK release cycle and can be done quickly. Only proceed to stage two if a critical bug is found in the library itself. When rolling back in production, stopping TaskCreate calls via the Anthropic Console session log first will help prevent orphan tasks (tasks that persist in limbo even after the parent session is gone) from accumulating.
Best Practices and Tips After Migration — Stable Headless Session Operations
Once you've switched to the new API, there are four operational points to keep in mind. These aren't just about getting things "working" in the short term — they're about keeping things running reliably even as team members change over the next six months.
Use the Public EffortLevel Type for Type Safety
In v0.2.82, the EffortLevel type was made public, allowing you to import low / medium / high as three Literal types. This tightens type annotations for parameters passed to agents, enabling CI tools like mypy or pyright to catch typos such as EffortLevel = "med". Beyond using it as an argument to TaskCreate and TaskUpdate, embedding it in your own wrapper function signatures will help reduce accidents during headless operation.
Watch Out When Combining with MCP Server Background Connections
Claude Agent SDK Python includes a mechanism for connecting to MCP (Model Context Protocol) servers in the background, and there are some quirks when combining this with the new Task tools. Cases have been reported where TaskCreate fires first while the MCP connection is still at status: "pending", resulting in a ResourceNotReady exception when trying to reference an MCP resource immediately after a Task is created. The fix is to insert a small helper before TaskCreate that polls until the MCP status reaches ready.
Diffs Caused by the Bundled Claude CLI v2.1.142 Auto-Update
Installing Claude Agent SDK Python v0.2.82 also updates the bundled Claude CLI to v2.1.142. The CLI's help text and error message format have changed slightly, so any operational scripts that parse output via subprocess may find their regular expressions no longer match. Right after release, it's a good idea to pin the output of claude --version and claude --help in CI so you can detect unexpected diffs early.
Claude Code v2.1.143: Enforced Plugin Dependencies and the New worktree.bgIsolation: "none" Setting
The simultaneously announced Claude Code v2.1.143 enforces plugin dependency resolution, causing a startup error the moment a dependency not listed in package.json is required. It also introduces a new worktree.bgIsolation: "none" setting that gives teams running multiple worktrees in parallel the option to share background processes. If your team uses Claude Agent SDK Python together with Claude Code, it's recommended to audit Claude Code's package.json and configuration at the same time you update the SDK.