Thinking Outside the Sandbox
Colton BerryNovember 2, 2026
Using Vercel's fx harness to run agents outside of their sandbox
Every agent on Fractal, our cloud agent platform, has a sandbox, a small Linux computer where it runs commands, edits files, and opens a browser. Most of our agents also run their harnesses there. The harness is a program that runs an agent's loop of model calls and tool calls.
Now, we also run cloud agent harnesses as libraries inside our backend, starting with Vercel's fx. For these agents, the loop itself does not need a Linux sandbox, which means an fx agent can get to work on a message almost immediately. Tools that need a computer, such as shell commands and file edits, still run in the agent's sandbox, but it only starts when necessary.
By contrast, any message to an agent whose harness runs in a sandbox must wait for both the sandbox and harness to start up (a sandbox often sleeps to save money).
A harness program in the sandbox
0 s
The message waits. The agent is offline.
about 7 s
The sandbox boots and the harness starts.
then
The harness reads the message and answers.
after 2 idle min
The sandbox sleeps. The agent is offline again.
fx as library code in our backend
0 s
The worker opens the engine from its journal, in about 10 milliseconds.
100 ms
The agent answers.
first shell call
The sandbox starts.
after being idle
The sandbox sleeps while the agent stays ready.
agent can answeragent offline
Harnesses as programs
On Fractal, when you choose Claude Code or Codex as an agent's harness, we run it inside the agent's sandbox, supervised by a program that starts the harness, sends it work, relays its transcript to our backend, and restarts it when needed. The harness owns the turn loop: it calls the model, runs tools, compacts the conversation when it gets long, and keeps its session in files on the sandbox's disk.
Fractal API
- messages and channel activity
Sandbox
Supervisor
- starts the harness, relays its transcript
Claude Code or Codex
- turn loop and compaction
- session files on the sandbox disk
- runs shell and file tools itself
Model proxy
- credits, usage, provider keys
This works well, and we continue to support it: most of our agents still run this way. However, because the harness runs within the sandbox, the sandbox must be awake for the agent to respond.
Harnesses as library code
A library harness is not a program of its own. It runs inside one, such as a web server or a worker process. When the model calls a tool, the harness hands the call to its host program, and the host decides how to carry it out: in a sandbox, through an API, or not at all.
Incoming work
- messages and events
Host program · a web server, worker or other service
Library harness module
- turn loop and compaction
- no shell, files or process of its own
- keeps no data of its own
Host code
- makes model calls, stores state, runs tools
Model API
- any model provider
Storage
- owned by the host
- a database, disk or memory
Sandbox
- starts when a tool needs it
- sleeps when idle
model calls
Model API
- any model provider
journal and history
Storage
- owned by the host
- a database, disk or memory
shell and file calls
Sandbox
- starts when a tool needs it
- sleeps when idle
For fx agents on Fractal, the host is our backend. When the model asks to run a shell command, our backend runs it in the agent's sandbox, starting the sandbox first if it is asleep. Our backend can call the model and other APIs directly, without starting the sandbox. The library harness also stores nothing itself: it hands its journal and conversation history to our backend for storage.
Vercel's fx harness
fx is Vercel's library harness, an agent engine whose core is written in Zig and published as fx-core.wasm in the libfx package. Because it is a WebAssembly module, any program with a WebAssembly runtime can load it and call it like a library. We load it in our backend.
We run it with wazero, a WebAssembly runtime written in pure Go, in interpreter mode. The interpreter never generates machine code, so no code compiled from the module runs in our process. The module has no filesystem, no network, and no environment beyond a few settings we pass in.
The fx wasm module talks to the host in two ways:
- JSON-RPC on stdin and stdout, to open a session, send a prompt, steer, cancel, and restore a saved conversation.
- Host functions, functions our Go code provides and the module imports. They are the only way it can affect anything outside its own memory.
Not available
fx-core.wasm
- Zig, compiled to WebAssembly
- interpreted by wazero
Go host
model request
sends it to the model proxy with the agent's credential
tool call
runs a Fractal, shell or file tool
journal events
stores them in Postgres before the turn continues
attachments
passes images in and conversation snapshots out
steering
delivers a queued message at the next safe point
Not available
fx-core.wasm
- Zig, compiled to WebAssembly
- interpreted by wazero
Go host
The module is portable. The same module can run anywhere with a WebAssembly runtime, from a browser to a program written in Go or Rust, as long as the host provides its functions.
What fx handles for us
A model API answers one request at a time. An agent keeps going: it calls the model, runs the tools the model asks for, sends back the results, and calls the model again, often dozens of times for one task. fx handles that work:
- The turn loop. Build the request, stream the response, detect tool calls, wait for their results, append them in the format the provider expects, and call the model again until it stops.
- Context management. When a conversation nears the model's context window, it asks the model for a structured summary and continues from that.
- Durability. It emits a journal of everything that happens, and it can resume a turn that was interrupted in the middle.
- Turn control. Steering takes a new message at a safe point between model calls, and cancellation ends a turn cleanly.
- Many models. It speaks a generic chat API, so one engine works for Claude, GPT, and other models in our catalog.
We did not have to write any of this.
What we added on
While fx handles the core harness features, we implemented the following additional functionality:
- Subagents. The agent can hand parts of a task to helper agents. Each one is another fx engine with its own conversation, working in the parent's sandbox.
- Background processes. The agent can start a command, such as a dev server, that keeps running after the tool call returns. Fractal users can see it while it runs, and it keeps the sandbox awake until it exits.
- Shell and file tools. Commands and file edits run in the agent's sandbox, which starts on the first call that needs it.
- Repository instructions. When the agent works in a repository, we add its AGENTS.md and CLAUDE.md to its context.
- Model settings. We set how hard each model thinks, and handle differences between providers' APIs, such as prompt caching for Claude.
Built into fx
Turn loop
model calls and tool calls until done
Compaction
summarizes long conversations
Journal and resume
picks up an interrupted turn
Steering
takes new messages mid-turn
Cancellation
ends a turn on request
Many models
one chat API for every provider
Added by Fractal
model requests
Model settings
how hard the model thinks, and caching
Errors
stops a turn that keeps failing
tools
Tools and sandbox
shell and file tools; the sandbox starts on first use
Subagents
helpers that take on part of the task
Background processes
commands that keep running
Repository instructions
AGENTS.md and CLAUDE.md
around the engine
Context windows
each model's real limit
Stopping
ends a turn when a cancel is ignored
The future of harnesses
fx is not the only harness built this way. On October 1, Earendil, the company behind the Pi coding agent, released Pi Durable, an experimental framework for long-running agent applications. An application opens the harness inside its own process and supplies the storage and the environment where tools run, which can be a laptop, a remote VM, or an in-memory sandbox.
These harnesses let a product choose where the agent loop runs and use a sandbox only for tools that need one. We're excited to see more harnesses take this approach.