| name | mirage |
| description | Use when you need an isolated copy of a large repository — especially a Unity project — for an agent task, parallel work, or a risky experiment, and a full git worktree or plain copy is too expensive (slow, many GB of disk, or a forced Unity reimport). macOS/APFS only. |
mirage
Overview
mirage makes near-free copy-on-write clones of a repo using APFS clonefile. A clone
shares disk blocks with its source until written, so it costs ~0 bytes and ~1 minute even
for a ~28 GB Unity project, yet is a fully independent git working copy: edits never touch
the source, and Unity reuses the cloned Library/ (no reimport).
Reach for it instead of git worktree, which materializes the whole tree (GB of disk) and
forces a Unity reimport. CLI is mirage (on PATH); full flags via mirage --help.
When to use
- Isolating an agent task or risky experiment on a large/Unity repo without touching the source.
- Running several parallel workspaces off one repo cheaply.
- You'd otherwise reach for
git worktree / cp -r but it's too slow or too big.
When NOT to use: small or non-Unity repos where a worktree is already cheap; crossing
filesystem volumes (clonefile can't); non-macOS or non-APFS systems.
Quick reference
| Task | Command |
|---|
| Create a clone (Unity-ready) | mirage new <src> --name <name> |
| Create, code-only (lighter, Unity reimports) | mirage new <src> --no-library |
| Clone to an explicit path | mirage new <src> <dest> |
| List clones | mirage ls |
| Inspect one | mirage info <name> |
| Destroy one (deletes the tree + deregisters) | mirage rm <name> [-y] |
| Forget hand-deleted clones | mirage prune |
<name> is the clone's directory under ~/.mirage/trees/ (the default location). Pass either
--name <name> or an explicit <dest> path; if you pass both, <dest> wins.
Typical workflow
mirage new ~/projects/sample --name fix-bug
cd ~/.mirage/trees/fix-bug
mirage rm fix-bug -y
Set the agent's working directory to the clone path. Every file operation (read, write,
edit, search, shell) then operates on the clone transparently — no wrapper or interception.
Behaviors to know
- Snapshot, not live. A clone is frozen at creation; later source changes do NOT flow in,
and clone changes never flow back. If the source drifts a lot while you work, rebase your
clone's branch onto it before opening the MR.
- Git is fully intact. The clone starts on the source's currently-checked-out branch with
full history and remotes, so branching and
git push work normally.
- No merge-back. mirage only makes clones. Integrate using normal git inside the clone
(branch, commit, push, open an MR) — there is no
mirage merge/sync command.
- Working tree, untracked files, and submodules ride along exactly as cloned — the project
compiles without re-running
make setup or submodule init (a clone is more complete than a
fresh worktree).
- Same volume only. Source and clone must be on one APFS volume; mirage refuses with an
error otherwise. Use an explicit
<dest> elsewhere on that volume if the default won't do.
- Unity-ready by default.
Library/ is included so Unity skips reimport. Use
--no-library only when you will NOT open the clone in Unity (lighter, a bit faster).
Common mistakes
- Editing the source out of habit. After
mirage new, cd into the clone — stop working
in the original.
du panic. du reports logical size (~full); real cost is only the blocks you change.
A fresh clone is not actually consuming the source's full size.
--no-library then opening Unity. That forces a full reimport — defaulting to
Unity-ready is usually what you want.
- Hand-deleting with
rm -rf. Prefer mirage rm so the registry stays consistent (or run
mirage prune afterward).