Design and implementation
How YoloFS stages mutations cheaply, snapshots without destroying history, and gates accesses through evolving rules — and how it's wired into Linux. Drawn from §4 of the paper.
The two gaps from the study imply five requirements for any agent-native filesystem:
And, of course, performance — every access sits on the critical path of an agent session.
YoloFS is a Linux stackable filesystem that interposes between the agent and the underlying filesystem. The user mounts YoloFS with a project-local config file, then runs an agent either inside or through it. To the agent, file operations look normal. To the user, the session is no longer a stream of opaque commands.
User process / AI agent
│
▼ VFS syscall
┌──────────────────────────────────────────────┐
│ YoloFS │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ Permission │ → │ Staging │ │
│ │ gating │ │ layer │ │
│ └────────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────┘
│ vfs_*() on lower FS
▼
Lower filesystem (ext4 / xfs / …)
For every VFS operation the permission gating layer runs first: it
resolves the effective rule for the path. If the rule is
ask, the thread sleeps until the userspace daemon answers.
If the rule is allow or read-only, the staging layer
then routes the operation: reads come from the staged inode if the file
has been modified, otherwise from base; writes go to staged inodes.
Final I/O is delegated to the lower filesystem via vfs_*().
YoloFS is a kernel module + userspace CLI. The kernel handles the critical path; the CLI handles higher-level operations (diff, snapshot management, commit) by reading shared on-disk state and issuing ioctls. The mount sits on top of the entire root filesystem to ensure completeness.
Mirroring the base directory tree in an upper layer (à la OverlayFS) is too expensive: creating a file in a nested directory requires creating all its parent directories in the upper layer; renaming a file triggers a full copy even without content change; renaming a directory recursively copies the entire subtree. YoloFS sits on the critical path of every agent operation — it cannot pay this cost.
YoloFS uses three structures, kept independent on purpose:
ino. New files and truncating writes
(O_TRUNC) skip the copy and allocate empty. After this
initial allocation, file I/O passes through to the lower filesystem
with no further indirection.
S p ino (stage), R src dst (rename),
D p (delete). The kernel only writes; the CLI reads the
journal to audit, diff, or commit.
echo > file doesn't read the original; it allocates an empty staged inode directly.Audit and commit are user-driven. The journal and file store are ordinary files on the base filesystem; the CLI parses the journal to build a diff at any point. Commit replays journal actions onto the base; abort drops the staged file store and clears the override tree.
ZFS, Btrfs, and WAFL support rollback by restoring a snapshot and discarding everything after. For an agent, that erases the evidence of the mistake: the user can no longer inspect the abandoned actions, and the agent cannot return to them later if the rollback itself was wrong.
YoloFS keeps a single global generation counter incremented on every snapshot or travel. Each StagedFile records the generation it was created in. When a staged file is opened for writing and its generation is stale, YoloFS performs copy-on-write — allocating a fresh file rather than overwriting the old one. Old generations stay alive as travel targets while the active branch grows.
Snapshots and travels are markers in the same append-only journal:
P name for snapshot, T name g for
a travel to generation g. Markers partition the journal
into segments. A travel makes the segments between target and
current state dead: they remain in the journal for audit and as
future travel targets, but no longer contribute to the staged view.
Liveness is itself dynamic — traveling can resurrect dead segments.
When the agent travels, the CLI computes segment liveness, replays the live journal segments in order to rebuild the override tree at the target generation, serializes the result, and hands it to the kernel via an ioctl. The kernel atomically swaps in the new override tree. Common operations like lookup and readdir stay O(1) regardless of how many snapshots exist — the kernel only ever sees the current tree.
Unix DAC can't help — the agent runs as the user. Landlock, AppArmor, and SELinux are monotonically restricting: tighten only. Mount namespaces are monotonically expanding: expose only. In practice, broad policies allow harmful accesses; narrow policies block legitimate work and push users to disable safety entirely.
Each path can be one of five states:
readdir.readdir skips it, stat/open behave as if absent.
The effective permission is computed during path lookup: walk root →
target, carrying the current state and replacing it whenever a more
specific rule is encountered. The result is cached on the in-memory
inode (where VFS's inode_permission check fires).
A global version number guards the cache. When a rule is added or removed, YoloFS bumps the version — no subtree traversal. On the next access, a stale inode walks up the dentry chain until it finds the nearest ancestor with a rule. Revalidation cost is proportional to path depth, not subtree size.
When access hits an ask state, the kernel blocks the thread and enqueues a request — path, operation, process name — for the userspace daemon. The daemon answers with allow/deny and may install a rule for future accesses, at any path (not just the one that triggered). Common pattern: install on a parent so the next 100 accesses to the subtree don't ask again.
Why this matters for friction. Codex's "don't ask again for
sed -i" rule is either too broad (allow any in-place
edit) or too narrow (a 300-char one-liner that won't recur). YoloFS's
rule sits on the file path the agent actually touched — so
it generalizes correctly, regardless of which command issued the syscall.
.yolofs/ in the project. File contents go in files/, sharded into subdirectories to avoid huge flat directories. The journal is at .yolofs/journal.yolofs.toml in the project root: rules, mount options, ask defaults, timeouts, checkpoint policy.PreToolUse hook for Bash to route shell commands through the YoloFS CLI, so every command runs inside the staged sandbox.For an end-to-end CLI walkthrough — init, rules, ask prompts, diff, travel, and commit — see the demo on the home page.
| Aspect | YoloFS | OverlayFS |
|---|---|---|
| Model | Explicit commit / abort with checkpoints | Live union — upper is the state |
| Truncating write | Zero-copy (empty inode) | Full copy-up, then truncate |
| Rename | Zero-copy via dirent metadata | vfs_rename() with copy-up |
| Lookup | One lookup (override tree → base) | Two lookups (upper + lower) |
| On-disk format | Flat inode store + journal — any base FS | Requires whiteout support (ext4/xfs) |
| Aspect | YoloFS | Landlock |
|---|---|---|
| Default policy | Ask (block + prompt) | Deny (handled rights only) |
| Overlapping rules | Nearest-ancestor wins (both directions) | Additive only — can't deny child of allowed parent |
| Dynamic rules | Add / remove / change at runtime | Immutable after enforce |
| Steady-state cost | O(1) via inode cache + version counter | O(depth × log n) per ancestor |
| Scope | Per-mount | Per-process (cred-attached) |
Native CoW snapshots cover predefined namespaces and target archival or backup workloads. They do not adapt to changes made by an interactive agent (granularity is fixed) and they support only destructive rollback. YoloFS snapshots adapt to the agent's actual changes, work on any base filesystem, and preserve the full branching history so the user can audit abandoned branches and the agent can travel forward again.
Git handles text-based source files inside one repository. Agents
operate on the version history itself (git reset --hard,
git clean) and routinely destroy uncommitted work that
git alone cannot recover. YoloFS treats git commands as ordinary file
operations — so the user can recover even if the version history itself
is corrupted by the agent.
Single-file I/O matches bare ext4. Metadata operations are typically faster than OverlayFS — sometimes faster than ext4 for files that are already staged. Snapshots scale to hundreds without slowing reads or writes. On a real kernel-development workflow (build, edit, rebuild, commit, across 100k files) YoloFS adds ~3.5 s of commit overhead to a workload that's otherwise as fast as ext4; OverlayFS is 18% slower; BranchFS (a recent FUSE-based research filesystem) adds 2 minutes to a 20-second build. Full numbers are in §6 of the paper.
For how we evaluated all this, see the benchmark page and the performance page.