Checkouts for agents: isolated, copy-on-write views of any folder, a git repository or not, opened without copying it. Agents work in the checkout; you review with diff and merge back with a three-way apply. Checkouts can be snapshotted, forked, and attached to another machine, where their content arrives on first read.
One daemon serves every checkout as a folder of a single mount: NFSv3 on macOS, FUSE on Linux, SMB or WinFsp on Windows. No root, and no kernel extension beyond WinFsp where you install it.
Opening a folder sorts every path into a class. source paths are captured: they are what diff, apply and snapshots see, and the only bytes that leave the machine. cache and local paths (build outputs, ignored files, secrets) show the live folder until the checkout writes them. hidden paths are absent. Writes go to the checkout's own copy-on-write layer, so the folder is never written until you apply. In a git repository the checkout gets a private git directory: commit freely, then apply --branch NAME to bring the commits back.
ovnfs reads and writes git repositories itself, so it needs no git installation; fetches use git when it is on the PATH. Verbs start the daemon when none is running, and start, stop, restart and status manage it. restart swaps in the daemon of the binary you run, e.g. after an upgrade, leaving an NFS or SMB mount and the shells inside it in place.
- new opens a checkout on a folder, git revision or snapshot; run uses a disposable checkout that is removed afterwards.
- snap freezes a checkout's changes into a snapshot; fork opens a second checkout on one.
- diff lists source changes since a snapshot, optionally as a git patch; apply merges them back with a three-way merge.
- grep and glob search the daemon without traversing the mount.
- ls, prune and rm manage checkouts and their snapshots.
- attach, send, pull and push move a checkout to another machine over ssh, fetching content lazily on first read.
- explain reports which class a path gets and which rule decided; completion provides bash, zsh and fish completion.
ovnfs isolates files, not processes: it is not a sandbox.
README
ovnfs
Checkouts for agents: isolated, copy-on-write views of any folder, a git
repository or not, opened without copying it. Agents work in
the checkout; you review with diff and merge back with a three-way apply.
Checkouts can be snapshotted, forked, and attached to another machine, where
their content arrives on first read.
One daemon serves every checkout as a folder of a single mount: NFSv3 on
macOS, FUSE on Linux, SMB or WinFsp on Windows. No root, and no kernel
extension beyond WinFsp where you install it.
Install
Linux and macOS:
curl -fsSL https://stencil.so/ovnfs.sh | sh
Windows (PowerShell):
irm https://stencil.so/ovnfs.ps1 | iex
The installers download the latest release binary (Linux, macOS and Windows on
amd64 and arm64) from build.stencil.so, check its SHA-256 and put it in
~/.local/bin, or on Windows in %LOCALAPPDATA%\Programs\ovnfs, added to the
user PATH. OVNFS_INSTALL_DIR picks another folder, --version v0.2.3
(-Version on Windows) another release. With Go (see go.mod):
go install github.com/stencil-hq/ovnfs@latest
go build -o bin/ovnfs . builds a clone. ovnfs reads and writes git
repositories itself, so it needs no git installation (fetches use git when it
is on the PATH); on Linux it needs
fusermount3 (the fuse3 package). ovnfs version prints the build;
ovnfs update replaces it with the latest, through go install when that
built it, and ovnfs restart then moves the daemon onto it.
GitHub releases carry the same
binaries as archives.
Quick start
cd ~/src/app
cd "$(ovnfs new)" # starts the daemon, prints the checkout's path
git status # same status as ~/src/app; nothing is written there
# ...let the agent work...
ovnfs diff app -p # what changed
ovnfs apply app # merge it back into ~/src/app
cd ~/src/app && ovnfs rm app # remove the checkout and its unused snapshots
More, from ~/src/app:
ovnfs run -- make test # a disposable checkout: run, then remove
ovnfs new --rev main # start from a revision instead of the working tree
ovnfs attach app --to devbox # the same checkout on another machine, fetched lazily
ovnfs send . devbox:src/app # attach over ssh, installing ovnfs there first if missing
ovnfs push app # copy what devbox still reads from here, so it works with this machine off
ovnfs grep 'TODO' app # search in the daemon, without traversing the mount
ovnfs glob '*.go' app # matching paths, recursively and ignore-aware
ovnfs ls . # the checkouts of this folder
ovnfs prune . --idle 7d # remove those untouched for a week (--dry-run first)
ovnfs help lists every verb, grouped by what they do and coloured on a
terminal (--color auto|always|never, NO_COLOR honoured; a pipe gets plain
text). Bash, zsh and fish completion come from the same grammar:
eval "$(ovnfs completion bash -c)", or ovnfs completion zsh -c for the
shell to source. Verbs start the daemon when none is running;
start, stop, restart and status manage it, serve runs it in the
foreground. restart swaps in the daemon of the binary you run, e.g. after an
upgrade, leaving an NFS or SMB mount and the shells inside it in place. stop
fails while something uses the mount; a second stop forces the unmount.
How it works
Opening a folder sorts every path into a class. source paths are captured:
they are what diff, apply and snapshots see, and the only bytes that leave
the machine. cache and local paths (build outputs, ignored files, secrets)
show the live folder until the checkout writes them: a path it writes or
deletes stays its own from then on, and apply never carries it back.
hidden paths are absent. Built-in rules
handle the common cases; .o2/ovnfs.yml and --rule override them, and
ovnfs explain PATH says which rule decided.
Writes go to the checkout's own copy-on-write layer, so the folder is never
written until you apply. In a git repository the checkout gets a private git
directory: commit freely, then apply --branch NAME to bring the commits back,
or git fetch ovnfs/NAME them from its git remote.
ovnfs isolates files, not processes: it is not a sandbox.
Documentation
Configuration: classes, rules, .o2/ovnfs.yml and ovnfs config, where state and checkouts live
Checkouts: --rev, --take, run, snapshots, forks, diff and apply