---
title: "Todo Tracking in the Agent SDK"
aliases: [todo-lists, todo-tracking, sdk-todos]
tags: [agent-sdk, todos, progress-tracking, typescript, workflow]
sources: [raw/Todo Lists.md]
created: 2026-04-17
updated: 2026-04-17
---

# Todo Tracking in the Agent SDK

Built-in todo functionality for managing multi-step workflows and displaying task progress to users. Todos are surfaced as `TodoWrite` tool calls in the [[wiki/agent-sdk/agent-loop|agent message stream]].

## Todo Lifecycle

| State | Meaning |
|-------|---------|
| `pending` | Task identified, not yet started |
| `in_progress` | Work actively underway |
| `completed` | Task finished successfully |
| *(removed)* | Cleared when all tasks in a group are done |

## When the SDK Creates Todos Automatically

- Complex multi-step tasks requiring **3+ distinct actions**
- User-provided **task lists** (multiple items mentioned)
- Non-trivial operations that benefit from progress visibility
- Explicit user requests for todo organization

## Monitoring Todo Changes

Todos appear in the message stream as `tool_use` blocks with `name === "TodoWrite"`:

```typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Optimize my React app performance and track progress with todos",
  options: { maxTurns: 15 }
})) {
  if (message.type === "assistant") {
    for (const block of message.message.content) {
      if (block.type === "tool_use" && block.name === "TodoWrite") {
        const todos = block.input.todos;
        todos.forEach((todo, index) => {
          const status =
            todo.status === "completed" ? "✅"
            : todo.status === "in_progress" ? "🔧"
            : "❌";
          console.log(`${index + 1}. ${status} ${todo.content}`);
        });
      }
    }
  }
}
```

## Real-time Progress Tracker (Class Pattern)

```typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

class TodoTracker {
  private todos: any[] = [];

  displayProgress() {
    if (this.todos.length === 0) return;

    const completed = this.todos.filter(t => t.status === "completed").length;
    const inProgress = this.todos.filter(t => t.status === "in_progress").length;
    const total = this.todos.length;

    console.log(`\nProgress: ${completed}/${total} completed`);
    console.log(`Currently working on: ${inProgress} task(s)\n`);

    this.todos.forEach((todo, index) => {
      const icon =
        todo.status === "completed" ? "✅"
        : todo.status === "in_progress" ? "🔧"
        : "❌";
      // in_progress todos expose an activeForm (present-tense description)
      const text = todo.status === "in_progress" ? todo.activeForm : todo.content;
      console.log(`${index + 1}. ${icon} ${text}`);
    });
  }

  async trackQuery(prompt: string) {
    for await (const message of query({ prompt, options: { maxTurns: 20 } })) {
      if (message.type === "assistant") {
        for (const block of message.message.content) {
          if (block.type === "tool_use" && block.name === "TodoWrite") {
            this.todos = block.input.todos;
            this.displayProgress();
          }
        }
      }
    }
  }
}

const tracker = new TodoTracker();
await tracker.trackQuery("Build a complete authentication system with todos");
```

### Notable Todo Fields

| Field | Notes |
|-------|-------|
| `content` | Task description (pending/completed) |
| `activeForm` | Present-tense description used when `in_progress` |
| `status` | `"pending"` \| `"in_progress"` \| `"completed"` |

## Key Takeaways

- Todos surface as **`TodoWrite` tool_use blocks** in the assistant message stream — intercept them the same way as any other tool call.
- The `activeForm` field gives a present-tense verb phrase for the active task, useful for UIs.
- Todos are created **automatically** for 3+ step tasks; no special configuration needed.
- Tracking state is ephemeral per session — persist `this.todos` externally if you need durable progress records.
- Pairs naturally with [[wiki/agent-sdk/streaming-output|streaming output]] for live progress UIs and [[wiki/agent-sdk/sdk-hooks|SDK hooks]] for side-effects on task transitions.

## Related

- [[wiki/agent-sdk/agent-loop|Agent Loop]] — how messages and tool calls flow
- [[wiki/agent-sdk/streaming-output|Streaming Output]] — real-time token/tool event handling
- [[wiki/agent-sdk/sdk-hooks|SDK Hooks]] — intercept tool calls pre/post execution
- [[wiki/agent-sdk/user-input-approvals|User Input & Approvals]] — `canUseTool` callback patterns

---

*Source: raw/Todo Lists.md — https://code.claude.com/docs/en/agent-sdk/todo-tracking*
