# The harness for long-running work

A loop that runs for hours forgets everything between sessions, so its memory has to live in files. Progress logs, a feature list the agent may only flip, a startup routine, and the habit of retesting each part when the model changes.

## Every session starts with amnesia

A loop that runs for hours is really many sessions in a row, and each one begins with no memory of the last. Justin Young's article on long-running agents starts from that fact. Everything the next session needs to know has to be somewhere it can read.

The context engineering guidance says the same thing from the other side: structured note-taking is external memory. Addy Osmani's recipe includes it as a memory store, a markdown file or board on disk that records what is done and what is next. Ralph's plan file is the same idea in its simplest form.

Young's article is built around four failures, and each fix maps to one: premature victory, undocumented state, premature "done", and wasted setup.

## The first session sets the stage

Young splits the work into an initializer session and many coding sessions. The initializer does the one-time setup.

- It writes `init.sh`, a script that starts the project, so later sessions do not waste time working out how.
- It starts a progress log.
- It makes the first git commit.
- It expands the prompt into a JSON feature list, with every feature marked failing.

Every later session does one feature. It may change only the `passes` field of that feature. Young chose JSON over Markdown for this file because models overwrite it less. A feature list the agent can rewrite is a feature list that will quietly shrink until the work looks finished.

```json
{
  "feature": "User can reset a password by email",
  "steps": ["open reset page", "submit email", "follow link", "set new password"],
  "passes": false
}
```

**Question:** Why does the feature list start with every feature marked as failing, and let later sessions change only the passes field?

- To make the file shorter
- So the agent cannot declare victory early or rewrite the goal, it can only flip a feature to passing
- Because JSON cannot hold more fields
- To avoid using git

**Answer:** So the agent cannot declare victory early or rewrite the goal, it can only flip a feature to passing. Premature victory is a named failure. A list the agent cannot reshape keeps the target fixed while the work proceeds.


## The startup routine

Each coding session begins with the same short routine.

```flow
Read the progress log and the git log
Read the feature list
Run init.sh
Run a basic end-to-end check
Pick one failing feature
```

The last check before picking a feature is what protects the rest. If the previous session left the app broken, the new session finds out before it builds on top of the break. Young also reports that browser automation, a Puppeteer MCP in his setup, caught bugs that reading the code missed.

At the end of a session, the agent commits with a descriptive message and updates the progress log, so the next one starts clean.

## What the compiler run taught

Nicholas Carlini's C compiler used a different shape: 16 agents in separate Docker containers on one shared git repo, no orchestrator at all. Coordination was files and git.

- **Lock files.** An agent claims a task by writing a lock file into `current_tasks/`. Git forces a second agent that tries the same task to pick another.
- **Tiny test output.** Keep it to a few lines and log details to files. A run that floods the context with output blinds the agent.
- **Time blindness.** Claude cannot judge elapsed time, so he added a fast sampling mode and kept progress output sparse.
- **CI.** New features kept breaking old ones, so tests and CI became part of the harness.

## What the game harness taught

Prithvi Rajasekaran's harness for a retro game maker used three roles: a planner that turned one sentence into a 16-feature, 10-sprint spec, a generator, and a separate evaluator. The generator and evaluator agreed on what "done" meant for each sprint through files.

The most useful part came later. With Sonnet 4.5, the harness needed context resets, a fresh agent plus a structured handoff, because of what the article calls context anxiety. With Opus 4.5 those resets were dropped. With Opus 4.6 the sprint structure was removed, the evaluator moved to one final pass, and the planner stayed.

> **Every part is an assumption**
The lesson the author draws: each piece of a harness encodes an assumption about what the model cannot do. Assumptions expire. Retest each part with every new model release, and delete the ones that no longer earn their cost.


> **Design the files, not the loop**
For a project you could loop, list the files its memory would live in: a progress log, a feature list with a passes field, a script to start the project. Write the five-line startup routine a fresh session would follow. If a new session could not pick up from those files alone, the loop will repeat itself.


**Question:** A newer model arrives. What does the long-running harness research suggest you do with your harness?

- Keep it unchanged, it worked before
- Retest which parts are still needed, because each encodes an assumption about what the old model could not do
- Add more parts to be safe
- Remove the evaluator in every case

**Answer:** Retest which parts are still needed, because each encodes an assumption about what the old model could not do. In the game harness, context resets and sprints were needed for one model and dropped for later ones. Retest per model.
