Getting started
mado is Linux-only and needs FUSE (/dev/fuse). Every command below is a
subcommand of the mado binary — a custom jj CLI: mado log, mado describe,
and every other jj verb work exactly as in upstream jj, backed by mado’s stores.
Local: a mounted jj working copy
mkdir myrepo && cd myrepo
mado init # a jj repo whose backend + working copy are mado
mado mount --mountpoint ~/mnt & # FUSE daemon: serves @, folds edits back into @
cd ~/mnt # work here: read lazily, edit freely
echo hello > hello.txt # ...idle edits auto-snapshot into @ (~1 s)
mado log # the full jj CLI, backed by mado stores
mado init creates a jj repository whose object backend and working copy are
mado. By default the local store uses the loose-file at-rest format (fs), one
object per file — the format that lets a mado mount daemon and a mado CLI
process share the same store side by side. (--store-format fjall selects the
embedded LSM format instead; it is held exclusively by one process at a time and
is meant for import/serve stores, not side-by-side local use.)
The mount daemon
mado mount --mountpoint <dir> runs a daemon that:
- serves the working-copy commit
@through the mountpoint (which must be a path other than the workspace root); - collects edits made through the kernel into a durable overlay journal
(
overlay.snapshot), restoring them on restart; - auto-snapshots those edits into
@after a short idle period — an in-process jj transaction, so an agent’s work is captured in jj history without it running any command. Pass--no-auto-snapshotto turn that off and rely on the overlay journal plus explicitmado snapshot.
mado snapshot is the manual, on-demand equivalent of the daemon’s idle fold:
it pulls the live overlay from the running daemon over the control socket and
amends @. It is quiet and idempotent.
To let another user (or a container / guest VM) read the mount, add
--allow-other (requires user_allow_other in /etc/fuse.conf). --read-only
mounts a reference checkout the kernel refuses writes to before they reach the
VFS.
Daily jj use
Once mounted, work inside the mountpoint and drive history with ordinary jj
verbs through the mado binary:
cd ~/mnt
mado new master # start a new change on top of master
$EDITOR src/lib.rs # edits fault content in on first read,
# land in the overlay, auto-snapshot into @
mado describe -m "fix the thing" # set @'s description
mado log
mado diff
mado rebase -d main
mado undo # jj's operation log works normally
Nothing needs pre-warming: a cold read inside the mount faults the blob in over whatever backend the workspace uses (local disk or a remote server) and caches it. See Performance for what “cold” costs and how to make a whole subtree warm in one fetch.
Networked: one server, many clients
A shared mado serve server lets many thin clients check out the same history
lazily. See Operations for running the server; the client
side is:
mkdir ~/client1 && cd ~/client1
export MADO_REMOTE_ADDR=http://server:50051 # object reads/writes go here
mado init --workspace alice # register a UNIQUE workspace name
mado new master # position @; objects fetch lazily
mado mount --mountpoint ~/mnt1 & # a 50k-file repo mounts instantly
Every client of a shared server must use a distinct
--workspacename. Two workspaces sharing one name fight over the same working-copy commit — each checkout makes the other stale and resets its mount. Against a remote, a name already registered on the server is refused (unless you are resuming — see Workspaces).
Clients share the op-log through the server (concurrent operations merge exactly
like jj’s --at-op), fetch blobs lazily through a local disk cache, and fold
their mount edits into their own @.
Scratch directories (build output)
Build output (target/, node_modules/, …) is large and write-hot, and you
almost never want it in the jj snapshot. Mount with a scratch backing
directory and redirect those paths to plain local disk:
mado mount --mountpoint ~/mnt \
--scratch ~/scratch-alice \
--redirect target --redirect node_modules
Paths listed with --redirect (merged with whatever the repo’s
.mado-redirections manifest declares) are served from disk under --scratch
instead of the virtual tree, so they never enter a jj snapshot. Give each agent
its own scratch directory so their build trees don’t collide. Scratch state
travels with mado ws pause / resume — see Workspaces.