open source · a lab on self-hosted infrastructure

The whole harness, not just the loop

A persistent desktop where autonomous agents work: tools, sandbox, privilege, durable state and kernel observation. Plus a loop that knows to stop — including when it delivered without fulfilling the request.

Swapping models changes little. What decides whether an agent works is what it can touch and what it does until it stops. This repository is those two layers, built and measured.

136Go files
608tests
90.9%coverage
7stop reasons

The model is the smallest of the three. The loop decides what it does until it stops; the harness decides what it can touch.

the two layers

One test tells them apart, and it is short

If you can fix it by changing a prompt or a stop condition, it is the loop. If you have to change what the agent can do, it is harness. Almost every agent diagnosis starts by getting this question wrong.

Harness

what it can touch

  • 10 tools: shell, 6 browser ones, take-over, delegation to another coding agent
  • Per-user sandbox, with sudo on a closed list
  • Encrypted vault — the model uses the credential without reading it
  • Durable state on a volume that outlives the machine
  • Shape of the error: a tool failure becomes text in the history, it does not kill the task
  • Observation: OpenTelemetry around the loop and eBPF in the kernel

Changes by recompiling and reinstalling. It is what the agent is able to do.

Loop

what it does until it stops

  • Up to 60 iterations per invocation, 180 turns counting resumes
  • Loop detector: 3 identical failures in a row
  • Cost ceiling in dollars, per task
  • Wall-clock ceiling
  • Completion check before accepting that it finished
  • Seven stop reasons, each with what to ask the person for

Changes with an environment variable. It is what the agent does with what it has.

loop engineering

Stopping is not fulfilling

The loop finished a task when the model stopped calling tools. That measures that it stopped, not that it did what was asked — and the gap is where the silent defect lives: the task reads “done”, nobody looks, and the request never happened.

calls the model up to 60 iterations runs tools in series, with a ceiling checks completion with quoted evidence fulfilled finishes hands back the gap calls you take-over the gap goes back to the model up to twice; after that, a person

Verification demands evidence quoted from the history: a verifier that could approve without pointing at anything would approve out of inertia.

The seventh stop reason points the opposite way from the others

Five reasons describe what the site demands — password, 2FA, CAPTCHA, payment, human presence. The sixth, guardrail, contains what went too far: loop, cost, turns, time. The seventh, unverified, marks what stopped too early. On screen the question differs in each case: in one you decide whether to continue, in the other you find out what is missing.

harness engineering

Three extension points, and picking the wrong one costs rework

The same test from the previous section decides where a new capability goes. The colour of each row says which layer.

The common mistake is a skill that teaches calling the API with curl: the credential moves to the command line, within reach of exactly who it should contain.

privilege

The declared adversary is the model itself

The machine publishes nothing: only port 22 in the firewall, with screen, browser and API on loopback. The security question is not who gets in from outside — it is what the model reaches through the shell tool, which is the product’s function, not a flaw.

UserWho it isReaches
agentdthe servicethe encrypted vault, /etc/agentd
agentthe model’s tools/workspace, sudo by closed list
rootthe operator, via a key that exists only on the laptopeverything

observation

Three layers, because one does not answer the whole question

The first knows the intent and is blind to what the system did. The second knows the fact and is blind to the intent. Only together do they answer “the model tried X and the machine did Y”.

The kernel layer is the only one the model cannot switch off from inside — and even it falls to anyone with sudo. That is why the proof that it is alive lives off the machine: absence of data is the signal.

machine state — measured 2026-09-01
sistemaNixOS 25.11 · kernel 6.12.93declarative
volume/workspace · 20 GB · 282 conversationsdurable
firewall22/tcp · everything else on 127.0.0.1invariant
agent-probeeBPF · execve + connectstarts at boot
tela 5stopped without fulfilling the requestneeds you

containment

Every loop ceiling adjusts without recompiling

A ceiling that only changes by recompiling is a ceiling switched off. And there is one more reason: the containment test has to force it, because asking the model to fail produces a test that passes and fails at random — measured, with the same prompt across two runs.

VariableDefaultWhat it stops
AGENTD_MAX_TURNS180Accumulated turns, carried across resumes
AGENTD_MAX_TOOL_FAILURES3Identical failures in a row — this is the loop detector
AGENTD_MAX_COST_USD3.00Inference per task, in dollars
AGENTD_MAX_VERIFY_ATTEMPTS2Times the gap goes back before calling a person
AGENTD_MAX_CONCURRENT_TASKSConcurrent tasks across the whole machine

getting started

From zero to an observed machine

  1. task checkChecks binaries, token, key and latency — before spending anything
  2. AGENT_OS=nixos task upDurable volume and droplet, declarative system, end-to-end validation
  3. task deploy && task vaultInstalls the agent over root SSH and provisions the encrypted vault
  4. task obs:upBrings up the observation backend on the laptop, with Nix
  5. task probe:deployCompiles the BPF objects and installs the kernel collector
  6. task openOpens the live screen through a tunnel — nothing is exposed