Agent harness and sandbox: TrueForge and smolvm

TrueForge is an open-source harness in TypeScript holding the execution loop, MCP tools, approvals and secrets. smolvm is a Rust CLI booting microVMs with a separate guest kernel on libkrun, with an egress allowlist in the configuration file. Underneath sit five different isolation levels, from seccomp to a full VM, and each stops different things.

AICybersecurityAIAI AgentsSecuritySandboxmicroVMOpen SourceHarnessRust
Contents
  1. TrueForge, the harness layer
  2. smolvm, the isolation layer
  3. The five levels, and what each stops
  4. What smolvm states it does not protect
  5. How the two layers compose
  6. What we think
  7. Sources
Four figures on TrueForge, smolvm and the isolation levels for agents
Repositories read on 20 August. Sources at the end.

An agent working on its own touches two layers that need designing separately. Above sits the harness, holding the loop, the tools, the secrets and the approvals, which we wrote about in harness engineering. Below sits confinement, meaning where the code actually runs.

Two projects released over recent months take one layer each.

TrueForge, the harness layer

TrueForge comes from TrueFoundry, in TypeScript, MIT licence, repository opened on 23 July 2026, with 2,178 stars as read on 20 August. It describes itself as “the open-source agent harness - the runtime layer that turns an LLM into a working agent”.

What it holds is in the list: model calls, MCP tools, skills, sandboxing, approvals, context management and session state. It exposes itself three ways, a chat UI, an HTTP API with a TypeScript SDK, and an embeddable UI SDK.

Three choices matter for anyone looking at security.

Human checkpoints are part of the runtime rather than a graft: tool approval, ask-user-questions and generative UI inside the chat. Asking for confirmation before an irreversible action is easier to sustain when the loop provides for it.

The sandbox is a tool, provisioned only when needed, and the provider today is Daytona. On the same line the README says “Secrets stay in the harness”: code runs elsewhere, credentials remain in the layer that decides.

Configuration starts from YAML catalogs for models, MCP servers, skills and sandbox. A declared list of what an agent may use is also the list to review in an audit.

The rest is context engineering, with subagents, deferred tool loading, offloading of large results and compaction, plus two operating modes: local single process with SQLite, or Postgres and Redis through Docker Compose or Helm.

smolvm, the isolation layer

smolvm is in Rust, Apache-2.0 licence, repository opened on 18 December 2025, with 5,562 stars on 20 August. The description is “Ship and run software with isolation by default”.

Every workload runs in a VM with a separate guest kernel, on Hypervisor.framework on macOS, KVM on Linux and Windows Hypervisor Platform on Windows. The VMM is libkrun and the guest kernel comes from libkrunfw. Images are OCI, so any image on Docker Hub or ghcr.io boots without a Docker daemon.

Defaults are 4 vCPUs and 8 GiB of RAM, with elastic memory through a virtio balloon: the host commits what the guest actually uses and reclaims the rest. vCPU threads sleep in the hypervisor while idle.

The machine is declared in a Smolfile in TOML, with image, resources, mounts, ports and setup commands. Two details weigh more than they look.

The first is the network policy. Networking is off by default, and when switched on there is an explicit allowlist:

[network]
allow_hosts = ["api.stripe.com", "pypi.org"]

For an agent running code a model just generated, egress is the vector remembered last, and having it declared in a file that lives in the repository makes it reviewable like any other configuration.

The second is that unknown keys are rejected rather than ignored: a typo fails when the machine is created, not silently at runtime.

Then there is the snapshot: a machine configured by hand packs into a .smolmachine file and pushes to an OCI registry, with no Dockerfile written.

The five levels, and what each stops

The word sandbox covers very different things. Ordered by how much they isolate, and by what they cost.

LevelToolsWhat it separates
System filterseccomp-bpf, LandlockRestricts the process’s calls, shared kernel
Namespacesbubblewrap, nsjailIsolates filesystem, network and PID views, shared kernel
Application kernelgVisorIntercepts syscalls in userspace
microVMlibkrun, Firecracker, microsandboxSeparate guest kernel, hardware boundary
Full VMKata ContainersFull kernel and container runtime

The row most often misread is gVisor, and the project spells it out: “gVisor is not a syscall filter (e.g. seccomp-bpf), nor a wrapper over” another runtime. It is an application kernel written in Go running in userspace and implementing the Linux interface, so the host kernel sees only what gVisor passes it.

The real step sits between the third and fourth rows. Above, an escape aims at the host kernel, which is shared. Below, the guest has its own kernel and reaching the host means going through the hypervisor. It is the same reasoning behind AWS building Firecracker, today at 36,165 stars, to run different customers’ code on the same machine.

For agents the choice narrows quickly. An agent that compiles, installs packages and launches processes needs a wide Linux surface, and over that surface system filters alone leave too much uncovered. microVMs cost more in memory and startup, and in exchange they move the boundary onto a much narrower surface.

Among managed services, E2B is Apache-2.0 with 13,486 stars and was built as a cloud sandbox for agents, while Daytona, the one TrueForge uses today, sits at 71,955.

What smolvm states it does not protect

The README carries a Security Model section worth more than many pages of documentation, because it lists the limits instead of omitting them.

The CLI and the VMM processes run with the permissions of the invoking user, and that account, the host, the hypervisor, libkrun and smolvm itself sit in the trusted computing base. Directories passed with --volume are exposed to the guest on purpose, and the project warns against mounting secrets there. SSH agent forwarding does not copy private keys into the guest, but it lets the guest request signatures while the VM is alive.

There is also a point about distribution: release archives publish SHA-256 checksums and the installer rejects a mismatch when the checksum file is available, but releases are neither signed nor accompanied by provenance attestations, and the installer proceeds if the checksum file cannot be downloaded. The recommended installation is a curl | bash, so anyone bringing smolvm into a working environment downloads the binary from releases and verifies the checksum by hand.

How the two layers compose

The division of labour these two projects suggest is clean, and it holds when the tools change.

The harness holds what must never enter the sandbox: credentials, approval policy, the list of permitted tools, session history. The sandbox holds what must never leave: the process running unreviewed code, the filesystem it writes to, and its network.

The boundary between them is the surface to design, and it is the same question we asked looking at DeepSeek Harness, where plugins arrive from a GitHub reference resolved by pnpm with no signing or allowlist, and in security and governance of the agentic loop.

What we think

The cheapest way to get this wrong is treating “sandbox” as a box to tick. Between a syscall filter and a microVM with its own kernel there are three levels, and the difference shows only on the day something escapes.

The practical criterion we take from this is to start from what the agent runs. If it only runs tools you wrote yourself, namespace confinement with an egress allowlist already covers a lot. If it runs code the model has just generated, or packages pulled from a public registry, the shared kernel becomes the weak point and the microVM is the right level.

On networking the rule is simpler and ignored more often: deny by default and declare destinations in a versioned file. An agent able to resolve any host has an exfiltration channel, however isolated its filesystem is.

And the part neither layer solves is the supply chain of what gets put inside them. A binary installed with curl | bash from unsigned releases, or a plugin resolved from a repository reference, enters the trusted base before the sandbox even starts.

Sources

Need support?Under attack?Service Status
Need support?Under attack?Service Status