write_todos: A Guardrail, Not a To‑Do List, for Keeping Agents on Track

The article explains how the write_todos tool in Deep Agents serves as a process controller that breaks long tasks into observable steps, updates status in real time, and prevents agents from losing track, offering concrete guidelines, data structures, and best‑practice rules for effective task management.

Tech Ocean
Tech Ocean
Tech Ocean
write_todos: A Guardrail, Not a To‑Do List, for Keeping Agents on Track

Conclusion

write_todos

acts as a process controller for an agent: it splits a long task into discrete steps, marks the current step, and updates the status immediately after completion. This prevents the model from treating a long task as free‑form prose.

Real structure of a Todo

The source defines Todo as a TypedDict with only two fields:

class Todo(TypedDict):
    content: str
    status: Literal["pending", "in_progress", "completed"]

When an agent calls write_todos it passes a list of such dictionaries, for example:

[
    {"content": "梳理调用链", "status": "in_progress"},
    {"content": "定位需要修改的文件", "status": "pending"},
    {"content": "写单测覆盖边界条件", "status": "pending"},
]

Each call replaces the entire list; it is not a patch. Parallel calls can overwrite each other, which the source code warns against.

When the middleware applies automatically

TodoListMiddleware

injects system‑level rules that decide when a todo list should be created. The suitability criteria are:

Task has three or more steps (single‑step tasks are not suitable).

Planning is required before execution (very simple tasks with fewer than three steps are not suitable).

User explicitly asks for a todo list (casual chat or simple queries are not suitable).

Multiple todos are provided at once (if a todo list does not help the result, it is not suitable).

New subtasks may appear during execution (simple translation or single‑word changes are not suitable).

The author advises against forcing a todo list in the system_prompt, because it adds an unnecessary token round for trivial tasks.

Why status switching matters

The source lists four rules and their effects:

When a todo is created, its status is set to in_progress. Effect: the agent continues immediately instead of stopping after planning.

Mark a todo as completed as soon as the step finishes. Effect: the user sees progress.

As long as not all steps are done, at least one todo remains in_progress. Effect: the list stays "alive".

Do not mark a todo as completed when a blocker exists. Effect: failures remain visible.

Independent tasks can share the same in_progress status. Effect: parallel subtasks need not be serialized.

Example scenario – refactoring a Python module:

拆分任务
 → 阅读相关文件
 → 修改实现
 → 补测试
 → 跑验证
 → 更新结果

If a step fails, the todo status shows exactly where the agent got stuck.

Reading todo status

Todos are stored in the LangGraph state and can be read after the agent finishes:

from deepagents import create_deep_agent

agent = create_deep_agent(
    model="anthropic:claude-sonnet-4-6",
    system_prompt="你是一个项目助手,复杂任务先用 write_todos 规划。",
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "帮我把 user.py 拆成 model / repository / service 三层"}]
})

for todo in result.get("todos", []):
    print(f"[{todo['status']:^12}] {todo['content']}")

Typical output:

[ completed  ] 阅读 user.py 当前结构
[ completed  ] 抽出 User 数据类到 model.py
[in_progress ] 把数据库操作迁到 repository.py
[  pending   ] 业务逻辑迁到 service.py
[  pending   ] 跑测试验证

This line‑by‑line view is clearer than a single long model response.

What makes a good todo

A good todo should be:

Executable – e.g., 抽出 User 数据类到 model.py.

Sortable – each step follows a logical order.

Failure‑exposing – blockers generate additional steps instead of silently marking everything completed.

Bad examples include vague statements like "做完用户模块" or "处理一下测试" that do not specify concrete actions.

Control the number of items: 3–7 items are usually comfortable. Fewer than three often means the list is unnecessary; more than ten indicates overly fine granularity, turning the agent into a log‑keeping bot.

When the model’s context is tight it may lazily mark many items as completed. In that case verify the status against file diffs, test results, and tool outputs.

Author’s judgment on when to use write_todos

The decision criterion is simple: if the task can drift and the drift can be detected, use write_todos. Typical scenarios include code migration, bulk document organization, API integration, and automated test fixing. The guardrail does not make the model smarter; it makes the process explicit, allowing failures to be located more easily.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

process controllong-running tasksDeep AgentsAI task managementstatus trackingwrite_todos
Tech Ocean
Written by

Tech Ocean

Focused on AI programming, sharing ready-to-use development efficiency solutions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.