Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Harnesses

A harness is code the daemon schedules: one hash-pinned RV64IMAC ELF, compiled and run in-process, confined to its own address space, reaching the world only through host calls it was given. It never runs of its own accord — the daemon decides when, and while running it may call back in.

A harness is what shapes an agent — what it remembers, what it can load, what it knows of its own past, the tools it habitually reaches for. An agent is its harnesses, which is why each one is declared per agent rather than shipped to everybody.

This chapter describes harness images. The daemon also carries compiled-in harnesses — MCP and memory — which share the trait and none of the confinement; see Architecture.

The argument is the capability

Host calls are keyed by number, and a number with nothing registered traps. So a capability the declaration did not bound is not checked for — it is absent from the linker the harness was instantiated with. Enforcement is the absence of code. There is no check to write and none to forget.

Every capability takes an argument, and the argument is not optional decoration — it is the capability. Without the argument it is never registered, so an under-specified declaration reaches nothing rather than everything.

CapabilityReachesBounded by
fsFilesroot
execCommandsroot
httpThe networkhosts
peersThe other agents’ names
sessionsThe agent’s own past conversationsthe declaring agent
skillsThe skills the agent namedskills
berm.callAnother harness the same agent declaredthe declaring agent

The runtime is reached through one capability per operation rather than one carrying every message. Each narrows by existing: sessions::search cannot name an agent, because it takes a search and returns hits and there is no field in it to mean anything else.

That is also why the daemon’s own port is not a way back in: http can only reach a name written in hosts, so localhost is unreachable unless somebody put it there.

Calling another harness

berm.call takes a harness name, a tool, and the argument blob a model would have sent. The name is resolved per call against the declaring agent’s own resolution, so what a name means is what that agent declared it to mean — two agents installing different images under one name reach their own.

A caller can tell a target that ran and failed from one that never ran: the first is the tool’s own failure, the second a refusal. There is no depth bound. The watchdog bounds a chain on time rather than on links, so a cycle reaches the host thread’s stack first.

The image is the capability

There is no list of permitted capabilities beside those arguments. A published harness is a fixed ELF: one that never calls a capability does not need to be stopped from calling it, and one that does is a harness for exactly that. To run a shell-less environment, install an image with no shell tool — a tool that is absent cannot be called, where a tool present but starved of its host call is only a broken tool.

Manifest, not inference

A harness carries .berm.abi, an ELF section holding its ABI version, tools, and usage. A section rather than an export, because learning what a harness claims to be must not mean running it — the daemon reads a tool list, a schema, and usage text out of the file without compiling anything.

Images are content-addressed

An image is keyed by a digest of what determines it: the ELF, the root and hosts bounding it, the session it resolved under, and the Scope its runtime capabilities close over. Not by the agent that declared it.

Two agents that declare the same ELF against different roots hash differently and get two linkers. Two that declare it identically share one image. A rename changes nothing, because the agent’s name was never part of the key — but a per-agent narrowing is part of it, so two agents holding the same session harness deliberately get two images rather than sharing one narrowing.

The session is in the key for berm.call, which closes over the resolution a name is looked up in. Only a session-rooted declaration reaches the bound root, so without it a rootless or fixed-root image would be shared across sessions while resolving its siblings against whichever one compiled it first.

Invocation

Memory is per-invocation: a fresh store each call, nothing surviving between them. Anything a harness needs to persist belongs in a capability, not in its heap. The boundary costs roughly 17µs; compiling an image is ~15ms cold and ~3ms against the on-disk code cache, paid per image rather than per call.

Entering a harness blocks the thread it runs on, and exec can hold it for the length of a command, so dispatch hands the invocation to the blocking pool. A watchdog bounds how long a harness may run, set to outlast the longest host call a capability may make.