Phase 14 - Lesson 34

Memoria del Repositorio y Estado Durable

El historial de chat es volátil. El repositorio es durable. La workbench almacena el estado del agente en archivos versionados para que la próxima sesión, el próximo agente y el próximo revisor lean todos de la misma fuente de la verdad.

Tipo: Build Lenguajes: Python (stdlib + jsonschema opcional) Requisitos previos: Fase 14 · 32 (Minimal Workbench) Tiempo: ~60 minutos

Objetivos de Aprendizaje

  • Definir qué pertenece a la memoria del repositorio y qué pertenece al historial de chat.
  • Crear JSON Schemas para agent_state.json y task_board.json.
  • Construir un administrador de estado que cargue, valide, mute y persista el estado de forma atómica.
  • Usar el esquema para rechazar escrituras incorrectas antes de que corrompan la workbench.

El Problema

El agente finaliza una sesión. El chat se cierra. La próxima sesión se abre y pregunta por dónde empezar. El modelo dice "déjame verificar los archivos", lee notas desactualizadas y vuelve a hacer el trabajo que ya estaba completo. O peor aún, reescribe un archivo terminado porque nadie le dijo que el archivo estaba listo.

La solución de la workbench es la memoria del repositorio: el estado reside en archivos JSON en el repositorio, escritos bajo un esquema, persistidos de forma atómica y fáciles de visualizar diferencias (diff-friendly) en revisiones de código. El chat es un flujo transitorio; el repositorio es el sistema de registro.

El Concepto

flowchart LR
  Agent[Bucle del Agente] --> Manager[StateManager]
  Manager --> Schema[agent_state.schema.json]
  Schema --> Validate{¿válido?}
  Validate -- sí --> Write[agent_state.json]
  Validate -- no --> Reject[rechazar + lanzar error]
  Write --> Manager

Qué pertenece a la memoria del repositorio

Pertenece No pertenece
ID de tarea activa Transcripciones de chat sin procesar
Archivos modificados en esta sesión Trazas de razonamiento a nivel de token
Suposiciones que hizo el agente "El usuario parecía frustrado"
Bloqueadores abiertos Completados muestreados (completions)
Siguiente acción IDs de modelos específicos del proveedor

La prueba es la durabilidad: ¿sería útil esto dentro de tres meses en una nueva ejecución de CI? Si es así, al repositorio. Si no, a la telemetría.

Estado schema-first

JSON Schema es el contrato. Sin él, cada agente inventa nuevos campos, cada revisor aprende una estructura nueva y cada script de CI tiene que manejar versiones anteriores como casos especiales. Con él, una escritura incorrecta es una escritura rechazada.

El esquema cubre:

  • Claves requeridas.
  • Valores de status permitidos.
  • Valores prohibidos (por ejemplo, null para arrays).
  • Restricciones de patrón (IDs de tareas que coinciden con T-\d{3,}).
  • Campo de versión para migraciones.

Escrituras atómicas

Las escrituras de estado deben sobrevivir a fallas parciales: escribir en un archivo temporal (tempfile), aplicar fsync y renombrar sobre el destino. El archivo de estado es la fuente de la verdad; uno escrito a medias es peor que no tener ningún archivo.

Migraciones

Cuando el esquema cambie, publique un script de migración junto con la actualización del esquema. El archivo de estado incluye un campo schema_version; el administrador se niega a cargar un archivo de una versión que no puede migrar.

Construcción

code/main.py implementa:

  • agent_state.schema.json y task_board.schema.json.
  • Un validador exclusivo de la biblioteca estándar (subconjunto de JSON Schema: required, type, enum, pattern, items).
  • StateManager.load, StateManager.update, StateManager.commit con escrituras atómicas de tipo crear-temporal-y-renombrar (temp-and-rename).
  • Una demostración que muta el estado, persiste, recarga y prueba el ciclo completo (round-trip).

Ejecútelo:

python3 code/main.py

El script escribe workdir/agent_state.json y workdir/task_board.json, los muta a lo largo de dos turnos e imprime el estado validado en cada paso.

Patrones de producción en la práctica

Cuatro patrones transforman el mínimo de esta lección en algo con lo que un monorrepositorio multiagente puede sobrevivir.

La escritura atómica con archivo temporal y renombrado no es opcional. Un informe de errores del proyecto Hive de marzo de 2026 documenta claramente el modo de fallo: state.json se escribía mediante write_text() y las excepciones se capturaban y silenciaban. Las escrituras parciales hacían que las sesiones se reanudaran con estados corruptos sin ninguna señal. La solución siempre es: tempfile.mkstemp en el mismo directorio que el destino, escribir, fsync, os.replace (renombrado atómico en POSIX y Windows). El atomic_write de esta lección hace exactamente eso.

Claves de idempotencia en cada llamada a herramienta no idempotente. Si un agente falla después de llamar a una herramienta pero antes de registrar el punto de control (checkpoint) del resultado, la recuperación vuelve a intentar la llamada a la herramienta. Esto es seguro para lecturas; peligroso para correos electrónicos, inserciones en bases de datos y subidas de archivos. El patrón: registrar cada ID de llamada a herramienta antes de la ejecución en un pending_calls.jsonl. Al reintentar, verificar el ID; si está presente, omitir la llamada y usar el resultado almacenado en caché. Tanto Anthropic como LangChain señalan esto en sus guías de 2026; el checkpointer de LangGraph persiste las escrituras pendientes por la misma razón.

Separe los artefactos grandes del estado. No almacene archivos CSV, transcripciones largas ni archivos generados en agent_state.json. Guarde el artefacto como un archivo independiente (o súbalo a un almacenamiento de objetos) y mantenga solo la ruta en el estado. Los checkpoints se mantienen pequeños y rápidos; los artefactos crecen de forma independiente.

Event sourcing para auditoría, snapshots para reanudar. Agregue a un registro de eventos (state.events.jsonl) en cada mutación; tome snapshots periódicamente en state.json. La reanudación lee el snapshot y luego reproduce cualquier evento posterior a la marca de tiempo (timestamp) del snapshot. Esto cuesta más disco pero permite reproducir las decisiones del agente textualmente, lo cual es esencial al depurar ejecuciones de largo plazo (long-horizon). Es la misma estructura que Postgres usa internamente para WAL.

Migraciones de esquema o rechazo de carga. El entero schema_version es el contrato. Cuando el administrador carga un archivo con una versión desconocida, se niega a leer. Publique un script de migración junto con la actualización del esquema; tools/migrate_state.py se ejecuta de forma idempotente en cada inicio.

Uso

En producción:

  • Checkpointers de LangGraph. Misma idea, almacenamiento diferente. El checkpointer persiste el estado del grafo en SQLite, Postgres o un backend personalizado. El esquema que enseña esta lección es a lo que recurrirá cuando el checkpointer falle y necesite leer el estado a mano.
  • Bloques de memoria de Letta. Bloques persistentes con esquemas estructurados (Fase 14 · 08). La misma disciplina aplicada a personas de larga duración.
  • OpenAI Agents SDK session store. Backends acoplables, conscientes del esquema. El archivo de estado en esta lección es el backend de archivo local.

Entrega

outputs/skill-state-schema.md genera un par de JSON Schema específico para el proyecto (estado + tablero/board), un StateManager en Python conectado a escrituras atómicas y una estructura de migración para que la próxima actualización del esquema no rompa la workbench.

Ejercicios

  1. Agregue una marca de tiempo (timestamp) last_human_touch. Rechace cualquier escritura del agente dentro de los dos segundos posteriores a una edición humana. (Wait! en.md says five seconds. Let's make sure it is five seconds: "dentro de los cinco segundos") -> "dentro de los cinco segundos posteriores"
  2. Extienda el validador para que admita oneOf, de modo que una tarea pueda ser una tarea de construcción (build) o una tarea de revisión con diferentes campos obligatorios.
  3. Agregue un campo schema_version y escriba la migración de v1 a v2 (renombre blockers a risks).
  4. Mueva el backend de almacenamiento de un archivo local a SQLite. Mantenga la API de StateManager idéntica.
  5. Ejecute dos agentes contra el mismo archivo de estado con una condición de carrera de escritura (write race) de 50 ms. ¿Qué sale mal y cómo le salva el renombrado atómico?

Términos Clave

Término Lo que la gente dice Lo que realmente significa
Memoria del repositorio (Repo memory) "Archivo de notas" Estado almacenado en archivos rastreados en el repositorio, bajo un esquema
Schema-first "Validar entradas" Definir el contrato antes de la escritura, rechazar desviaciones
Escritura atómica "Solo renombrar" Escribir en un archivo temporal, aplicar fsync y renombrar, para que fallas parciales no corrompan los datos
Migración "Actualización de esquema" Un script que transforma el estado vN en estado v(N+1)
Sistema de registro (System of record) "Fuente de la verdad" El archivo o artefacto que la workbench trata como autoritativo

Lecturas Adicionales

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).