Agent Mentor Learn
Gestión de estado y persistencia: que las tareas largas sobrevivan a una interrupción · Lección 5 de 6

Lección 5: Rebobinar y bifurcar: el segundo valor de los puntos de control

Objetivos de aprendizaje:

  • Explicar los dos usos proactivos de los puntos de control más allá de la recuperación ante desastres —rebobinar a una escena anterior para reintentar y bifurcar una segunda línea temporal para explorar— y ver que ambos descansan sobre la misma secuencia de puntos de control que la reanudación
  • Convertir los puntos de control de «conservar solo el último» a una secuencia retenida por turno, implementar rewindTo(turn) y explicar que rebobinar revierte la escena de decisión, no los efectos secundarios externos que ya ocurrieron
  • Implementar forkFrom(turn, branchName) para copiar una línea temporal independiente desde la misma escena, y trazar las líneas divisorias entre lo que le corresponde a los puntos de control, a Git y al registro de efectos

Requisitos: Terminaste las Lecciones 1 a 4 y conoces la disposición de campos de checkpoint.json (version, task, turns, tokensUsed, messages, pendingToolUse) más las escrituras atómicas, cómo la reanudación concilia una llamada colgante, y el registro de efectos y las claves de idempotencia de la Lección 4 | Anterior: Lección 4 << | Siguiente: Lección 6 >>

Los puntos de control no son solo un fusible

Las primeras lecciones trataron los puntos de control como un seguro contra el desastre: el proceso se cae y retomas el bucle desde el punto de control más reciente. Nada de malo en usarlos así, pero si el único momento en que echas mano de ellos es después de una caída, están ociosos la mayor parte del tiempo. No hubo caída, entonces ¿el estado que guardaste se desperdició?

No se desperdició. Una hilera de puntos de control acumulados es en realidad una línea temporal de la tarea: qué estaba pensando en cada turno, qué estaba por hacer, qué efectos ya había confirmado, todo dejado como rastro. Más allá de la recuperación ante desastres, esa línea temporal sostiene dos usos más proactivos: rebobinar a un turno anterior para empezar de nuevo, y bifurcar desde un turno para ejecutar una segunda ruta en paralelo con la primera. Una hoja de ruta comunitaria construida alrededor de la ingeniería del arnés resume el componente de persistencia atando exactamente esos tres: guardar el estado en un punto de control en cada nodo para poder reanudar, rebobinar y bifurcar1. Es una nota de encuadre de la hoja de ruta —no prescribe una implementación—, pero señala una cosa: la reanudación es apenas un tercio de para qué sirven los puntos de control, y los otros dos son el tema de esta lección.

  • Rebobinar: la tarea no se cayó, pero se salió del camino. Revierte la escena de decisión a un turno anterior al desvío y empieza de nuevo.
  • Bifurcar: no estás seguro de qué ruta es mejor, así que copias dos líneas temporales independientes desde la misma escena, ejecutas cada una y eliges el resultado.

Ninguno de los dos es «limpieza después de un desastre»: ambos pueden aparecer mientras la tarea corre perfectamente bien.

Rebobinar: revierte la escena de decisión, no el mundo exterior

Imagina una tarea que ejecuta veintipico de turnos de llamadas a herramientas. En el turno 15 el modelo toma una mala decisión: elige el archivo equivocado para editar, o hace una suposición errónea sobre un requisito vago. Durante los 10 turnos siguientes sigue construyendo encima de ese error. El Curso 8 de esta serie, «Ingeniería de contexto: gastar una atención finita donde más rinde», mostró que a medida que el contexto se apila más largo y más desprolijo, la capacidad del modelo de recordar información de ahí con precisión se degrada, y este tramo de historia carga además con una decisión equivocada. En vez de dejar que el modelo siga forcejeando dentro de un contexto largo y descarriado, revierte la escena al turno 14, el punto anterior a la mala decisión, y empieza de nuevo desde ahí.

Para hacer eso, un punto de control ya no puede ser «solo el último». El saveCheckpoint de las lecciones anteriores sobrescribía el mismo checkpoint.json cada vez, así que al recuperar solo podías obtener el último estado escrito: alcanza para recuperación ante desastres, pero no sirve para rebobinar, porque la escena del turno 14 hacía rato que la había sobrescrito el turno 15. Para soportar el rebobinado, los puntos de control tienen que retenerse como una secuencia por turno, con el número de turno y el punto de guardado en el nombre del archivo: checkpoints/turn-014-A.json, checkpoints/turn-014-B.json, y así. Dentro de cada turno, el punto de guardado A aterriza cuando el modelo propuso su plan pero la herramienta todavía no se ejecutó; el punto de guardado B aterriza cuando el resultado de herramienta del turno queda escrito de vuelta en messages y el turno está genuinamente terminado. Por defecto, «volver al turno N» significa la escena posterior a que ese turno terminó, es decir, el último punto de guardado escrito en ese turno:

Con la escena que devuelve rewindTo(14), lo que sigue es el mismo flujo que el de la reanudación: usa estos messages para reconstruir la historia y continúa el bucle desde este conteo de turns. La única diferencia es que esta vez el modelo se enfrenta a una escena limpia, anterior a que la decisión se tomara, y no al contexto que el turno 15 contaminó.

Pero hay algo que vale la pena decir en voz alta: rebobinar revierte la escena de decisión, no el mundo exterior. Si la mala decisión del turno 16 ya llamó a una herramienta de alto impacto —envió de verdad un correo, digamos—, rebobinar al turno 14 no trae ese correo de vuelta. Un punto de control guarda messages, turns, pendingToolUse y cualquier otro campo de estado que hayas definido dentro de la instantánea; nunca tuvo la intención de deshacer una acción externa que ya aterrizó, ni puede hacerlo. El registro de efectos de la Lección 4 (effects.json) sigue cumpliendo su regla de solo agregar: después de que rebobines y vuelvas a ejecutar desde el turno 15, incluso si el modelo elige esta vez una acción completamente distinta, el registro solo gana una anotación nueva, no borra la vieja. Lo que haya pasado en los diez turnos descartados sigue dejando su rastro en el registro, que es exactamente la mirada sobre la idempotencia de la Lección 4 llevada al escenario del rebobinado.

Bifurcar: ejecutar dos líneas temporales desde una misma escena

Rebobinar resuelve «esta ruta estaba mal, retrocede y rehazla». Pero a veces la pregunta no es «¿estaba mal?», es «no estoy seguro de cuál es mejor»: dos planes de refactorización tienen sentido, y quieres ejecutar cada uno y comparar antes de elegir. En ese caso, no elijas uno de forma destructiva: copia dos líneas temporales independientes desde el mismo punto de control y ejecuta cada una:

Después de forkFrom(14, "plan-b"), checkpoints-plan-b/ tiene su propia secuencia de puntos de control y un registro de efectos en blanco. Del turno 14 en adelante, adónde va esta línea temporal, cuántos turnos ejecuta, cuántos puntos de control aterriza: nada de eso interfiere con la línea principal.

Que las dos líneas temporales bifurcadas sean independientes es una advertencia para las herramientas de alto impacto: si ambas líneas llamaran a la misma acción genuinamente externa —las dos necesitan enviar el mismo correo, digamos—, dejar que cada una corra hasta el final sin aprobación significa que cada línea lo envía una vez, lo que se convierte en un efecto secundario duplicado. Cablearles una compuerta de aprobación a herramientas así, o pasar a un modo de simulación durante la bifurcación, vale la pena antes de bifurcar. Es el mismo razonamiento que el de que el registro no se revierta al rebobinar: un punto de control se puede copiar en dos, pero un efecto externo que ya aterrizó no se puede copiar en «uno por mundo paralelo».

Comparación con un producto: Claude Code ya lo lanzó como funcionalidad

El rebobinado y la bifurcación de arriba son algo que Claude Code ya trae como funcionalidad de nivel producto; esto es solo para comparar, no es la herramienta que se enseña. Su mecanismo de puntos de control captura automáticamente el estado de tu código antes de cada prompt de la persona usuaria2: cada prompt crea un punto de control nuevo2, y Claude Code guarda los puntos de control junto con la conversación, así que todavía puedes ejecutar /rewind después de reanudar una sesión2.

Su menú /rewind divide «qué restaurar» en tres opciones: "Restore conversation: rewind to that message while keeping current code" (restaurar la conversación: rebobinar hasta ese mensaje conservando el código actual), "Restore code: revert file changes while keeping the conversation" (restaurar el código: revertir los cambios de archivos conservando la conversación), o "Restore code and conversation: revert both code and conversation to that point"2 (restaurar el código y la conversación: revertir ambos hasta ese punto), que resulta ser la versión producto de la frase de esta lección, «rebobinar revierte la escena de decisión». Puedes elegir revertir solo la escena de decisión (la conversación), o revertir también el código junto con ella. La documentación oficial también lista algunos casos de uso habituales de los puntos de control, como "Exploring alternatives: try different implementation approaches without losing your starting point" (explorar alternativas: probar distintos enfoques de implementación sin perder tu punto de partida) y "Recovering from mistakes: quickly undo changes that introduced bugs or broke functionality"2 (recuperarse de errores: deshacer rápido cambios que introdujeron bugs o rompieron funcionalidad). Vale la pena notar que esos casos de uso están listados de forma genérica bajo los puntos de control (/rewind), no separados en «rebobinar» y «bifurcar». Pero puestos contra los dos usos de esta lección —«salió mal, retrocede y rehaz» y «no estoy seguro, bifurca y prueba»—, la dirección coincide.

Del lado de la bifurcación, Claude Code ofrece /branch o 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 ramificarte y probar un enfoque distinto conservando intacta la sesión original, usa /branch o claude --continue --fork-session).

Fronteras y división del trabajo: de qué se hace cargo cada uno —puntos de control, Git y registro de efectos

La documentación de Claude Code también traza una frontera propia: su mecanismo de puntos de control "does not track files modified by bash commands"2 (no rastrea archivos modificados por comandos bash), y "Only direct file edits made through Claude's file editing tools are tracked"2 (solo se rastrean las ediciones directas de archivos hechas a través de las herramientas de edición de archivos de Claude). Por la misma lógica, los puntos de control de tu propio arnés cubren solo los campos de estado que definiste explícitamente dentro de la instantánea: messages, turns, tokensUsed, pendingToolUse. Los cambios que una herramienta hizo en el mundo exterior —escribir en una base de datos, llamar a otro servicio, enviar un correo— no son asunto de un punto de control. Ese es el trabajo del registro de efectos.

La documentación oficial enuncia con claridad el papel del mecanismo: los puntos de control están diseñados para una recuperación rápida a nivel de sesión, y para la historia de largo plazo y la colaboración habría que "continue using version control, such as Git, for commits, branches, and long-term history."2 (seguir usando control de versiones, como Git, para commits, ramas e historia de largo plazo). Los tres se hacen cargo de tramos distintos, y lado a lado queda más claro:

MecanismoDe qué se hace cargoEscala temporal
Punto de controlLa escena en curso: messages, conteos de turnos, la llamada a herramienta todavía no ejecutadaMinutos, a nivel de sesión
GitLa historia propia del código: commits, ramas, colaboraciónPermanente, colaborativa
Registro de efectosEfectos secundarios externos que ya ocurrieron: correos enviados, escrituras en bases de datosSolo agregar, conservado de forma permanente

El costo de retener: elige tu compromiso

Retener una secuencia de puntos de control por turno no es gratis: dos puntos de guardado por turno y, cuanto más largo corra la tarea, más archivos se apilan en disco. El principio de Anthropic de que "you should consider adding complexity only when it demonstrably improves outcomes"3 (habría que considerar agregar complejidad solo cuando mejora los resultados de forma demostrable) aplica igual acá. Si la tarea corre apenas unos pocos turnos y rara vez necesita un rebobinado, conservar la secuencia entera puede costar más de lo que vale; como en las lecciones anteriores, con conservar solo el último alcanza. Del otro lado, si la tarea corre decenas de turnos y necesita habitualmente rebobinar o bifurcar para probar algunos enfoques, la secuencia que conservas se gana su lugar: cuando algo sale mal no tienes que empezar de cero, y el costo del ensayo y error baja. Esto es en el fondo un juicio a escala del tamaño de la tarea, no una cuestión de qué enfoque es intrínsecamente correcto.

Resumen

  • Los puntos de control no son solo un seguro de recuperación ante desastres: una hilera retenida de puntos de control es la línea temporal de la tarea y, más allá de la reanudación, soportan rebobinar y bifurcar; una hoja de ruta comunitaria encuadra esos tres juntos como aquello de lo que se hace cargo el componente de persistencia1
  • Rebobinar revierte la escena de decisión, no el mundo exterior: las acciones externas que de verdad ocurrieron no se deshacen al rebobinar, y el registro de efectos se mantiene de solo agregar; es la mirada sobre la idempotencia de la Lección 4 llevada al escenario del rebobinado
  • Soportar el rebobinado exige que los puntos de control se retengan como una secuencia por turno (tipo turn-014-A/B.json) en vez de sobrescribir para conservar solo el último; rewindTo(turn) toma por defecto el último punto de guardado escrito en ese turno
  • Bifurcar copia líneas temporales independientes desde la misma escena, cada una con su propia secuencia de puntos de control y su propio registro de efectos. Si ambas líneas fueran a golpear la misma herramienta de alto impacto, acuérdate de cablear una compuerta de aprobación o pasar a modo de simulación; si no, son efectos secundarios duplicados
  • Claude Code ya trae el rebobinado y la bifurcación como funcionalidades de producto: puntos de control creados automáticamente por prompt, /rewind puede restaurar la conversación o el código por separado, /branch y --fork-session para bifurcar2. Pero traza su propia frontera: solo rastrea las ediciones hechas desde las propias herramientas de edición de archivos de Claude, no los cambios de comandos bash2, y está posicionado como recuperación rápida a nivel de sesión, con Git haciéndose cargo todavía de la historia de largo plazo y la colaboración2
  • Tres trabajos distintos: los puntos de control se hacen cargo de la escena en curso en escala de minutos, Git de la historia permanente y colaborativa del código, el registro de efectos de los efectos secundarios externos que ya ocurrieron. Retener una secuencia completa de puntos de control por turno tiene un costo en disco; si vale la pena depende de la escala de la tarea, no de qué enfoque es intrínsecamente correcto3

>> Lección 6: Manos a la obra: conectar los puntos de control y la reanudación al arnés

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

Ejercicios

01

Para cada uno de los cuatro escenarios de abajo, ¿qué deberías usar: rebobinar, reanudar, bifurcar o Git? Responde cada uno y da tu razonamiento.

Nivel 1: Cuatro escenarios, elige la herramienta correcta
  1. Una tarea corrió veintipico de turnos y notas que el modelo eligió el plan de refactorización equivocado en el turno 12. Los turnos siguientes construyeron todos encima de ese plan equivocado, pero el proceso en sí sigue corriendo bien, sin caída.
  2. La misma tarea llegó al turno 18, reiniciaron la máquina anfitriona, el proceso murió por completo y no terminó nada.
  3. No estás seguro de si dividir un módulo en dos servicios o en tres, y quieres que el agente ejecute cada plan una vez para poder comparar resultados.
  4. Quieres saber cómo se veía este código hace tres días, y quién lo cambió y cuándo.
Criterios de finalización · marcado local
02

El código de abajo es la versión vieja de las lecciones anteriores: sobrescribe el mismo checkpoint.json cada vez, así que puede soportar la reanudación pero no el rebobinado. Reescríbelo como pide esta lección: los nombres de archivo siguen la regla de retención por turno turn-NNN-A.json / turn-NNN-B.json; provee un loadLatest() para la reanudación que por defecto tome el último punto de guardado escrito en el turno más nuevo; y provee un rewindTo(turn) que tome la escena de un turno específico. Cuando termines, escribe la verificación: guarda 5 turnos seguidos, llama a rewindTo(3) y confirma que el turns de la escena devuelta es 3 y que el largo del registro de efectos effects.json no se revirtió.

Nivel 2: Convertir saveCheckpoint en una secuencia por turno
Criterios de finalización · marcado local