Documentation
Exodrive moves a developer cache to an external drive. It checks the copy before it frees the space. This page covers the window, the command line, and the ledger.
Install
Install the newest release with one command:
curl -fsSL https://jungley8.github.io/exodrive/install.sh | sh
On Windows, run this command in PowerShell:
irm https://jungley8.github.io/exodrive/install.ps1 | iex
The script downloads the archive for this machine and checks it
against SHA256SUMS. A mismatch stops the install before
it writes anything. On macOS it installs Exodrive.app
to ~/Applications and the command line tool to
~/.local/bin. On Linux it installs the command line
tool only. On Windows it installs both programs to
%LOCALAPPDATA%\Programs\Exodrive.
Read the script before you run it: install.sh or install.ps1
Install one part, or another version:
curl -fsSL https://jungley8.github.io/exodrive/install.sh | sh -s -- --cli
curl -fsSL https://jungley8.github.io/exodrive/install.sh | sh -s -- --app
curl -fsSL https://jungley8.github.io/exodrive/install.sh | sh -s -- --version v0.8.0
install.ps1 takes -Version and
-Dir.
A download from a browser adds the quarantine flag, and macOS asks
for your confirmation on the first start. Right-click the app, then
choose Open. The script uses curl, so
no flag is added.
Or download the archive from the releases page, then check it:
shasum -a 256 -c SHA256SUMS
Build from source
git clone https://github.com/Jungley8/exodrive
cd exodrive
make build # bin/exodrive and bin/exodrive-gui
make app # bin/Exodrive.app, signed with an ad-hoc identity
Go 1.27 or later builds the source.
Use the window
The window opens on a check of this computer. It lists every cache it can move.
- Choose a folder. Press Choose to open the folder panel of macOS. The panel lists every connected drive. You can also type the path.
- Select the caches. Press Select all, or press the box on a card.
- Move them. Press Move. Read the list in the dialog, then press Move again.
The window shows two gauges. The left gauge holds the free space of this computer and the bytes in caches. The right gauge holds the free space of the chosen drive and the bytes that moved there.
A card holds one cache: its size, its state, its folder, its copy, and the change that Exodrive makes. A card also holds the one action that fits the state.
The rail on the left groups the caches by toolchain: Node, Python, Rust, Go, Apple, JVM, Mobile, Homebrew, and Docker. The filter above the list keeps one place. A change to the filter clears the selection, so a move never acts on a cache you cannot see.
The first start shows three steps. Press Skip to close that card. The window does not show it again.
Use the command line
Scan every toolchain:
exodrive check
Check one cache against a folder, without moving data:
exodrive preflight npm.cache --target=/Volumes/External/exodrive
Move the caches to a folder:
exodrive migrate --target=/Volumes/External/exodrive --all
exodrive migrate --target=/Volumes/External/exodrive --tools=npm,pnpm
Read the plan without moving data:
exodrive migrate --target=/Volumes/External/exodrive --all --dry-run
Find caches that an earlier change left behind:
exodrive orphans
exodrive orphans --clean
The command line exits with a code that a script can read. A refused move is a failure, not a warning.
The ledger
Exodrive writes ~/.exodrive/manifest.json. Each move
adds one record: the item, its old path, its new folder, the change
that points the tool at the copy, the size, the time, and the digest
of the copy.
Exodrive locks the file while it writes, so two runs cannot lose a record. An item appears once.
Set EXODRIVE_MANIFEST_PATH to keep the file somewhere
else.
Keep the ledger and the drive together. A move back needs both.
Check a moved copy
A move records a digest of the copy. Press Check the copy on a card, or run:
exodrive verify npm.cache
exodrive verify --all
exodrive verify --all --json
The check reads the copy again and compares the two digests. It writes nothing to the drive. The command prints one line for each copy, and it exits with code 1 when a copy is not ok.
- ok: the copy holds the bytes that the move wrote.
- changed: a file in the copy differs from the move. Move the cache back, then move it again.
- missing: the copy is not at the recorded path. Connect the drive.
- unverified: the record holds no digest. A record from an older Exodrive holds none.
A check never reports ok for a record it cannot prove.
Move a cache back
Press Move back on the card, then confirm.
Or use the command line with the item ID:
exodrive check # lists the item IDs
exodrive rollback npm.cache
Exodrive copies the cache to its old folder and checks the copy. It removes the copy on the drive after the check passes. It removes the record last.
When both copies differ, Exodrive stops. It keeps both copies and the record, because it cannot choose for you.
Run exodrive rollback --keep-local <item> to keep the
folder on this Mac. The command deletes the copy on the drive and
removes the record. The window offers the same action as
Keep the local folder on the failure card.
Stop the window
macOS closes the window without asking. Exodrive cannot hold the window open during a move.
A move writes a record before it starts and removes the record when it ends. The next start reads that record and names the cache that was changing.
Press Stop after this cache to end a long move between caches. The cache that copies now finishes first.
A window that closes in the middle of a copy leaves a partial copy on the drive and the full cache here. Run a check. If the card still shows the local state, move the cache again.
Troubleshooting
| The window says | Do this |
|---|---|
| Cannot move | The card holds the reason. Fix it, then press Rescan. |
| A program still uses this cache | Quit that program. Press Rescan. |
| The copy did not match | Press Try again. A second failure points at the drive. |
| This drive cannot hold caches | Choose a folder on APFS, HFS+, ext4, btrfs, zfs, xfs, f2fs, bcachefs, or NTFS. |
| Your shell sets the cache path | Remove the variable the window names from your shell, then retry. |
| The drive is full | Free space on the drive, or move fewer caches. |
| Cannot move, and the card names the simulator folder | Keep the folder on this Mac. Delete the simulators you do not use in Xcode. |
| Xcode created a real folder in place of the link | A rollback compares the two folders first. When they differ, both stay. Press Keep the local folder to delete the copy. |
| No record of this move | Run a scan. The record file may sit somewhere else. |
A toolchain that Exodrive cannot find does not appear in the list. The window reads the PATH of your shell. Add the tool to that PATH, then press Rescan.
Report a failure
Exodrive writes one line to ~/.exodrive/failures.jsonl
for each failure it shows. The line holds the time, the version,
the platform, the step, the kind, the cache, and the message. The
home folder reads as ~.
Press Copy details on a failed card. Press Report a problem in the footer to read the exact text. The dialog copies the text or opens a prefilled GitHub issue. Edit the issue before you send it. Exodrive sends nothing by itself.
In the terminal, run exodrive doctor. It prints the same facts.
Set EXODRIVE_NO_FAILURE_LOG=1 to stop the log. Delete
the file to remove every record.
Platforms
- macOS 13 or later: the window ships here. Every test runs here.
- Linux: the command line tool builds and runs. CI tests it on Ubuntu.
- Windows: the command line tool and the window ship. No test runs on Windows.
A bug on a system without a promise is still a bug. Report it, and the fix follows the same checks.
Security
Exodrive runs as you. It reads the tool settings on this computer and writes the files the tools use. It opens no network service.
The update check reads the public release list from GitHub. Set
EXODRIVE_NO_UPDATE_CHECK=1 to turn the check off.
Report a security problem through the security policy in the repository.