SpyBara
Go Premium

agent-sdk/todo-tracking.md 2026-09-08 20:00 UTC to 2026-09-09 22:58 UTC

This page contains 245 additions and 195 deletions.

2026
Wed 9 22:58 Thu 10 23:00 Sat 12 03:02

Rastrear tarefas

Rastreie tarefas em sessões do Agent SDK e renderize o progresso do Claude em sua aplicação a partir de chamadas de ferramentas estruturadas

Nos modelos listados em Disponibilidade de modelos, Claude rastreia trabalho com múltiplas etapas sem uma lista de tarefas escrita, e Claude Code deixa as ferramentas de rastreamento de tarefas fora das sessões por padrão. Você não precisa de nada nesta página para Claude trabalhar através de tarefas com múltiplas etapas nesses modelos.

Em uma sessão que possui as ferramentas de rastreamento de tarefas, Claude mantém uma lista de tarefas escrita, atualizando o status de cada item conforme trabalha. Você vê cada mudança no fluxo de mensagens como uma chamada de ferramenta estruturada. Opte por uma sessão apenas quando sua aplicação lê essas chamadas de ferramentas, seja para registrar atividade de tarefas ou para renderizar sua própria exibição de progresso.

Disponibilidade de modelos

Nos modelos listados, a menos que você opte por uma sessão, você não vê blocos tool_use para as ferramentas no fluxo de mensagens. O Agent SDK aplica esses padrões através do binário Claude Code que ele agrupa. Se você apontar pathToClaudeCodeExecutable (TypeScript) ou cli_path (Python) para sua própria instalação do Claude Code, você obtém quaisquer ferramentas que essa instalação fornece, sob seus próprios padrões. Para ver o conjunto exato em uma sessão em execução, verifique quais ferramentas estão disponíveis. Para optar por uma sessão, faça um dos seguintes:

  • Nomeie uma das ferramentas na opção allowedTools (TypeScript) ou allowed_tools (Python)
  • Liste as ferramentas na opção tools, que restringe as ferramentas integradas da sessão àquelas que ela nomeia. Inclua as ferramentas que você deseja junto com as outras ferramentas integradas que você usa
  • Defina CLAUDE_CODE_ENABLE_TODO_TOOLS=1 na opção env, como os exemplos nesta página fazem. No TypeScript, env substitui o ambiente do subprocesso, então espalhe ...process.env para manter variáveis herdadas. No Python, env é mesclado no topo do ambiente herdado

Ciclo de vida das tarefas

Claude move cada tarefa através de um ciclo de vida previsível:

  1. Criada: Claude adiciona a tarefa como pending quando identifica uma tarefa
  2. Ativada: Claude define a tarefa como in_progress quando inicia o trabalho
  3. Concluída: Claude marca como concluída quando a tarefa termina com sucesso
  4. Removida: Claude deleta uma tarefa que não precisa mais definindo status: "deleted" em uma chamada TaskUpdate

Quando Claude cria tarefas

Em uma sessão que possui as ferramentas de rastreamento de tarefas, Claude cria tarefas para a maioria dos trabalhos com múltiplas etapas, como:

  • Tarefas complexas com múltiplas etapas que exigem três ou mais ações distintas
  • Listas de tarefas fornecidas pelo usuário quando vários itens são mencionados
  • Operações mais longas que se beneficiam do rastreamento de progresso
  • Solicitações explícitas quando os usuários pedem organização de tarefas

Claude pode pular tarefas para solicitações muito curtas ou de uma única etapa.

Exemplos

Antes de executar estes exemplos, instale o Claude Agent SDK seguindo o guia de início rápido. Cada exemplo nesta página compartilha a mesma configuração de permissões e comportamento de saída:

  • Modo de permissão: os exemplos de prompt pedem ao Claude para fazer trabalho real em um projeto, então cada exemplo define permissionMode: "acceptEdits" (TypeScript) ou permission_mode="acceptEdits" (Python) para aprovar automaticamente as edições de arquivo que o trabalho produz. Veja Modos de permissão para as alternativas.
  • Limite de turnos: cada exemplo é executado até que o agente termine e produza sua mensagem de resultado final. Se uma sessão atingir seu limite de turnos primeiro, essa mensagem de resultado terá o subtipo error_max_turns. Verifique subtype para detectar esse encerramento.
  • Tratamento de erros: estes exemplos usam chamadas query() de um único disparo. Após produzir um resultado error_max_turns, query() lança um erro que inclui Reached maximum number of turns. Cada exemplo envolve seu loop em um bloco try para sair corretamente quando isso acontece. Veja Lidar com o resultado para os subtipos de resultado.

Monitorar mudanças de tarefas

O exemplo a seguir observa o fluxo do assistente para blocos tool_use TaskCreate e TaskUpdate e imprime uma linha + com o assunto de cada nova tarefa e uma linha de atualização com o ID da tarefa e o novo status de cada mudança de status. Use esta forma quando você deseja um registro de atividade de tarefas em vez de uma exibição renderizada. As linhas + não incluem os IDs atribuídos, então este registro não pode corresponder atualizações de volta às suas criações. Para manter essa correlação, capture os IDs como Exibir progresso em tempo real faz.

A entrada tool_use transmitida é a forma bruta que o modelo emitiu. Claude Code repara alguns nomes de chave próximos mas incorretos antes da execução, mapeando id ou task_id para taskId e active_form para activeForm, mas esse reparo não é refletido no fluxo. Leia os campos de entrada de TaskUpdate defensivamente, como ambos os exemplos nesta página fazem, em vez de assumir que o nome canônico está sempre presente.

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

try {
for await (const message of query({
prompt: "Create a static website with a home page, an about page, and a shared stylesheet, and track progress with todos",
// Keeps the Task tools on models where Claude Code otherwise doesn't provide them.
options: { maxTurns: 15, permissionMode: "acceptEdits", env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } },
})) {
if (message.type !== "assistant") continue;
for (const block of message.message.content) {
if (block.type !== "tool_use") continue;
if (block.name === "TaskCreate") {
const input = block.input as { subject: string };
console.log(`+ ${input.subject}`);
} else if (block.name === "TaskUpdate") {
const input = block.input as {
taskId?: string;
id?: string;
task_id?: string;
status?: string;
};
const taskId = input.taskId ?? input.id ?? input.task_id;
if (taskId && input.status) console.log(`  ${taskId} -> ${input.status}`);
}
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result.
console.log(`Session ended with an error: ${error}`);
}

Exibir progresso em tempo real

O exemplo a seguir observa o fluxo do assistente para blocos tool_use TaskCreate e TaskUpdate e mantém um mapa de tarefas codificadas por ID de tarefa em uma classe TaskTracker, renderizando novamente um resumo de progresso a cada mudança. O resumo conta tarefas concluídas e em progresso e mostra o rótulo activeForm de cada item ativo no lugar de seu subject. Use esta forma quando sua aplicação mantém uma exibição de progresso em vez de registrar cada evento.

O ID de tarefa atribuído não está na entrada de TaskCreate. Claude Code entrega a saída estruturada de cada ferramenta na mensagem do usuário que carrega seu bloco tool_result, no campo tool_use_result. Para TaskCreate, esse objeto é documentado para TypeScript como TaskCreateOutput em Tipos de Saída de Ferramenta, e em Python o campo é um dict simples da mesma forma. O rastreador emparelha cada bloco tool_result com sua chamada tool_use por tool_use_id e lê task.id da mensagem emparelhada tool_use_result. Claude pode ler a lista de volta com TaskList e os detalhes completos de uma tarefa com TaskGet.

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

type Task = { subject: string; activeForm?: string; status: string };

class TaskTracker {
private tasks = new Map<string, Task>();
private pendingCreates = new Map<string, { subject: string; activeForm?: string }>();

displayProgress() {
if (this.tasks.size === 0) {
console.log("\nProgress: no open tasks\n");
return;
}

const items = [...this.tasks.values()];
const completed = items.filter((t) => t.status === "completed").length;
const inProgress = items.filter((t) => t.status === "in_progress").length;

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

for (const [id, task] of this.tasks) {
const icon =
task.status === "completed" ? "✅" : task.status === "in_progress" ? "🔧" : "❌";
const text = task.status === "in_progress" && task.activeForm ? task.activeForm : task.subject;
console.log(`${id}. ${icon} ${text}`);
}
}

handleToolUse(block: { id: string; name: string; input: unknown }) {
if (block.name === "TaskCreate") {
const input = block.input as { subject: string; activeForm?: string; active_form?: string };
this.pendingCreates.set(block.id, {
subject: input.subject,
activeForm: input.activeForm ?? input.active_form,
});
} else if (block.name === "TaskUpdate") {
const input = block.input as {
taskId?: string;
id?: string;
task_id?: string;
status?: string;
activeForm?: string;
active_form?: string;
};
const taskId = input.taskId ?? input.id ?? input.task_id;
if (!taskId) return;
if (input.status === "deleted") {
this.tasks.delete(taskId);
this.displayProgress();
return;
}
const task = this.tasks.get(taskId);
if (!task) return;
if (input.status) task.status = input.status;
const active = input.activeForm ?? input.active_form;
if (active) task.activeForm = active;
this.displayProgress();
}
}

handleToolResult(block: { tool_use_id: string; is_error?: boolean }, result: unknown) {
const create = this.pendingCreates.get(block.tool_use_id);
if (!create) return;
this.pendingCreates.delete(block.tool_use_id);
if (block.is_error) return;
// The result's user message carries the tool's structured output as
// tool_use_result; for TaskCreate that's TaskCreateOutput,
// { task: { id, subject } }.
const out = result as { task?: { id: string } };
if (!out?.task?.id) return;
this.tasks.set(out.task.id, { ...create, status: "pending" });
this.displayProgress();
}

async trackQuery(prompt: string) {
try {
for await (const message of query({
prompt,
options: { maxTurns: 20, permissionMode: "acceptEdits", env: { ...process.env, CLAUDE_CODE_ENABLE_TODO_TOOLS: "1" } },
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "tool_use") this.handleToolUse(block);
}
}
if (message.type === "user" && Array.isArray(message.message.content)) {
for (const block of message.message.content) {
if (block.type === "tool_result") this.handleToolResult(block, message.tool_use_result);
}
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result,
// such as when the maxTurns limit is hit.
console.log(`Session ended with an error: ${error}`);
}
}
}

// Usage
const tracker = new TaskTracker();
await tracker.trackQuery("Build a complete authentication system with todos");