Base: anatomía del loop|INEMA.CLUB-PRO

Clase 5 · 16 min

Estado fuera del modelo: archivos y git como memoria

En un loop largo, el contexto del modelo va a ser compactado, reseteado o cambiado por una sesión nueva. Lo que solo existía en la conversación desaparece o vuelve como resumen, mezclando hecho y suposición. La salida: sesión descartable, estado en archivos y en git, y todo ciclo empieza releyendo. Tú armas un ciclo así y lo interrumpes a propósito.

Empezar la lección
Carpetas de papel y un disco externo junto a un notebook, conectados por cables finos que se ramifican.

En esta lección vas a

  1. 1Por qué la memoria del modelo no aguanta un loop largo
  2. 2La lista de ítems con passes, el archivo de progreso y el git log
  3. 3Interrumpir y retomar sin rehacer ni saltar
  4. 4Git como deshacer y como historial del loop

Objetivo: armar un ciclo descartable que relee el estado en archivo, hace un ítem, verifica y hace commit, y retomar después de interrumpir sin rehacer nada.

01Una sesión descartable, un estado que se queda

Haz clic en cada paso del ciclo: qué lee y qué deja grabado.

Desplázate por la página: cada etapa de abajo ilumina su parte del diagrama.

  1. 1/6

    Sesión nueva

    Puede ser un /clear, una compactación, un codex exec nuevo, el Ralph llamando de nuevo u otra persona tomando el relevo. El diseño parte del peor caso: la sesión no recuerda nada y puede interrumpirse a la mitad.

  2. 2/6

    Relee el estado

    En el harness de larga duración de Anthropic (26/11/2025), toda sesión empieza así: dónde estoy (pwd), qué se hizo (git log y el archivo de progreso), cuál es el próximo ítem, y una prueba básica antes de programar. La lista de ítems es JSON con el campo passes; el post dice que el modelo sobrescribe menos el JSON que el Markdown.

  3. 3/6

    Hace un ítem

    Elige el primer ítem pendiente y hace solo ese. En el post de Anthropic, las sesiones siguientes solo pueden cambiar el campo passes; no reescriben ni borran ítems de la lista.

  4. 4/6

    Verifica y marca

    El ítem solo pasa a passes: true si la verificación de ese ítem pasó. La línea en el progreso dice cuándo y el resultado. Si falló, el ítem sigue pendiente y el motivo queda registrado.

  5. 5/6

    Commit

    El commit es el checkpoint: si la próxima sesión se cae, nada de lo que se verificó se pierde; si un ítem salió mal, git revert lo deshace. LOOP-R usa el mismo principio para las versiones del proceso ("git es el mecanismo de promoción y rollback"; detalle en el curso 5).

  6. 6/6

    Relee la carpeta, no la conversación

    La sesión es descartable; el estado no. Lo que necesita sobrevivir a una compactación, a un reset o a un cambio de modelo va a un archivo y a un commit antes del fin del ciclo.

El kit execucao-longa lleva la idea a siete archivos (goal, plan, state, progress, failures, decisions, canal): es la clase 1 del curso 2.

02Un ciclo descartable en Python

Cada ejecución es una "sesión" que no recuerda nada: relee, hace un ítem, verifica, graba y hace commit. Sin modelo: la acción es escribir un archivo.

Terminal · preparar la carpeta
mkdir -p ~/ensaio-loop/estado && cd ~/ensaio-loop/estado && git init -q
cat > features.json <<'EOF'
[
 {"id":"f1","descricao":"ler o CSV","passes":false},
 {"id":"f2","descricao":"contar linhas","passes":false},
 {"id":"f3","descricao":"gravar o resumo","passes":false}
]
EOF
git add -A && git commit -qm inicio
ciclo.py
#!/usr/bin/env python3
"""Un ciclo que empieza de cero cada vez: relee el estado en los archivos, hace UN ítem, graba y hace commit."""
import json, subprocess, sys, datetime, pathlib

estado = pathlib.Path("features.json")
itens = json.loads(estado.read_text())
pendentes = [i for i in itens if not i["passes"]]
if not pendentes:
    print("nada pendente: objetivo cumprido")
    sys.exit(0)
item = pendentes[0]
print(f"releu features.json: {len(itens) - len(pendentes)} feitos, {len(pendentes)} pendentes")
print(f"faz: {item['id']} ({item['descricao']})")
pathlib.Path(f"{item['id']}.txt").write_text(item["descricao"] + "\n")   # la "acción"
item["passes"] = pathlib.Path(f"{item['id']}.txt").exists()                # la "verificación"
estado.write_text(json.dumps(itens, ensure_ascii=False, indent=2) + "\n")
agora = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
with open("progress.md", "a") as f:
    f.write(f"| {agora} | {item['id']} | passes={item['passes']} |\n")
subprocess.run(["git", "add", "-A"], check=True)
subprocess.run(["git", "commit", "-qm", f"feito: {item['id']}"], check=True)
print(f"commit: feito: {item['id']}")
Terminal · ejecutar, "caer" y retomar
python3 ciclo.py
# cierra el terminal aquí, abre otro y vuelve a la carpeta
cd ~/ensaio-loop/estado
python3 ciclo.py && python3 ciclo.py && python3 ciclo.py
git log --oneline
Ejemplo del repositorio
$ python3 ciclo.py
releu features.json: 0 feitos, 3 pendentes
faz: f1 (ler o CSV)
commit: feito: f1
--- (sessão descartada; outra começa do zero)
$ python3 ciclo.py
releu features.json: 1 feitos, 2 pendentes
faz: f2 (contar linhas)
commit: feito: f2
$ python3 ciclo.py
releu features.json: 2 feitos, 1 pendentes
faz: f3 (gravar o resumo)
commit: feito: f3
$ python3 ciclo.py
nada pendente: objetivo cumprido

$ git log --oneline
58d590c feito: f3
16ff9e9 feito: f2
7345668 feito: f1
7f9664d inicio

Los hashes cambian en tu máquina; el orden y los mensajes no.

03Interrumpe a la mitad y mira la retomada

Cada tarea es un ciclo. Ejecuta, interrumpe y ejecuta de nuevo: lo que ya tiene commit no se rehace.

pendientes (passes: false)

en esta sesión

passes: true + commit

la verificación falló

Simulación ilustrativa en el navegador. El fallo es a propósito: un ítem sin prueba no pasa a passes: true.

04Práctica

En tu máquina. No gasta cuota: no hay modelo en el ciclo.

E1 · Tres sesiones, tres commits

10 min

Prepara la carpeta, pega el ciclo.py y ejecútalo una vez. Cierra la terminal, abre otra y ejecútalo hasta que aparezca "nada pendente".

Listo cuando: La última ronda imprime nada pendente: objetivo cumprido, y git log --oneline | wc -l → 4.

E2 · La verificación que reprueba

15 min

Agrega el ítem f4 "arquivo vazio" y cambia la verificación para exigir un archivo no vacío (stat().st_size > 0). Haz que la acción de f4 grabe un archivo vacío y ejecútalo.

Listo cuando: python3 -c "import json;print([i['passes'] for i in json.load(open('features.json'))])" → [True, True, True, False], y tail -1 progress.md termina con passes=False |.

E3 · La lista de un trabajo tuyo

15 min

Elige una tarea real de varias horas y divídela en al menos 5 ítems verificables en un features.json, todos con passes: false, en una carpeta de proyecto con git.

Listo cuando: python3 -c "import json;d=json.load(open('features.json'));print(len(d)>=5, any(i['passes'] for i in d))" → True False, y git log --oneline -1 -- features.json muestra el commit de la lista.

05Prueba de la lección

Pregunta 1 de 4

Después de una compactación, el resumen dice "f3 concluído", pero features.json muestra f3 con passes: false y no hay commit de f3. ¿Qué vale?competencia

06En tres frases

Sesión descartableDiseña para el peor caso: la próxima sesión no recuerda nada y puede caerse en medio.
Vuelve a leer antes de actuarLa lista con passes, el archivo de progreso y el git log dicen dónde quedó; el resumen de la conversación no.
Un ítem, una prueba, un commitpasses solo pasa a true con verificación, y cada ítem verificado se vuelve un punto de reanudación.

Para ir más allá

Clase anteriorPróxima clase