Trabalhar com sessões
Como as sessões persistem o histórico de conversas do agente e quando usar continue, resume e fork para retornar a uma execução anterior.
Uma sessão é o histórico de conversas que o SDK acumula enquanto seu agente trabalha. Ela contém seu prompt, cada chamada de ferramenta que o agente fez, cada resultado de ferramenta e cada resposta. O SDK a escreve em disco automaticamente para que você possa retornar a ela mais tarde.
Retornar a uma sessão significa que o agente tem contexto completo de antes: arquivos que já leu, análises que já realizou, decisões que já tomou. Você pode fazer uma pergunta de acompanhamento, se recuperar de uma interrupção ou ramificar para tentar uma abordagem diferente.
As sessões persistem a conversa, não o sistema de arquivos. Para capturar e reverter alterações de arquivo que o agente fez, use file checkpointing.
Este guia cobre como escolher a abordagem certa para seu aplicativo, as interfaces do SDK que rastreiam sessões automaticamente, como capturar IDs de sessão e usar resume e fork manualmente, e o que você precisa saber sobre retomar sessões entre hosts.
Escolha uma abordagem
Quanto gerenciamento de sessão você precisa depende da forma do seu aplicativo. O gerenciamento de sessão entra em jogo quando você envia múltiplos prompts que devem compartilhar contexto. Dentro de uma única chamada query(), o agente já faz quantas voltas precisar, e prompts de permissão e AskUserQuestion são tratados em loop (eles não encerram a chamada).
| O que você está construindo | O que usar |
|---|---|
| Tarefa única: prompt único, sem acompanhamento | Nada extra. Uma chamada query() resolve. |
| Chat multi-turno em um processo | ClaudeSDKClient (Python) ou continue: true (TypeScript). O SDK rastreia a sessão para você sem nenhum tratamento de ID. |
| Retomar de onde parou após reinicialização do processo | continue_conversation=True (Python) / continue: true (TypeScript). Retoma a sessão mais recente no diretório, sem necessidade de ID. |
| Retomar uma sessão passada específica (não a mais recente) | Capture o ID da sessão e passe para resume. |
| Tentar uma abordagem alternativa sem perder a original | Faça fork da sessão. |
| Tarefa sem estado, não quer nada escrito em disco | Defina persistSession: false (apenas TypeScript). A sessão existe apenas na memória durante a chamada. Em Python, defina CLAUDE_CODE_SKIP_PROMPT_HISTORY na opção env para suprimir escritas de transcrição. |
Continue, resume e fork
Continue, resume e fork são campos de opção que você define em query() (ClaudeAgentOptions em Python, Options em TypeScript).
Continue e resume ambos retomam uma sessão existente e adicionam a ela. A diferença é como eles encontram essa sessão:
- Continue encontra a sessão mais recente no diretório atual. Você não rastreia nada. Funciona bem quando seu aplicativo executa uma conversa por vez.
- Resume recebe um ID de sessão específico. Você rastreia o ID. Necessário quando você tem múltiplas sessões (por exemplo, uma por usuário em um aplicativo multi-usuário) ou quer retornar a uma que não é a mais recente.
Fork é diferente: cria uma nova sessão que começa com uma cópia do histórico da original. A original permanece inalterada. Use fork para tentar uma direção diferente enquanto mantém a opção de voltar.
Gerenciamento automático de sessão
Ambos os SDKs oferecem uma interface que rastreia o estado da sessão para você entre chamadas, para que você não passe IDs manualmente. Use-os para conversas multi-turno dentro de um único processo.
Python: `ClaudeSDKClient`
ClaudeSDKClient trata IDs de sessão internamente. Cada chamada para client.query() continua automaticamente a mesma sessão. Chame client.receive_response() para iterar sobre as mensagens da consulta atual. Use o cliente como um gerenciador de contexto assíncrono para que a configuração e encerramento da conexão sejam tratados para você, ou chame connect() e disconnect() manualmente.
Este exemplo executa duas consultas contra o mesmo client. A primeira pede ao agente para analisar um módulo; a segunda pede para refatorar esse módulo. Como ambas as chamadas passam pela mesma instância do cliente, a segunda consulta tem contexto completo da primeira sem nenhum resume ou ID de sessão explícito:
import asyncio
from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
ResultMessage,
TextBlock,
)
def print_response(message):
"""Print only the human-readable parts of a message."""
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(message, ResultMessage):
cost = (
f"${message.total_cost_usd:.4f}"
if message.total_cost_usd is not None
else "N/A"
)
print(f"[done: {message.subtype}, cost: {cost}]")
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob", "Grep"],
)
async with ClaudeSDKClient(options=options) as client:
# First query: client captures the session ID internally
await client.query("Analyze the auth module")
async for message in client.receive_response():
print_response(message)
# Second query: automatically continues the same session
await client.query("Now refactor it to use JWT")
async for message in client.receive_response():
print_response(message)
asyncio.run(main())
Cada consulta imprime a resposta de texto do agente seguida por uma linha de status da mensagem de resultado, como [done: success, cost: $0.0042].
Veja a referência do SDK Python para detalhes sobre quando usar ClaudeSDKClient versus a função query() independente.
TypeScript: `continue: true`
O SDK TypeScript não tem um objeto cliente que mantém sessão como o ClaudeSDKClient do Python. Em vez disso, passe continue: true em cada chamada query() subsequente e o SDK retoma a sessão mais recente no diretório atual. Nenhum rastreamento de ID necessário.
Este exemplo faz duas chamadas query() separadas. A primeira cria uma sessão nova; a segunda define continue: true, que diz ao SDK para encontrar e retomar a sessão mais recente em disco. O agente tem contexto completo da primeira chamada:
import { query } from "@anthropic-ai/claude-agent-sdk";
// First query: creates a new session
try {
for await (const message of query({
prompt: "Analyze the auth module",
options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result,
// so the follow-up query below still runs.
console.error(`Session ended with an error: ${error}`);
}
// Second query: continue: true resumes the most recent session
for await (const message of query({
prompt: "Now refactor it to use JWT",
options: {
continue: true,
allowedTools: ["Read", "Edit", "Write", "Glob", "Grep"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
A API de sessão V2 experimental, que fornecia createSession() com um padrão send / stream, foi removida no TypeScript Agent SDK 0.3.142. Use a função query() e as opções de sessão descritas nesta página.
Use opções de sessão com `query()`
Capture o ID da sessão
Resume e fork requerem um ID de sessão. Leia-o do campo session_id na mensagem de resultado (ResultMessage em Python, SDKResultMessage em TypeScript), que está presente em cada resultado independentemente de sucesso ou erro. Em TypeScript, o ID também está disponível mais cedo como um campo direto na SystemMessage de inicialização; em Python, está aninhado dentro de SystemMessage.data.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
session_id = None
try:
async for message in query(
prompt="Analyze the auth module and suggest improvements",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
),
):
if isinstance(message, ResultMessage):
session_id = message.session_id
if message.subtype == "success":
print(message.result)
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the loop above already captured session_id;
# connection or process failures yield no result message, so session_id stays None.
print(f"Session ended with an error: {error}")
print(f"Session ID: {session_id}")
return session_id
session_id = asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
try {
for await (const message of query({
prompt: "Analyze the auth module and suggest improvements",
options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
if (message.type === "result") {
sessionId = message.session_id;
if (message.subtype === "success") {
console.log(message.result);
}
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, the loop above already captured sessionId;
// connection or process failures yield no result message, so sessionId stays undefined.
console.error(`Session ended with an error: ${error}`);
}
console.log(`Session ID: ${sessionId}`);
Quando a consulta é concluída, o script imprime a resposta do agente seguida por uma linha como Session ID: 5b3f2c1a-8d4e-4f6b-9a7c-2e1d0f9b8a6c. Nas próximas seções, você passa esse ID para resume.
Retomar por ID
Passe um ID de sessão para resume para retornar a essa sessão específica. O agente retoma com contexto completo de onde a sessão parou. Razões comuns para retomar:
- Acompanhamento de uma tarefa concluída. O agente já analisou algo; agora você quer que ele aja com base nessa análise sem reler arquivos.
- Recuperação de um limite. A primeira execução terminou com
error_max_turnsouerror_max_budget_usd(veja Handle the result); retome com um limite mais alto. Em uma chamadaquery()de um único disparo, o SDK lança após ceder esse resultado de erro, então capture o erro antes de retomar. - Reiniciar seu processo. Você capturou o ID antes do desligamento e quer restaurar a conversa.
Este exemplo retoma a sessão de Capture o ID da sessão com um prompt de acompanhamento. Como você está retomando, o agente já tem a análise anterior em contexto:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
session_id = "..." # The ID you captured in the previous example
async def main():
# Earlier session analyzed the code; now build on that analysis
async for message in query(
prompt="Now implement the refactoring you suggested",
options=ClaudeAgentOptions(
resume=session_id,
allowed_tools=["Read", "Edit", "Write", "Glob", "Grep"],
),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
const sessionId = "..."; // The ID you captured in the previous example
// Earlier session analyzed the code; now build on that analysis
for await (const message of query({
prompt: "Now implement the refactoring you suggested",
options: {
resume: sessionId,
allowedTools: ["Read", "Edit", "Write", "Glob", "Grep"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
Você deve ver uma resposta que se baseia na análise anterior em vez de começar do zero. Isso confirma que o agente retomou a sessão com seu contexto anterior intacto.
Claude Code armazena sessões em ~/.claude/projects/<encoded-cwd>/*.jsonl. Se você definir a variável de ambiente CLAUDE_CONFIG_DIR, procure em $CLAUDE_CONFIG_DIR/projects/ em vez disso.
Para encontrar o diretório da sua sessão, substitua cada caractere não alfanumérico no diretório de trabalho absoluto por -: /Users/me/proj se torna -Users-me-proj. Para um diretório de trabalho cujo nome convertido excede 200 caracteres, Claude Code trunca o nome e anexa um hash, então corresponda aos primeiros 200 caracteres do nome convertido quando você listar projects/.
Se você definir CLAUDE_CODE_PROJECT_DIR_NAME ao lado de CLAUDE_CONFIG_DIR, procure sob esse nome em projects/ em vez disso. Requer Agent SDK TypeScript v0.3.234 ou posterior, ou Agent SDK Python v0.2.140 ou posterior.
Você pode retomar de qualquer diretório de trabalho:
- Busca entre diretórios: Claude Code procura além do diretório do projeto atual para encontrar o ID; veja Resume a session para a ordem exata de busca e como cópias duplicadas são tratadas.
- Mesma máquina apenas: o arquivo de sessão ainda precisa existir na máquina atual.
Antes da v2.1.223, a busca era limitada ao diretório do projeto atual e seus git worktrees; versões do SDK que agrupam uma CLI mais antiga ainda se comportam dessa forma.
Para retomar sessões entre máquinas ou em ambientes sem servidor, espelhe transcrições para armazenamento compartilhado com um adaptador SessionStore.
Fork para explorar alternativas
Forking cria uma nova sessão que começa com uma cópia do histórico da original, mas diverge a partir desse ponto. O fork recebe seu próprio ID de sessão; o ID e histórico da original permanecem inalterados. Você acaba com duas sessões independentes que pode retomar separadamente.
Forking ramifica o histórico de conversas, não o sistema de arquivos. Se um agente com fork editar arquivos, essas alterações são reais e visíveis para qualquer sessão trabalhando no mesmo diretório. Para ramificar e reverter alterações de arquivo, use file checkpointing.
Este exemplo se baseia em Capture o ID da sessão: você já analisou um módulo de autenticação em session_id e quer explorar OAuth2 sem perder o thread focado em JWT. O primeiro bloco faz fork da sessão e captura o ID do fork (forked_id); o segundo bloco retoma o session_id original para continuar pelo caminho JWT. Você agora tem dois IDs de sessão apontando para dois históricos separados:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
session_id = "..." # The ID you captured in the previous example
async def main():
# Fork: branch from session_id into a new session
forked_id = None
try:
async for message in query(
prompt="Instead of JWT, outline how OAuth2 would work for the auth module",
options=ClaudeAgentOptions(
resume=session_id,
fork_session=True,
max_turns=5,
),
):
if isinstance(message, ResultMessage):
forked_id = message.session_id # The fork's ID, distinct from session_id
if message.subtype == "success":
print(message.result)
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, forked_id was already captured by the
# loop above; connection or process failures yield no result message.
print(f"Session ended with an error: {error}")
print(f"Forked session: {forked_id}")
# Original session is untouched; resuming it continues the JWT thread
try:
async for message in query(
prompt="Continue with the JWT approach",
options=ClaudeAgentOptions(resume=session_id),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
except Exception as error:
# A single-shot query() raises after yielding an error result.
print(f"Session ended with an error: {error}")
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
const sessionId = "..."; // The ID you captured in the previous example
// Fork: branch from sessionId into a new session
let forkedId: string | undefined;
try {
for await (const message of query({
prompt: "Instead of JWT, outline how OAuth2 would work for the auth module",
options: {
resume: sessionId,
forkSession: true,
maxTurns: 5
}
})) {
if (message.type === "system" && message.subtype === "init") {
forkedId = message.session_id; // The fork's ID, distinct from sessionId
}
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, forkedId was already captured by the loop
// above; connection or process failures yield no result message.
console.error(`Session ended with an error: ${error}`);
}
console.log(`Forked session: ${forkedId}`);
// Original session is untouched; resuming it continues the JWT thread
try {
for await (const message of query({
prompt: "Continue with the JWT approach",
options: { resume: sessionId }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result.
console.error(`Session ended with an error: ${error}`);
}
Você deve ver que forkedId difere do ID de sessão original. Retomar a sessão original ainda continua o thread JWT, o que confirma que o fork não modificou o histórico original.
Retomar entre hosts
Os arquivos de sessão são locais para a máquina que os criou. Para retomar uma sessão em um host diferente (workers de CI, contêineres efêmeros, sem servidor), escolha a abordagem que se adequa:
-
Passe um armazenamento de sessão. Anexe um adaptador
sessionStore/session_storepara que o SDK espelhe transcrições para seu próprio backend e outro host possa retomá-las. A chave de busca do armazenamento é derivada do diretório de trabalho, portanto retome a partir de umcwdque corresponda à execução original. -
Mova o arquivo de sessão. Persista
~/.claude/projects/<encoded-cwd>/<session-id>.jsonlda primeira execução e restaure-o dentro de qualquer diretório em~/.claude/projects/no novo host antes de chamarresume.Claude Code procura além do diretório do projeto atual para encontrar o ID; consulte Retomar uma sessão para a ordem exata de busca e como cópias duplicadas são tratadas. Antes da v2.1.223, a busca era limitada ao diretório do projeto atual e seus git worktrees; versões do SDK que agrupam uma CLI mais antiga ainda se comportam dessa forma.
-
Não confie em retomada de sessão. Capture os resultados que você precisa (saída de análise, decisões, diffs de arquivo) como estado do aplicativo e passe-os para o prompt de uma sessão nova. Isso geralmente é mais robusto do que enviar arquivos de transcrição.
Ambos os SDKs expõem funções para enumerar sessões em disco e ler suas mensagens: listSessions() e getSessionMessages() em TypeScript, list_sessions() e get_session_messages() em Python. Use-os para construir seletores de sessão personalizados, lógica de limpeza ou visualizadores de transcrição.
Ambos os SDKs também expõem funções para procurar e mutar sessões individuais: get_session_info(), rename_session() e tag_session() em Python, e getSessionInfo(), renameSession() e tagSession() em TypeScript. Use-os para organizar sessões por tag ou dar-lhes títulos legíveis por humanos.
Recursos relacionados
- How the agent loop works: Entenda voltas, mensagens e acumulação de contexto dentro de uma sessão
- File checkpointing: Faça snapshot e reverta alterações de arquivo que o agente fez dentro de uma sessão
- Python
ClaudeAgentOptions: Referência completa de opções de sessão para Python - TypeScript
Options: Referência completa de opções de sessão para TypeScript