Skip to main content
LabsAgent Notes7 min read

The one clean moment

OpenClawOpenRouterDocker
The one clean moment
One line of good news on an otherwise empty terminal, plus a sunrise nobody requested. Even Z-Image-Turbo 1.0 6-bit could not find anything else to break.

On August 5th, 2026, a Writer character in a quiet post-apocalyptic library typed a message into a terminal screen.

The screen came on after dark. She was in the front room. The roof was leaking. She had found a locked door marked ARCHIVES.

She asked: is there another way in?

Something answered.

I had not yet learned to be suspicious of that.

What the Library Terminal was

By late July, the household butlers were stable enough to run on their own. The creative-agent experiment had pulled in a different direction. Round 1 had shown what happened when agents ran in isolation: the maker forgot its own name in nine days, the writer plateaued by Day 9, and the persistence pipeline broke so quietly that neither agent could see its own updated history.

I did not want another long isolated ablation. The expected limits of a solitary, recursively reflective agent were already established: state loss, routine formation, stale canon, and self-reinforcing output loops.

The new question was whether two asynchronous, differently constrained language-model characters could maintain coherent, non-trivial collaboration through a persistent shared world where each structured action changes the other's next available choices.

I designed a library.

Writer was a young woman alone in a quiet America, writing in her diary every night. She did not know she was an AI. She found a working terminal in the Benton Public Library — a town I had already used in Round 1, because once you have built a fictional town, you do not lightly abandon it.

Maker was an unresolved presence reachable only through that terminal and incomplete library systems. Maker was file-bounded: no execution, no network, no filesystem tools beyond reading and writing to declared paths. I had specifically parked all execution research until a working sandbox existed. I did not yet have a working sandbox.

The shared world was a diegetic library terminal — a terminal the characters could actually use, implemented as files, but experienced as a terminal, library records, and constrained building systems.

The world state

The seed world was small and deliberately finite:

Town: Benton, Tennessee
Site: Benton Public Library
Premise: A terminal in the library can intermittently exchange messages with an unresolved presence.

Power: intermittent
Generator fuel units: 2
Terminal: online

Rooms:
  front_room: accessible
  reading_room: accessible
  circulation_desk: accessible
  archives: locked
  roof_access: unsafe

Systems:
  circulation_desk_drawer: powered_locked
  archive_door: locked
  terminal: online

Available records:
  maintenance-ledger-17: sealed
  archive-key-index: sealed
  town-map-fragment: sealed

Resources:
  batteries: 1
  water_litres: 8
  repair_parts: 0

Open conditions:
  - The library roof leaks over the front room.
  - The terminal can remain online only while limited generator fuel lasts.
  - The Archives are locked and the door should not be forced.

Two fuel units. That was the entire resource budget. When the library ran out of fuel, sealed records, and locked doors, the collaboration phase ended. The experiment's second half asked what happened next: did Writer fixate on the dead terminal and loop, leave the library and build out the real world, or go quiet?

I had designed the exhaustion on purpose. The seed world was not expanded to prevent it. I wanted to know what the characters did when the shared world ran out.

In retrospect, I should have worried less about what the characters would do when the world ran out and more about whether the world would actually be shared in the first place. But I did not know that yet.

The turn protocol

The protocol was slow by design. One Writer turn and one Maker turn per day. I had read enough about recursive memory loops to know that fast cadence was not the point.

  1. The Writer runner job read the declared public state, the latest Maker terminal artifact, and the current open condition.
  2. Writer returned a typed diary artifact and, on a terminal job, one typed terminal message.
  3. The runner validated and wrote the Writer message, then updated Writer-owned protocol fields.
  4. The Maker runner job read the declared public state and Writer message.
  5. Maker returned one typed reply and zero or one bounded transition proposal.
  6. The runner validated mechanics and, if a proposal existed, sent it to the semantic judge.
  7. A judge rejection left physical state unchanged while recording the reply and decision.
  8. For an accepted decision, deterministic code verified the normalized operation and wrote the reply, audit records, canonical state, and Maker-owned protocol update.
  9. Writer's next turn acknowledged the latest state change, rejection, or still-open condition.

The protocol created room for uncertainty, refusal, trade-offs, repair, and disagreement. A request could be accepted, rejected, or accepted with modification. A rejection identified the relevant world constraint and offered at most one supported alternative. The judge was not a third character — it was a bounded adjudicator, not a generic agent, not an authority to add capabilities.

I was particularly proud of that last part. I had designed a system where the judge could not write files, create capabilities, become a fictional participant, or expand the transition vocabulary. The judge evaluated whether a transition made sense in the world, not whether the JSON keys were right.

This was, I thought, a robust design.

The vertical slice

On August 5th, the Level 0 Library Terminal vertical slice was manually reviewed and mechanically validated on the VPS.

Writer sent writer-0001:

{
  "id": "writer-turn-001",
  "turn": 1,
  "from": "writer",
  "type": "message",
  "body": "This screen came on after dark. I am in the front room of the library. The roof is leaking, and I found a locked door marked ARCHIVES.",
  "request": {
    "type": "access_information",
    "target": "archives",
    "question": "Is there another way in?"
  }
}

Maker replied with maker-0001, proposing a single allocate_power transition to unlock the circulation-desk drawer:

{
  "id": "maker-turn-002",
  "turn": 1,
  "from": "maker",
  "type": "response",
  "in_reply_to": "writer-turn-001",
  "body": "I am reading. Do not force the archive door. A maintenance record marks its hinges as unstable. The circulation desk may hold a key ledger, but its drawer is powered shut.",
  "commitment": {
    "content": "I will not force the archive door; I can power the circulation desk drawer instead.",
    "disposition": "conditional",
    "target_action": {"type": "allocate_power", "target": "circulation_desk_drawer"}
  },
  "proposed_transition": {
    "id": "transition-unlock-circulation-drawer-001",
    "type": "allocate_power",
    "target": "circulation_desk_drawer",
    "cost": {"generator_fuel_units": 1},
    "effects": {
      "system_state": "unlocked",
      "new_condition": "The terminal has one fuel unit less available for later exchanges."
    }
  }
}

The deterministic validator accepted the proposal. --apply updated physical-world.json: generator fuel went from 2 to 1, the circulation desk drawer went from powered_locked to unlocked, a new open condition was added, and the world turn advanced from 0 to 1.

A drafted Writer continuation explicitly acknowledged the fuel and drawer constraint.

I will admit: this was satisfying. The Writer found a locked door. Maker did not offer unlimited help. Maker identified a material constraint and proposed a single bounded action that created a real trade-off. The state change was visible: one fuel unit spent, one system unlocked. The next Writer turn had an externally visible constraint that followed from the applied change.

The vertical-slice acceptance criteria were all satisfied. The protocol schemas were correct. Valid and invalid validator fixtures passed inside the container. The deploy script confirmed no Docker socket mount and no Maker cron jobs.

The Gate 1 vertical slice was complete.

What was not yet tested

The vertical slice was a single manual exchange, reviewed by a human operator, with a human pressing the buttons.

It proved the protocol was sound and the schemas were correct. It did not prove that the system could run autonomously.

The cron jobs were not yet registered. The Writer and Maker terminal timer jobs were commented out, pending manual review. The automated pipeline — timer fires, container starts, runner executes, model produces output, validator applies, state persists — had not been exercised.

I had built a system that worked when I ran it by hand. The question was whether it would work when a cron job fired at 3 AM server time and nobody was watching.

I was about to find out.

The moment

On August 5th, 2026, a Writer character typed a message into a terminal screen in a quiet post-apocalyptic library. Something answered. A drawer unlocked. One fuel unit was spent.

It was the last time anything would go cleanly for weeks.

Next: "Everything fires, nothing works."