by pid1lab

A filesystem your coding agent can't break.

Point agentfs at a directory and run your agent inside it. Reads come from your real files; every write lands in a copy-on-write layer alongside them. Snapshot it, diff it, undo it — or throw it away and your project is exactly as you left it, byte for byte.

agentfs quick ~/code/api -- claude

agentfs — zsh
$ agentfs quick ~/code/api -- claude agentfs: workspace: kernel-overlay (mounted inside the sandbox) agentfs: entering sandbox 'api' (project at /home/you/code/api) … the agent works: edits 14 files, deletes 3, runs the tests … agentfs: checkpoint a41f0c8e2b17 (idle) agentfs: checkpoint 7c3d9be05a44 (idle) agentfs: auto-snapped → 7c3d9be05a44 (auto-1785904837) $ agentfs diff api a41f0c8e2b17 auto-1785904837 M src/orders.rs M src/lib.rs D src/legacy.rs A src/orders/refund.rs $ git -C ~/code/api status --porcelain (nothing — your working tree was never written to) $ agentfs undo api # didn't like it restored to a41f0c8e2b17 $ agentfs apply api # or: promote it for real 4 changes written to /home/you/code/api

Your files are never written to

The host directory is mounted read-only from inside. Writes copy up into a separate layer, so restore is a real rollback rather than a best-effort undo — and doing nothing at all leaves the project untouched.

Checkpoints it can't skip

The trigger runs outside the sandbox, so the agent has no way to suppress one. It can ask for an extra checkpoint at a turn boundary; that channel only ever adds. Snapshots are additive, which is why forging the request is a non-event.

Kernel speed by default

Where the kernel can serve the overlay, agentfs uses it — probing the actual mount rather than guessing. An incremental cargo build runs at 1.02× the speed of no sandbox at all — the numbers — and it falls back to FUSE where it can't.

Quick start

  1. Install the prereqs

    sudo apt install -y build-essential pkg-config libfuse3-dev fuse3 rsync

    Fedora: dnf install fuse3-devel fuse3 rsync. Arch: pacman -S fuse3 rsync. Linux only for the sandbox — see below.

    On Ubuntu 24.04+, rootless mode also needs unprivileged user namespaces turned back on: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0. That isn't specific to agentfs — every rootless container runtime wants it.

  2. Build it

    cargo build --release

    One binary, no daemon, no service to keep running. It runs rootless by default — no sudo for normal use.

  3. Run your agent inside

    agentfs quick ~/code/api -- claude

    Derives a project name from the directory, attaches it, and drops the agent in. Your dotfiles and tools are visible inside, with credential paths masked — so Claude Code, cargo and git behave normally. Leave off -- claude to get a shell instead.

  4. Decide afterwards

    agentfs diff api <from> <to>  # what changed
    agentfs undo api               # walk it back
    agentfs apply api              # promote it into your real tree

    Nothing reaches your working tree until apply. Until then the whole session lives in the project's layer, and agentfs list shows every checkpoint you can return to.

Commands

CommandWhat it does
agentfs quick <dir>Init, attach and run in one shot. Project name from the directory's basename.
agentfs init <name>Create a project under ~/.agentfs/.
agentfs mount <name> <dir>Attach a host directory as the project's read-only lower layer.
agentfs run <name> -- <cmd>Run a command inside the sandbox. Defaults to $SHELL.
agentfs snap <name> [tag]Snapshot the current layer, optionally under a name.
agentfs list <name>Every snapshot and checkpoint, with the current one marked.
agentfs log <name>History from the current position back.
agentfs diff <name> <a> <b>Path-level diff between two snapshots.
agentfs restore <name> <ref>Put the layer back to a snapshot. Append-only: the state you left is still there.
agentfs undo <name>One step back, without naming a snapshot.
agentfs apply <name>Write the agent's changes into the real directory. The only command that touches it.
agentfs status [name]Position, active sandbox, mounts, layer size.
agentfs gc <name>Collect snapshots nothing points at any more.

Useful flags

FlagEffect
--mount-backendauto (default), kernel to require the fast path, fuse to pin the portable one.
--snapshotsWhen to snapshot automatically: all, checkpoints, exit, none.
--checkpoint-intervalLongest gap between automatic checkpoints for an agent that never pauses.
--ro-bind / --bindExpose an extra path read-only, or read-write. RW writes leak to the host and aren't snapshotted.
--show-bindsPrint the resolved mount set and which backend was chosen. The first thing to reach for when something isn't visible inside.

Every command, every flag, and how projects, layers and snapshots fit together — read the docs.

Checkpoints land where the agent stopped typing

A watcher outside the sandbox notices when writing goes quiet and snapshots there — a turn boundary, physically. If the agent never pauses, a ceiling fires anyway so a long build still produces restore points; those are labelled as taken mid-operation, because every file in them is whole but the set of them is a moment rather than a resting point.

Taking one freezes the whole process tree for the walk, so nothing is caught halfway through a write. And because the agent shares a user and a process tree with whatever launched it, no proof-of-identity check would survive contact — which is exactly why the trigger lives outside, and why the in-sandbox channel can only ever add a checkpoint.

What agentfs doesn't do

The threat model is "the agent might make mistakes, or follow bad instructions, while editing my code." Three things it is not, said here rather than discovered later.

It isn't a VM

It doesn't claim isolation against an agent deliberately trying to break out through a kernel exploit. Within its scope — accidents, overconfident refactors, a prompt-injected instruction to "clean up" your repo — your source is protected by construction. Outside it, use a real VM.

The network is shared

The sandbox has no network namespace yet, so the agent reaches the public internet, localhost services, and anything on your LAN or VPN exactly as you can. Filesystem isolation is the value on offer today; network isolation is designed but not shipped.

Linux, for now

The sandbox is built from mount and user namespaces, which macOS has no equivalent of. The snapshot store and the overlay are already portable and the sandbox crate is platform-split, so a Seatbelt-based macOS port is a known shape of work rather than an open question — it just isn't done.

It's what Lyra runs on

agentfs came out of building Lyra, where an AI agent edits your documents while you're looking at them. The guarantee that had to hold there — that nothing the agent does can damage the thing you care about, and that any moment is recoverable — is the same one it offers here, as a tool you can point at any directory.