Agent Mentor Learn
Gerenciamento e persistência de estado: fazendo tarefas longas sobreviverem à interrupção · Lição 5 de 6

Lição 5: Rebobinar e bifurcar: o segundo valor dos checkpoints

Objetivos de aprendizado:

  • Explicar os dois usos proativos dos checkpoints para além da recuperação de desastre — rebobinar até uma cena anterior para tentar de novo e bifurcar uma segunda linha do tempo para explorar — e ver que ambos se apoiam na mesma sequência de checkpoints em que a retomada se apoia
  • Transformar o checkpoint de “guardar só o mais recente” em uma sequência retida por turno, implementar rewindTo(turn) e explicar que a rebobinagem reverte a cena da decisão, não os efeitos colaterais externos que já aconteceram
  • Implementar forkFrom(turn, branchName) para copiar uma linha do tempo independente a partir da mesma cena, e traçar as linhas divisórias entre o que cabe aos checkpoints, ao Git e ao livro-razão de efeitos

Pré-requisitos: você concluiu as Lições 1-4 e conhece o layout de campos do checkpoint.json (version, task, turns, tokensUsed, messages, pendingToolUse), além das gravações atômicas, de como a retomada reconcilia uma chamada órfã e do livro-razão de efeitos e das chaves de idempotência da Lição 4 | Anterior: Lição 4 << | Próxima: Lição 6 >>

Checkpoints não são só um fusível

As primeiras lições trataram os checkpoints como seguro contra desastre — o processo cai e você retoma o loop a partir do checkpoint mais recente. Nada de errado em usá-los assim, mas se a única hora em que você recorre a eles for depois de uma queda, eles ficam ociosos a maior parte do tempo. Não houve queda, então o estado que você salvou foi desperdiçado?

Não foi. Um encadeamento de checkpoints acumulados é, na verdade, uma linha do tempo da tarefa — o que ela estava pensando a cada turno, o que estava prestes a fazer, quais efeitos já tinha consumado, tudo deixado como rastro. Para além da recuperação de desastre, essa linha do tempo sustenta mais dois usos proativos: rebobinar até um turno anterior para começar de novo, e bifurcar a partir de um turno para rodar uma segunda rota em paralelo à primeira. Um roteiro comunitário organizado em torno da engenharia de harness resume o componente de persistência amarrando exatamente esses três: fazer checkpoint do estado em cada nó para que você possa retomar, rebobinar, bifurcar1. Essa é uma afirmação de enquadramento do roteiro — ela não prescreve uma implementação —, mas aponta para uma coisa: a retomada é apenas um terço daquilo para que os checkpoints servem, e os outros dois são o assunto desta lição.

  • Rebobinagem: a tarefa não caiu, mas saiu do rumo. Reverta a cena da decisão para um turno anterior ao ponto em que ela deu errado e comece de novo.
  • Bifurcação: você não tem certeza de qual rota é melhor, então copia duas linhas do tempo independentes a partir da mesma cena, roda cada uma e escolhe o resultado.

Nenhuma das duas é “faxina depois de um desastre” — ambas podem aparecer com a tarefa correndo perfeitamente bem.

Rebobinagem: reverter a cena da decisão, não o mundo externo

Imagine uma tarefa que roda uns 20 turnos de chamadas de ferramenta. No turno 15, o modelo toma uma decisão ruim — escolhe o arquivo errado para editar, ou faz uma suposição equivocada sobre um requisito vago. Pelos 10 turnos seguintes, ele segue construindo em cima daquele erro. O Curso 8 desta série, "Context Engineering: Spending Finite Attention Where It Counts", mostrou que, conforme o contexto se acumula mais longo e mais bagunçado, a capacidade do modelo de recuperar informação dali com precisão despenca — e este trecho de histórico carrega uma decisão errada por cima disso. Em vez de deixar o modelo continuar se debatendo dentro de um contexto longo e fora do rumo, reverta a cena para o turno 14, o ponto anterior à decisão ruim, e comece de novo dali.

Para fazer isso, um checkpoint não pode mais ser “só o mais recente”. O saveCheckpoint das lições anteriores sobrescrevia o mesmo checkpoint.json toda vez, então na recuperação você só conseguia obter o último estado escrito — suficiente para recuperação de desastre, mas inútil para rebobinar, porque a cena do turno 14 havia sido sobrescrita pelo turno 15 muito antes. Para sustentar a rebobinagem, os checkpoints têm de ser retidos como uma sequência por turno, com o número do turno e o ponto de gravação no nome do arquivo: checkpoints/turn-014-A.json, checkpoints/turn-014-B.json e assim por diante. Dentro de cada turno, o ponto de gravação A cai quando o modelo propôs seu plano mas a ferramenta ainda não rodou; o ponto de gravação B cai quando o resultado da ferramenta daquele turno é escrito de volta em messages e o turno de fato terminou. Por padrão, “volte ao turno N” significa a cena depois que aquele turno terminou — ou seja, o último ponto de gravação escrito naquele turno:

Com a cena que rewindTo(14) devolve, o que vem em seguida é o mesmo fluxo da retomada: use este messages para reconstruir o histórico e continue o loop a partir desta contagem de turns. A única diferença é que desta vez o modelo encara uma cena limpa, anterior à decisão tomada, e não o contexto que o turno 15 poluiu.

Mas uma coisa merece ser dita em voz alta: a rebobinagem reverte a cena da decisão, não o mundo externo. Se a decisão ruim do turno 16 já chamou uma ferramenta de alto impacto — enviou de fato um e-mail, digamos —, rebobinar para o turno 14 não traz aquele e-mail de volta. Um checkpoint guarda messages, turns, pendingToolUse e quaisquer outros campos de estado que você tenha definido no instantâneo; ele nunca foi feito para desfazer uma ação externa que já caiu, e não consegue fazê-lo. O livro-razão de efeitos da Lição 4 (effects.json) segue cumprindo sua regra de somente acréscimo: depois de você rebobinar e reexecutar a partir do turno 15, mesmo que o modelo escolha desta vez uma ação completamente diferente, o livro-razão apenas ganha um registro novo — ele não apaga o antigo. O que quer que tenha acontecido nos dez turnos descartados continua deixando seu rastro no livro-razão, que é exatamente a visão de idempotência da Lição 4 levada para o cenário da rebobinagem.

Bifurcação: rodar duas linhas do tempo a partir de uma cena

A rebobinagem resolve “esta rota estava errada, volte e refaça”. Mas às vezes a pergunta não é “estava errada”, é “não tenho certeza de qual é melhor” — dois planos de refatoração ambos fazem sentido, e você quer rodar cada um e comparar antes de escolher. Nesse caso, não escolha um destrutivamente; copie duas linhas do tempo independentes a partir do mesmo checkpoint e rode cada uma:

Depois de forkFrom(14, "plan-b"), checkpoints-plan-b/ tem a própria sequência de checkpoints e um livro-razão de efeitos em branco. Do turno 14 em diante, para onde esta linha do tempo vai, quantos turnos ela roda, quantos checkpoints ela deixa — nada disso interfere na linha principal.

O fato de as duas linhas do tempo bifurcadas serem independentes é um alerta para ferramentas de alto impacto: se ambas as linhas fossem chamar a mesma ação genuinamente externa — ambas precisam enviar o mesmo e-mail, digamos —, deixar cada uma correr até o fim sem aprovação significa que cada linha o envia uma vez, o que vira um efeito colateral dobrado. Ligar uma válvula de aprovação em ferramentas assim, ou passar para um modo de dry-run durante a bifurcação, vale a pena antes de bifurcar. É o mesmo raciocínio do livro-razão não ser revertido na rebobinagem: um checkpoint pode ser copiado em dois, mas um efeito externo que já caiu não pode ser copiado em “um por mundo paralelo”.

Comparação com produto: o Claude Code entregou isto como funcionalidade

A rebobinagem e a bifurcação acima são algo que o Claude Code já entrega como funcionalidade de nível de produto — isto é só para comparação, não a ferramenta que está sendo ensinada. O mecanismo de checkpointing dele captura automaticamente o estado do seu código antes de cada prompt do usuário2: cada prompt do usuário cria um novo checkpoint2, e o Claude Code salva os checkpoints junto com a conversa, de modo que você ainda pode rodar /rewind depois de retomar uma sessão2.

O menu /rewind dele divide “o que restaurar” em três opções: "Restore conversation: rewind to that message while keeping current code", "Restore code: revert file changes while keeping the conversation", ou "Restore code and conversation: revert both code and conversation to that point"2 (na ordem: rebobinar a conversa até aquela mensagem mantendo o código atual; reverter as mudanças de arquivo mantendo a conversa; reverter código e conversa até aquele ponto) — que é justamente a versão produtizada da frase desta lição, “a rebobinagem reverte a cena da decisão”. Você pode escolher reverter só a cena da decisão (a conversa), ou reverter o código junto. A documentação oficial também lista alguns casos de uso comuns do checkpointing, como "Exploring alternatives: try different implementation approaches without losing your starting point" (explorar alternativas: experimentar abordagens de implementação diferentes sem perder o seu ponto de partida) e "Recovering from mistakes: quickly undo changes that introduced bugs or broke functionality"2 (recuperar-se de erros: desfazer rapidamente mudanças que introduziram bugs ou quebraram funcionalidades). Vale notar: esses documentos de casos de uso estão listados genericamente sob checkpointing (/rewind), não separados entre “rebobinagem” e “bifurcação”. Mas, confrontados com os dois usos desta lição — “deu errado, volte e refaça” e “não tenho certeza, bifurque e experimente” —, a direção coincide.

Do lado da bifurcação, o Claude Code oferece /branch ou claude --continue --fork-session: "To branch off and try a different approach while preserving the original session intact, use /branch or claude --continue --fork-session"2 (para ramificar e experimentar uma abordagem diferente preservando intacta a sessão original, use /branch ou claude --continue --fork-session).

Fronteiras e divisão de trabalho: o que cabe a checkpoints, ao Git e ao livro-razão de efeitos

A documentação do Claude Code também traça uma fronteira própria: o checkpointing dele "does not track files modified by bash commands"2 (não rastreia arquivos modificados por comandos bash), e "Only direct file edits made through Claude's file editing tools are tracked"2 (apenas edições diretas de arquivo feitas pelas ferramentas de edição do Claude são rastreadas). Pela mesma lógica, os checkpoints do seu próprio harness cobrem apenas os campos de estado que você definiu explicitamente no instantâneo — messages, turns, tokensUsed, pendingToolUse. Mudanças que uma ferramenta fez no mundo externo — escrever em um banco de dados, chamar outro serviço, enviar um e-mail — não são da conta de um checkpoint. Esse é o trabalho do livro-razão de efeitos.

A documentação oficial enuncia o papel do mecanismo sem rodeios: checkpoints são projetados para recuperação rápida em nível de sessão e, para histórico de longo prazo e colaboração, você deveria "continue using version control, such as Git, for commits, branches, and long-term history."2 (seguir usando controle de versão, como o Git, para commits, ramificações e histórico de longo prazo). Aos três cabem trechos separados, e fica mais claro lado a lado:

MecanismoO que lhe cabeEscala de tempo
CheckpointA cena corrente — messages, contagem de turnos, a chamada de ferramenta ainda não executadaMinutos, nível de sessão
GitO histórico do próprio código — commits, ramificações, colaboraçãoPermanente, colaborativo
Livro-razão de efeitosEfeitos colaterais externos que já aconteceram — e-mails enviados, registros escritosSomente acréscimo, guardado permanentemente

Custo de retenção: escolha seu trade-off

Reter uma sequência de checkpoints por turno não é de graça — dois pontos de gravação por turno e, quanto mais tempo a tarefa roda, mais arquivos se acumulam no disco. O princípio da Anthropic de que "you should consider adding complexity only when it demonstrably improves outcomes"3 (você deveria considerar acrescentar complexidade apenas quando isso comprovadamente melhorar os resultados) se aplica igualmente aqui. Se a tarefa roda só alguns turnos e raramente precisa de uma rebobinagem, guardar a sequência inteira pode custar mais do que vale — como nas lições anteriores, guardar só o mais recente basta. Do outro lado, se a tarefa roda dezenas de turnos e rotineiramente precisa rebobinar ou bifurcar para experimentar algumas abordagens, a sequência que você guarda justifica seu lugar: quando algo dá errado você não precisa começar do zero, e o custo de tentativa e erro cai. Isto é, no fim das contas, um julgamento proporcional ao tamanho da tarefa, não uma questão de qual abordagem é intrinsecamente certa.

Recapitulação

  • Checkpoints não são apenas seguro contra desastre: um encadeamento retido de checkpoints é a linha do tempo da tarefa e, para além da retomada, eles sustentam rebobinagem e bifurcação — um roteiro comunitário enquadra esses três juntos como aquilo que cabe ao componente de persistência1
  • A rebobinagem reverte a cena da decisão, não o mundo externo: ações externas que realmente aconteceram não são desfeitas pela rebobinagem, e o livro-razão de efeitos segue somente acréscimo — a visão de idempotência da Lição 4 levada para o cenário da rebobinagem
  • Sustentar a rebobinagem exige que os checkpoints sejam retidos como uma sequência por turno (como turn-014-A/B.json) em vez de sobrescritos para guardar só o mais recente; rewindTo(turn) assume por padrão o último ponto de gravação escrito naquele turno
  • A bifurcação copia linhas do tempo independentes a partir da mesma cena, cada uma com a própria sequência de checkpoints e o próprio livro-razão de efeitos. Se ambas as linhas fossem acionar a mesma ferramenta de alto impacto, lembre-se de ligar uma válvula de aprovação ou passar para o modo dry-run — do contrário são efeitos colaterais dobrados
  • O Claude Code já entrega rebobinagem e bifurcação como funcionalidades de produto: checkpoints criados automaticamente por prompt, /rewind capaz de restaurar conversa ou código separadamente, /branch e --fork-session para bifurcar2. Mas ele traça a própria fronteira — rastreia apenas edições vindas das ferramentas de edição de arquivo do próprio Claude, não mudanças por comando bash2, e se posiciona como recuperação rápida em nível de sessão, com o Git continuando a responder por histórico de longo prazo e colaboração2
  • Três trabalhos diferentes: aos checkpoints cabe a cena corrente em escala de minutos, ao Git cabe o histórico permanente e colaborativo do código, ao livro-razão de efeitos cabem os efeitos colaterais externos que já aconteceram. Reter uma sequência completa de checkpoints por turno tem custo de disco; se vale a pena depende da escala da tarefa, não de qual abordagem é intrinsecamente certa3

>> Lição 6: Mão na massa: soldando checkpoint e retomada no harness

Footnotes

  1. The 2026 Agent Engineering Roadmap — GitHub (codejunkie99/agent-roadmap-2026) — https://github.com/codejunkie99/agent-roadmap-2026 2

  2. Checkpointing — Claude Code Docs — https://code.claude.com/docs/en/checkpointing 2 3 4 5 6 7 8 9 10 11 12

  3. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2

Exercícios

01

Para cada um dos quatro cenários abaixo, o que você deveria usar — rebobinagem, retomada, bifurcação ou Git? Responda cada um e dê seu raciocínio.

Nível 1: Quatro cenários, escolha a ferramenta certa
  1. Uma tarefa rodou uns 20 turnos e você percebe que o modelo escolheu o plano de refatoração errado no turno 12. Os turnos seguintes todos construíram em cima daquele plano errado, mas o próprio processo continua rodando bem, sem queda.
  2. A mesma tarefa chegou ao turno 18, a máquina hospedeira foi reiniciada, o processo foi morto por inteiro e nada terminou.
  3. Você não tem certeza se divide um módulo em dois serviços ou em três, e quer que o agente rode cada plano uma vez para você comparar os resultados.
  4. Você quer saber como este código estava três dias atrás, e quem o mudou e quando.
Critérios de conclusão · marcado localmente
02

O código abaixo é a versão antiga das lições anteriores: ela sobrescreve o mesmo checkpoint.json toda vez, então sustenta retomada mas não rebobinagem. Reescreva-o do jeito que esta lição exige: nomes de arquivo seguindo a regra de retenção por turno turn-NNN-A.json / turn-NNN-B.json; forneça um loadLatest() para a retomada que assume por padrão o último ponto de gravação escrito no turno mais recente; e forneça um rewindTo(turn) que pega a cena de um turno específico. Depois de terminar, escreva a verificação: salve 5 turnos em sequência, chame rewindTo(3) e confirme que o turns da cena devolvida é 3 e que o comprimento do livro-razão de efeitos effects.json não foi revertido.

Nível 2: Transforme saveCheckpoint em uma sequência por turno
Critérios de conclusão · marcado localmente