Base: anatomy of the loop|INEMA.CLUB-PRO

Lesson 5 · 16 min

State outside the model: files and git as memory

In a long loop, the model's context will be compacted, reset, or swapped for a fresh session. What only existed in the conversation vanishes or comes back as a summary, mixing fact and guess. The way out: disposable session, state in files and in git, and every cycle starts by rereading. You build a cycle like this and interrupt it on purpose.

Start the lesson
Paper folders and an external drive next to a laptop, connected by thin cables that branch out.

In this lesson you will

  1. 1Why the model's memory can't handle a long loop
  2. 2The list of items with passes, the progress file, and the git log
  3. 3Interrupt and resume without redoing or skipping
  4. 4Git as undo and as the loop's history

Goal: build a disposable cycle that rereads the state from a file, does one item, verifies, and commits, and resume after an interruption without redoing anything.

01A disposable session, a state that stays

Click each step of the cycle: what it reads and what it leaves recorded.

Scroll the page: each step below lights up its part of the diagram.

  1. 1/6

    New session

    It could be a /clear, a compaction, a fresh codex exec, Ralph calling again, or someone else taking over. The design starts from the worst case: the session remembers nothing and can be interrupted midway.

  2. 2/6

    Rereads the state

    In Anthropic's long-running harness (11/26/2025), every session starts like this: where am I (pwd), what has been done (git log and the progress file), what is the next item, and a basic test before coding. The item list is JSON with the passes field; the post says the model overwrites JSON less than Markdown.

  3. 3/6

    Does one item

    Picks the first pending item and does only that one. In Anthropic's post, later sessions may only change the passes field; they do not rewrite or delete items from the list.

  4. 4/6

    Verifies and marks

    An item only becomes passes: true if its verification passed. The line in progress says when and what the result was. If it failed, the item stays pending and the reason is recorded.

  5. 5/6

    Commit

    The commit is the checkpoint: if the next session drops, nothing that was verified is lost; if an item came out wrong, git revert undoes it. LOOP-R uses the same principle for process versions ("git is the promotion and rollback mechanism"; details in course 5).

  6. 6/6

    Rereads the folder, not the conversation

    The session is disposable; the state is not. Whatever has to survive a compaction, a reset, or a model switch goes into a file and a commit before the end of the cycle.

The execucao-longa kit takes the idea to seven files (goal, plan, state, progress, failures, decisions, canal): it is lesson 1 of course 2.

02A disposable cycle in Python

Each run is a "session" that remembers nothing: it rereads, does one item, verifies, records, and commits. No model: the action is writing a file.

Terminal · set up the folder
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
"""A cycle that starts from zero every time: rereads the state from files, does ONE item, records and commits."""
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")   # the "action"
item["passes"] = pathlib.Path(f"{item['id']}.txt").exists()                # the "verification"
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 · run, "crash" and resume
python3 ciclo.py
# close the terminal here, open another one and go back to the folder
cd ~/ensaio-loop/estado
python3 ciclo.py && python3 ciclo.py && python3 ciclo.py
git log --oneline
Example from the repository
$ 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

The hashes will differ on your machine; the order and the messages will not.

03Interrupt midway and watch it resume

Each task is a cycle. Run it, interrupt it, and run it again: whatever already has a commit is not redone.

pending (passes: false)

in this session

passes: true + commit

verification failed

Illustrative simulation in the browser. The failure is intentional: an item without proof does not become passes: true.

04Practice

On your machine. It doesn't use up quota: there is no model in the cycle.

E1 · Three sessions, three commits

10 min

Set up the folder, paste in the ciclo.py, and run it once. Close the terminal, open another one, and run it until you see "nada pendente".

Done when: The last run prints nada pendente: objetivo cumprido, and git log --oneline | wc -l → 4.

E2 · The check that fails

15 min

Add item f4 "arquivo vazio" and change the check to require a non-empty file (stat().st_size > 0). Make f4's action write an empty file and run it.

Done when: python3 -c "import json;print([i['passes'] for i in json.load(open('features.json'))])" → [True, True, True, False], and tail -1 progress.md ends with passes=False |.

E3 · The list from a job of your own

15 min

Pick a real task that takes several hours and break it into at least 5 verifiable items in a features.json, all with passes: false, in a project folder with git.

Done when: python3 -c "import json;d=json.load(open('features.json'));print(len(d)>=5, any(i['passes'] for i in d))" → True False, and git log --oneline -1 -- features.json shows the commit of the list.

05Lesson quiz

Question 1 of 4

After a compaction, the summary says "f3 done", but features.json shows f3 with passes: false and there is no commit for f3. Which one counts?competency

06In three sentences

Disposable sessionDesign for the worst case: the next session remembers nothing and may drop in the middle.
Reread before you actThe list with passes, the progress file, and git log say where you stopped; the conversation summary does not.
One item, one proof, one commitpasses only becomes true with verification, and each verified item becomes a resume point.

Going further

Previous lessonNext lesson