Skip to content
emmettluPublic

About

tracefs: a versioned, branching file system for AI agents (kernel module + userspace daemon)

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŒ English ยท ็ฎ€ไฝ“ไธญๆ–‡

๐ŸŒณ tracefs

git for everything your agents touch, built into the file system

ci Linux โ‰ฅ 6.8 Rust no FUSE macOS ยท Windows MIT + GPL-2.0

๐ŸŒฟ Give every agent its own copy-on-write branch of your project.
๐Ÿ“ธ Record every tool call as a changeset.
๐Ÿ”€ Merge when the task is done, and let a third agent settle the conflicts.
โšก No FUSE. Every byte goes through kernel file systems.

         ๐Ÿง‘ you (vim, cargo, git)          ๐Ÿค– agent A              ๐Ÿค– agent B
                 โ”‚                             โ”‚                       โ”‚
                 โ–ผ                             โ–ผ                       โ–ผ
        ~/proj  โ”€โ”€ main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ branch A โ”€โ”€โ”      โ”Œโ”€โ”€ branch B
                 โ–ฒ  every write here  โ”‚   (own mount    โ”‚      โ”‚   (same path,
                 โ”‚  becomes history   โ”‚    namespace)   โ”‚      โ”‚    own copy)
                 โ”‚                    โ”‚                 โ–ผ      โ–ผ
                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 3-way merge, follows renames โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           conflicts โ†’ ๐Ÿค– resolver agent โ†’ ๐Ÿง‘ you

๐Ÿ’ก tracefs (AgentComputerFS) is the user-space side: tracefsd, the tracefs CLI, the SDKs and the plugins. It has nothing to do with Linux's own tracefs at /sys/kernel/tracing. Because of that one, the kernel file system in kernel/ is called acfs: two file systems with the same name would collide in the kernel.


๐Ÿค” Why

Coding agents write to your disk. Several of them at once, sometimes in your working tree while you're also in it. Then you get to answer:

  • โ“ What did it just change? Not "what did it say it changed".
  • โ“ Can I undo that one tool call and keep the ten after it?
  • โ“ Can two agents edit the same file at the same time without stepping on each other?
  • โ“ Can I roll back what an agent did without killing the shell, the editor and the dev server that have files open in that directory?

โœ… tracefs answers yes to all four, without asking the agent harness to cooperate.

โœจ What you get

๐ŸŒฟ A branch per agent tracefs run -- <agent> starts the agent in its own mount namespace. Every workspace it touches becomes its own btrfs snapshot, mounted at the same absolute path, so tool output and paths need no translation. Creating one is O(1): no data is copied.
๐Ÿ“ธ Changesets, not commits Each tool call can be an atomic snapshot of all the agent's branches together. The process is frozen while it's taken (41~56 ms with 10k changed files in the prototype, 91 ms in the current daemon) and nothing else pauses. Nothing to git add.
๐Ÿ‘€ Nothing gets past it Once a directory is registered, tracefs mounts its main over it. Edits from you, your editor or a build script are recorded as auto changesets once the writes stop. Undo writes back through the mount, so open files and running processes in the directory aren't disturbed.
๐Ÿ”€ A merge that follows renames Three-way merge by file identity (inode numbers within one snapshot lineage), then by content. If one agent renames a directory while another edits a file inside it, the edit ends up at the new path. Text conflicts go to git merge-file.
๐Ÿค– A third agent resolves conflicts --resolver '<cmd>' gets a directory with TASK.md, conflicts.json and base/ours/theirs for each conflict. It writes resolutions.json, and tracefs merges again. Anything it can't resolve is left for you.
โช Undo at any granularity reset to any point, revert one changeset, a range (one agent turn), or a whole session. Every undo is itself a new changeset, so history only grows.
๐Ÿ“œ Merge rules .tracefsignore keeps build output out of history and out of merges. .tracefsmerge sets a strategy per pattern: ours, theirs, newer, union, or unit=<name>, which decides a group of files together, so a lockfile always comes from the same side as its manifest.
โ˜๏ธ Incremental push/pull Snapshots ship as btrfs send -p streams plus a sha256 manifest, to any directory: local disk, NFS, or an S3 mount.
๐Ÿงน History that stays small Automatic snapshots are kept in full for 24 h, then hourly for 7 days, then daily. Their log and diff summaries are kept forever.
๐Ÿ’ฅ Crash-safe Branch rewrites are journaled. Agents keep running if tracefsd restarts, and tracefsd finds them again afterwards.
๐Ÿง A kernel file system kernel/ is a separate in-tree Linux file system with native branches, a diff ioctl that skips shared subtrees, and block-sharing copies. See below.

โšก 30 seconds

# 1๏ธโƒฃ once: hand a directory to tracefs (it must be under your home)
tracefs ws register proj --from ~/proj

# 2๏ธโƒฃ start two agents; each sees ~/proj, each gets its own branch
tracefs run -- pi        &
tracefs run --resolver 'my-agent "follow TASK.md"' -- claude

# 3๏ธโƒฃ meanwhile, edit ~/proj yourself; it's recorded too
tracefs log --ws proj -n 20
tracefs diff 01JD3Kโ€ฆ                 # what one changeset did
tracefs diff 01JD3Kโ€ฆ --patch         # โ€ฆwith unified diffs

# 4๏ธโƒฃ that tool call was a mistake
tracefs revert 01JD3Kโ€ฆ

# 5๏ธโƒฃ the whole session was a mistake
tracefs revert --session refactor-auth

๐Ÿ When an agent says a task is done (tracefs proc merge $TRACEFS_PROC), or when it exits, its branches are merged into main. Work that other agents merged in the meantime is merged back into its branch, and it keeps going from there. ๐Ÿค Two agents editing the same file is not an error: whoever finishes first merges cleanly, and only the second merge can conflict.

๐Ÿ”ง How it works

/var/lib/tracefs/
โ”œโ”€โ”€ ๐Ÿ—ƒ๏ธ meta.db           SQLite: workspaces, branches, snaps, changesets, journal
โ”œโ”€โ”€ ๐Ÿงฑ bases/<id>/       read-only subvolume: l/1 โ€ฆ l/n
โ”œโ”€โ”€ ๐ŸŒฟ branches/<id>/    one writable subvolume: l/1โ€ฆl/n + upper/ + work/
โ””โ”€โ”€ ๐Ÿ“ธ snaps/<id>/       read-only snapshot of a branch at a changeset
  • ๐Ÿฅž Data path: overlayfs on btrfs. Each branch is a single subvolume holding its lower layers, upper/ and work/. Inode numbers stay unique in the merged view, so find and cp -a behave. Copy-up is a reflink.
  • ๐ŸŒฟ Branches and snapshots: btrfs subvolume snapshots. They take O(1) time, are copy-on-write at block level, and work as incremental send streams for free.
  • ๐Ÿ‘‚ Change detection: inotify on upper/. Every write through the overlay lands there, and upper/ only contains directories that changed, so the number of watches stays small.
  • ๐Ÿ” Fast diff: btrfs send --no-data -p A B. The kernel walks only the parts of the two trees that differ, so the cost depends on the size of the change. The full upper-layer walk (v1) is kept as a check: the test suite runs both on every diff and fails if they disagree.
  • โœ๏ธ Merges write through the mount, using openat2(RESOLVE_BENEATH | NO_SYMLINKS | NO_XDEV). A file taken whole from one side is written with copy_file_range, which btrfs turns into a clone: no new space and no data written. Resetting a 1 GiB file took 1.3 s, and the result shares the snapshot's extents.
  • ๐ŸงŠ Agents: systemd-run --scope. The agent runs as you, with your environment, in a private mount namespace. The cgroup is used to freeze it for snapshots and to kill whatever it leaves behind.
  • ๐Ÿฉน Crash recovery. At startup tracefsd re-mounts workspaces, finishes or records half-done operations, finds running agents again by pid and start time, and merges whatever finished while it was down.

๐Ÿ“– Everything is specified, down to the invariants and the reasoning behind each decision, in AGENTS.md.

๐Ÿ“Š Numbers

Measured, not projected. Workload and machine are in AGENTS.md ยง8.

โธ๏ธ changeset pause, 10k changed files 41~56 ms (prototype, 3 workspaces), 91 ms (current daemon); other processes stall at most 0.7 ms
๐Ÿš€ tracefs run to the command starting, 3 workspaces 170 ms
๐Ÿ” diff of a 10-file changeset 17 ms
๐Ÿ“ merge a renamed 2,500-file directory 154 ms
๐Ÿค–ร—8 agents exit at once after editing one workspace all merged, no conflicts, in 771 ms
๐Ÿฆ€ cargo build, fio 4k random write same as native btrfs
๐Ÿ”Ž rg over the whole repo native +4%

โš ๏ธ One honest number: git status on 100k files is 14~20% slower than native, because of overlay metadata. core.untrackedCache / core.fsmonitor help.

๐ŸฅŠ Against the alternatives

๐Ÿ Head to head: same machine, same data

The three columns run on the same machine against the same base trees, and each is mounted the way it would be used: x86_64 NVMe, btrfs (compress=zstd:1), a Linux kernel checkout (~100k files) and the ripgrep repo, timed with hyperfine (script: tests/kernel/t07_perf.sh). fuse-overlayfs is the same layered design served through FUSE, so the gap between the last two columns is the cost of a trip to userspace on every operation.

workload ๐Ÿฅ‡ native btrfs โšก tracefs (kernel overlayfs) ๐Ÿข fuse-overlayfs
๐Ÿ”Ž rg over the whole repo baseline +4% 6.3ร— slower than tracefs
๐Ÿ“‚ git status, cold cache baseline +14% 87ร— slower than tracefs
๐Ÿ“‚ git status, hot cache baseline +17~20% not recorded
โœ๏ธ buffered writes baseline โ‰ˆ native 1.7ร— slower than tracefs
๐Ÿฆ€ cargo build (mid-size crate) baseline โ‰ˆ native not recorded
๐ŸŽฒ fio 4k random write baseline โ‰ˆ native not recorded

These are prototype runs on a machine that has since been retired. The raw output isn't in this repo. Other tools (git worktree, containers, other agent file systems) were not benchmarked here, so they get no numbers. ๐Ÿ™…

๐Ÿงญ How the approaches differ

๐ŸŒณ tracefs ๐ŸŒฒ git worktree ๐Ÿ“‹ copy the dir ๐Ÿข FUSE overlay ๐Ÿณ container overlay
making a branch costs O(1) snapshot a checkout of every tracked file a copy of every byte O(1) O(1)
untracked & ignored files come along โœ… โŒ only what's committed โœ… โœ… โœ…
edits recorded with no commit step โœ… per tool call + automatic โŒ โŒ โŒ โŒ
your own edits to the directory recorded โœ… โŒ โŒ โŒ โŒ
every agent sees the same path โœ… mount namespace โŒ another directory โŒ another directory โŒ another mount point โœ… inside the container
merging back โœ… 3-way, follows renames, resolver agent after you commit ๐Ÿ–๏ธ by hand ๐Ÿ–๏ธ by hand ๐Ÿ–๏ธ by hand
undo one tool call โœ… โŒ โŒ โŒ โŒ
data path โšก kernel โšก kernel โšก kernel ๐Ÿข userspace on every op โšก kernel
agent uses your shell, tools and env โœ… โœ… โœ… โœ… โŒ needs an image

๐Ÿ”Œ Plugins: works today on macOS and Windows too

sdk/portable gives agent plugins one interface with two backends:

backend when storage
๐Ÿง tracefsd Linux, inside tracefs run the daemon, as described above
๐Ÿชถ tracefs-lite everywhere else; no root, no VM ๐ŸŽ macOS: APFS sparse image + clonefile
๐Ÿง Linux: btrfs or a btrfs image + reflink
๐ŸชŸ Windows: an NTFS VHDX
npm install -g ./sdk/portable              # puts tracefs-lite on PATH
tracefs-lite init
tracefs-lite register proj ~/proj            # prints the path to work in
tracefs-lite branch proj agent1
tracefs-lite merge proj agent1 --prefer theirs
  • ๐Ÿฅง pi: pi -e sdk/pi/index.ts. Every assistant reply that writes files becomes a changeset, recorded in the session. /tree and /fork bring the files back to that point. /tracefs status|log|diff|undo|merge.
  • ๐Ÿ‹ DeepSeek Harness: dsh plugin --profile <name> add ./sdk/dsh. One changeset per step and a merge at the end of each turn. It also gives the model a tracefs tool so it can look at and undo its own work.
  • ๐Ÿงฉ Codex: codex plugin marketplace add emmettlu/tracefs, then install tracefs. Hooks record a changeset for every Bash / apply_patch / Edit / Write call and merge on Stop. A tracefs skill gives the model status / log / diff / undo / merge. Codex only runs a plugin's hooks after you trust them.
  • ๐Ÿช Anything else: call tracefs changeset --author <harness> --tool-call <id> from a hook (for example Claude Code's PostToolUse).

๐Ÿงฐ SDKs

One JSON request per line over /run/tracefs/tracefs-daemon.sock. The types are generated from schema/tracefs.schema.json, which is generated from the Rust protocol types, so neither side can drift. ๐Ÿ”’

// ๐ŸŸฆ TypeScript
import { Client } from "@dopamine-org/tracefs";
const log = await new Client().call("log", { ws: "proj", n: 10 });   // fully typed
# ๐Ÿ Python, zero dependencies
from tracefs_sdk import Client
diff = Client().call("diff", {"a": "01JD3Kโ€ฆ", "patch": True})

๐Ÿง Bonus: a kernel file system

kernel/ (GPL-2.0) is the same idea as its own Linux file system, acfs: mount -t acfs, with branches as a first-class feature.

mkfs.acfs /dev/sdX
mount -t acfs                  /dev/sdX /work   # main
mount -t acfs -o branch=agent1 /dev/sdX /a1     # another branch, same device
  • ๐ŸŒฒ Copy-on-write B+ trees with lazy reference counts. Creating a branch adds one reference to a root.
  • ๐ŸŽ›๏ธ ACFS_IOC_BRANCH_CREATE/DELETE/LIST/OPEN, and ACFS_IOC_DIFF, which walks two trees together and skips every subtree they share.
  • ๐Ÿงฌ copy_file_range, FICLONE and FIDEDUPERANGE share blocks, even across branches.
  • ๐Ÿชช A file has the same inode number in every branch it shares. Files created in different branches never collide.
  • ๐Ÿ›ก๏ธ Two alternating superblock slots, crc32c on all metadata, commits with preflush + FUA, and crash consistency without a log.
  • ๐Ÿ‘ค Users can snapshot a file system they own without CAP_SYS_ADMIN.
  • ๐Ÿงช Comes with mkfs.acfs, fsck.acfs and selftests (basic, concurrent, crash, stress) that run in QEMU.

๐Ÿ“– Format and ABI: kernel/Documentation/userspace-api/ac/acfs.rst.

๐Ÿ“ฆ Get it

Requirements: ๐Ÿง Linux โ‰ฅ 6.8 with btrfs, overlayfs and loop; systemd; btrfs-progs, git, diffutils. ๐Ÿ’พ The state directory doesn't have to be on btrfs: if it isn't, tracefsd creates a sparse btrfs image and loop-mounts it with direct I/O.

cargo build --release
sudo bash deploy/install.sh        # tracefsd.service + tracefs.slice limits
  • ๐Ÿน Arch packages: packaging/arch/PKGBUILD.
  • ๐ŸŽ๐ŸชŸ macOS/Windows: use tracefs-lite (above). tracefs-core also builds and tests there.

๐Ÿงช Tests. CI runs:

  • the plugins and Rust on Linux, macOS and Windows;
  • 15 root integration suites against real btrfs and systemd, each on a throwaway loop image, under memory-pressure guards;
  • a seeded random-operation fuzzer that checks diff/revert/reset/merge against a local replay;
  • the kernel module's selftests under QEMU/KVM.

See AGENTS.md โ€บ ๆต‹่ฏ•.

๐Ÿšซ What it isn't

  • ๐Ÿ”“ Not a sandbox. An agent runs as you and can do anything you can. Only its view of the workspaces is replaced by its own branches. If you need to contain a hostile agent, use a VM.
  • ๐Ÿ“ก Not live sharing. Agents don't see each other's unmerged writes. They share at merge time, by design.
  • ๐Ÿงพ Not per-write auditing. The unit of history is the changeset.

๐Ÿ“„ License

User space: MIT. kernel/: GPL-2.0.


About

tracefs: a versioned, branching file system for AI agents (kernel module + userspace daemon)

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages