Skip to content
covey

An agent that writes code has to be able to run it. It needs a shell, a file system, a programming language, sometimes a database to test against. In other words, it needs a computer.

Covey gives it one — as an isolated environment we call a sandbox. How that environment is built determines what the agent can and cannot do. This post describes it.

Two planes, deliberately separated

Covey consists of two parts with very different properties.

The control plane is the steering part. It knows which agents exist, what they may do, what work is waiting and what has happened so far. It holds all the state, it is always reachable, and it is the only place with access to the database. Technically it is a single Go program alongside a Postgres database.

The data plane is the working part: the sandboxes the agents actually work in. It is kept deliberately dumb. It contains nothing that is not also held elsewhere.

That separation is why a lost sandbox is not a problem. If one fails, it is rebuilt from two ingredients: the agent's versioned configuration and its home directory. Nothing is lost, because nothing lives in the sandbox that lives only there.

What survives a restart

There is exactly one place in the sandbox that persists: the agent's home directory. That is where its checked-out projects, its notes and its work in progress live.

Everything else is short-lived. The sandbox itself is built when the agent starts working and torn down when it finishes. An agent with nothing to do consumes no computing power.

The home directory can also be browsed from outside. You can look inside, download files, upload some, move and delete them — and you can see what is taking up space. That sounds mundane, but it is the difference between a system you can follow and one you cannot. Otherwise a full home directory only becomes apparent when a run fails because of it.

The workplace: more than an image

What the sandbox is equipped with is described by the workplace. It consists of a container image — the basic set of tools and languages — and the services that should run alongside it.

The second part is the more interesting one. If a project needs a database to run its tests, that database runs as a container of its own beside the sandbox and is reachable from there under its name. The agent does not install or operate it.

That is a deliberate decision. An agent that sets up its own test database does so afresh every time the sandbox is built, slightly differently each time, and nobody can say afterwards what was actually tested against. Put the database in the workplace and it becomes configuration: versioned, reviewable and identical for every agent with the same workplace.

If an agent is nevertheless missing a package, it does not build a workaround in its home directory. It files a request, and a person decides on it. What was missing and who approved it stays on the record afterwards.

Where the sandbox may talk

The sandbox's network egress is controlled. Which addresses an agent may reach is set by the platform — not by the agent and not by its prompt.

That is more than a precaution. An agent that can reach arbitrary addresses can send data from its working directory anywhere, and nobody would notice. An allowlist turns that into a decision somebody made and that can be read back.

Servers that are not ours

At first, all sandboxes ran on the same machine as the control plane. For a small installation that is exactly right, and it remains the default: Covey ships with a built-in server for the data plane, and anyone who configures nothing further gets it.

Anyone needing more capacity, or wanting separation for other reasons, registers further servers — we call them runners. If you know GitLab, you know the principle: the server registers, receives a token, and from then on accepts work.

Two properties matter to us here.

A runner has no access to the database. It receives orders over the same protocol the built-in server speaks, and nothing else. So an additional server extends the computing power, not the attack surface of the data.

Runners are selected by characteristics. You label them — for instance to record that they sit in a particular network or have plenty of memory — and an agent that needs such a thing lands there.

For maintenance, a server can be paused. It stays registered, credentials and working copies are preserved, work in progress finishes, and it simply accepts nothing new. Lifting the pause needs no restart. A server you want to take out for an update therefore does not have to be dismantled and set up again.

Why it is built this way

All of it follows from one assumption: an agent's working environment is the place where it makes mistakes. That is where it runs foreign code, where it tries things out, where things break.

So nothing lives there that could not be replaced. No long-lived credentials, no state known only to that one environment, no uncontrolled network access. What matters lives in the control plane, and the sandbox is a tool you can throw away and rebuild.

Back to all posts