Chimera: Sandboxing Agents in Userspace
AI coding agents can run arbitrary commands, often on a machine they share with you. Typically that's fine. The agent runs your project's test suite, greps the code, and installs dependencies. However, it only takes one hallucinated rm -rf or poisoned npm install for the coding agent to corrupt the machine you're working on. So you want to sandbox your agents.
However, the existing sandboxing solutions all come with friction. Virtual machines and containers give you strong isolation, but they need images, setup, and often a daemon. They also cut the agent off from the host, so you end up mounting half your filesystem back in and losing the isolation you were after. Kernel sandboxing mechanisms such as Linux seccomp and macOS's sandbox-exec are closer to the process. Still, they're platform-specific, awkward to compose, and they can only allow or deny operations, which is not that helpful. The tension is that you want the agent to use the host, your files, your toolchain, your caches, without being able to corrupt it.
That is why I built Chimera. Chimera is a userspace sandbox for running code you don't trust. It needs no virtual machine, no container, no special kernel features, and no privileges. Chimera is an ordinary program, so it works wherever your code already runs. Under the hood, Chimera runs unmodified binaries through dynamic binary translation and intercepts every system call the guest makes, so the sandbox decides what each one does: forward it to the host, deny it, or virtualize it. Chimera also comes with a copy-on-write filesystem out of the box, which allows you to modify the host filesystem without breaking it.
A Quick Tour
The best way to get a feel for Chimera is to run something in it. First, install the command-line tool:
> cargo install --git https://github.com/penberg/chimera chimera-cli
You run programs under Chimera with the chimera run command:
> chimera run --rm /bin/echo 'hello, sandbox'
hello, sandbox
Filesystem under Chimera is copy-on-write overlay by default. The sandboxed process sees your real files and can read and write them freely, but the writes land in a private workspace instead of the host. For example, if we start a shell and perform a destructive operation:
> chimera run bash
> rm -rf *
> git status | head
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: AGENTS.md
deleted: ARCHITECTURE.md
deleted: CLAUDE.md
deleted: Cargo.lock
Inside the sandbox, the damage looks real. But the host filesystem is still intact:
> exit
chimera: workspace kept; continue with:
chimera run -w 616396ae /bin/bash
> git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
However, we can resume a session in the workspace with the chimera run -w command and the changes are still there:
> chimera run -w 616396ae /bin/bash
> git status | head
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: AGENTS.md
deleted: ARCHITECTURE.md
deleted: CLAUDE.md
deleted: Cargo.lock
Chimera creates workspaces for every session unless you explicitly make the session ephemeral with the --rm command. You can see all the workspaces with the chimera workspace list command:
> chimera workspace list
ID AGE SIZE COMMAND
616396ae 2m 18K bash
You can also see a diff of the workspace against host filesystem:
> chimera workspace diff 616396ae
M /home/penberg/.bash_history
D /home/penberg/src/penberg/chimera/AGENTS.md
D /home/penberg/src/penberg/chimera/ARCHITECTURE.md
D /home/penberg/src/penberg/chimera/CLAUDE.md
D /home/penberg/src/penberg/chimera/Cargo.lock
D /home/penberg/src/penberg/chimera/Cargo.toml
D /home/penberg/src/penberg/chimera/LICENSE.md
D /home/penberg/src/penberg/chimera/Makefile
D /home/penberg/src/penberg/chimera/README.md
D /home/penberg/src/penberg/chimera/cli
D /home/penberg/src/penberg/chimera/perf
D /home/penberg/src/penberg/chimera/runtime
D /home/penberg/src/penberg/chimera/rust-toolchain.toml
D /home/penberg/src/penberg/chimera/scripts
D /home/penberg/src/penberg/chimera/testing
This turns agent sandboxing into the same workflow you already use for agent code changes: let the agent do whatever it wants, then review the diff and decide what to keep. Nothing touches the host until you say so.
How It Works
Chimera is built on system call interception. A process can only affect the world outside its own memory through system calls, so a sandbox that controls the syscall boundary controls everything the process can do to the host. Today, Chimera intercepts system calls with same-ISA dynamic binary translation, because it is the general solution: it needs no kernel support and works the same everywhere. When you run a program under Chimera, the runtime loads the binary into its own address space and translates its code one basic block at a time into a private code cache, then executes from the cache. Because the guest and the host share the same instruction set, translation is mostly a memory copy: ordinary arithmetic, memory, and logic instructions run natively, at native speed. The instructions that matter — branches and, crucially, system calls — are rewritten to hand control back to the runtime. Translation is one mechanism, though, not the design: we're also exploring lighter-weight interception such as Linux's syscall user dispatch.
Whatever the interception mechanism, every system call the guest issues lands in the runtime's handler instead of the kernel. The handler decides what each call does. It can forward the call to the host kernel unchanged, which is the default and makes the wrapped process behave like a native one. It can deny the call. Or it can virtualize it — answer the call itself without involving the kernel. The copy-on-write filesystem is exactly that: filesystem syscalls are intercepted and redirected through an overlay, so reads fall through to the host while writes land in the workspace.
Because everything runs in a single ordinary process, there is nothing to set up and nothing to privilege. No image to build, no daemon to run, no kernel module, no root. The trade-off is that this is not hardware-enforced isolation like a virtual machine — it is a control point on the syscall boundary, which is the right fit for confining code you are running on purpose but don't fully trust.
The CLI is one policy built on this mechanism, but Chimera also ships as a Rust library, and the interception point is programmable. You implement the SystemCalls trait to decide how each guest syscall is handled:
use chimera::{Sandbox, SystemCall, SystemCalls, host_syscall};
struct Tracer;
impl SystemCalls for Tracer {
fn handle(&mut self, call: &mut SystemCall) {
eprintln!("syscall {}", call.number);
call.set_result(host_syscall(call));
}
}
A handler that logs every call and forwards it is an strace. A handler that denies everything but an allowlist is a sealed sandbox. A handler that answers filesystem calls from a virtual filesystem never has to touch the host at all. Both the strace and the allowlist sandbox ship as worked examples in the repository.
If you want the full design — how program loading, translation, dispatch, and threading work in detail — it is written up in our tech report, Towards Sandboxing Untrusted Agents in Userspace.
What's Next
Chimera is early and in active development. It supports Linux/x86 today, with a Darwin/arm64 port in progress, and there is performance and compatibility work ahead.
I also want to explore integrating Chimera with AgentFS, the filesystem for agents that stores an agent's files, state, and toolcall audit trail in a single SQLite database. AgentFS ships an experimental agentfs run sandbox built on Linux namespaces and a FUSE mount. The chimera run command is essentially a better version of the same idea. As Chimera already intercepts every filesystem syscall in userspace, it can serve them directly from AgentFS: no namespaces, no FUSE, and the same behavior on every platform.
But there is a bigger vision behind Chimera. Because Chimera owns the syscall boundary, the sandbox's view of the world is programmable. The copy-on-write workspace does not have to live on local disk at all: it could be backed by object storage, so an agent's entire filesystem state — every workspace, every diff — lives on S3, for example, and can be resumed, branched, or reviewed from any machine. The same goes for the network: socket syscalls pass through the same interception point, so the sandbox can decide which hosts an agent may talk to, record its traffic, or virtualize connections entirely. Filesystem and network both become policy over syscalls.
If you want to give Chimera a go with your own agents, the source code is at github.com/penberg/chimera.