Oct 2026 · Grasphouse

Running an AI-Built Project

Contracts, rulings, planted bugs and gates: notes on knowing that code written by AI agents is right.

Contents

When AI agents write most of the code, the hard part of the project is no longer writing it. It is knowing that what got written is right, and keeping a long project from drifting while nobody holds all of it in their head.

These are notes from running Nablaframe, a small GPT trained from scratch so that its training and forward pass can be replayed and inspected. It is now in its seventh phase. Almost every line of its code was written by AI implementers, against specs and tests written by an AI spec partner, with me deciding what counts.

The one design idea underneath everything: no one grades their own work, and every claim traces back to something written down. Each mechanism below is a hand-off between roles, and each hand-off has a check that catches one kind of failure.

The cast #

Four roles, kept apart on purpose. The separation matters more than any tool.

RoleWhoOwnsNever does
GovernorMeRulings, phase sign-off, running the gatesWrites the code
Spec partnerOne long-running Claude sessionSpecs, contracts, tests, review, mergingWrites the shipped implementation
ImplementersClaude Code threads in a Project, one per packageThe code for one package, a PRChanges a contract, a test or a report
Reference machineMy MacEvery gate resultAnything else: no numbers from elsewhere count

The spec partner and the implementers are the same kind of model, but they never share a context. An implementer sees only the repo: the contracts, the spec and the decision log. That is what makes their agreement mean something.

Spec and rulings Delta Parallel threads Draft PRs Review and merge Gates on the Mac Generated reports Findings the governor decidesevery open choice stubs fail exactlythe listed tests named tests pass,with no skips every open readinglisted for review fresh clone, fulllane, real data status must matchthe numbers into the notebookand the next spec a contradiction: stop and report changes asked bars set fromearlier experiments
Code reaches main only through review, and results come only from the Mac. Each box is a hand-off, and the line under each name is its check. Work flows clockwise; review can send a PR back to its thread, an agent who finds a contradiction stops and reports it for a ruling, and findings from the gates feed the next spec.

Back to contents

Contracts first: the delta #

The unit of work is a delta: one slice of the spec turned into contracts and failing tests, applied to main before anyone implements it.

A delta ships:

The point is that the implementer’s job is small and checkable. It doesn’t decide what to build; it makes named tests pass without touching the contract.

Back to contents

Testing the tests #

A test suite written by the same model that will be judged by it is easy to fool. So every delta is proven twice before it ships.

The reference has a second use: when an implementer’s PR arrives, both versions run on real trained models, and their outputs have to match value for value.

Back to contents

Rulings #

Every choice that could reasonably go either way becomes a numbered entry in a decision log: its date, the decision, and the evidence it rests on. The project has more than 60. Committing an entry is the ruling, so only the governor does it.

Two rules make the log work:

Most new rulings arrive mid-build, not in planning. One came from a wrong function that could never fail. Another came from tracing what a code change would do to records written a phase earlier. The most recent came from a gate that couldn’t run as specified (below). Each took the governor a minute to decide, because the options and the evidence arrived written down.

Back to contents

Implementers, PRs and review #

Each implementer is a thread with a fresh context and one package: named files, named tests, and an objective “done when”. Threads that don’t depend on each other run in parallel, each on its own cloud machine; those that do run in waves. A thread opens a draft PR and lists every reading it had to make where the docstring left a choice open.

Review is where the independence pays off. For each PR the spec partner:

  1. Applies the diff to a fresh clone of main, and checks that no docstring, test or out-of-scope file moved.
  2. Runs the thread’s named tests, the full lane, and the whole wave applied together.
  3. Runs the code on real data, where it exists, against the private reference.
  4. Posts the review as a PR comment, verdict first, with a ruling on each listed reading.
  5. Merges only when every condition holds: the reviewed commit, only the allowed files, no decision left open, a passing lane, and the governor hasn’t asked to hold it.

Watching is event-driven. A small script polls GitHub once a minute and wakes the reviewer when a PR opens or gets new commits, with a scheduled check every two hours in case the session that runs it was reclaimed. A fixed half-hourly timer was the first version; reviews started up to 30 minutes late.

One caution from the last wave: “these threads share no files” is not the same as “these threads are independent”. One thread’s test needed another thread’s code, so the merge order mattered. The thread noticed and said so in its PR.

Back to contents

Gates and the machine of record #

Tests say the code does what the contract says. Gates say whether the project’s claims hold. A gate is a script that runs on the reference machine, measures something against a bar set from earlier experiments, and writes one report.

A case study: eight probe pairs #

The newest gate traces a small modular-addition model on a fixed probe of 8 input pairs. Before tracing, the engine runs an oracle that requires the model’s plain pass and its recording pass to produce bit-identical logits. That policy was ruled long ago and had held on every model since.

While exercising the gate on a cloud machine, the implementer found the two passes 1 float32 rounding step apart on about a third of the logits. The first suspect was the machine: a different CPU, more threads. A second machine with another CPU gave exactly the same counts, so it wasn’t the hardware. Then the Mac failed too.

The cause was size. Each pair is only 3 tokens, so 8 pairs make 24 rows, and at that size the compiler builds the two passes differently. From 48 pairs the passes agree bit for bit; the earlier models’ probes had never been small enough to notice. A 64-pair probe passed the oracle at all 45 trained checkpoints and an 8-pair probe at none. The ruling: trace 64 pairs and keep the oracle strict. From first report to ruling took an afternoon, and no gate result was ever at risk, because the gate would have failed loudly instead of passing quietly.

Back to contents

Where it breaks #

The process has three weak points, and each has shown up in practice.

Back to contents

Takeaways #

If you run a project with AI agents doing the building, these are the habits that paid for themselves:

  1. Keep the roles apart: whoever specifies doesn’t implement, whoever implements doesn’t review, and one human decides.
  2. Write contracts where the code lives, and ship them with failing tests before anyone implements.
  3. Prove each contract with a private implementation, then break it on purpose and make sure the tests notice.
  4. Ask of every bar whether it can fail. If it can’t, it isn’t a bar.
  5. Keep a decision log, and make “stop and report” the default answer to a contradiction.
  6. Give implementers small, named jobs and let them list their own readings. Those lists are where the spec’s gaps surface.
  7. Review on real data, not only on tests, and merge only under written conditions.
  8. Pick one machine of record, and let only its generated, validated reports state results.
  9. Make results rebuildable: key everything by its inputs and code, and recompute.
  10. Expect the process’s own blind spots. Trace each change’s effect on what already exists before it ships.

Back to contents


Part of Grasphouse.