# RescueVault (CLI prototype) This is a genuinely working prototype of the file-level backup slice of the RescueVault concept: hardlink-based incremental snapshot backup. Each run of `backup` creates a new timestamped snapshot that is a complete, browsable copy of your source directory tree, but files that are unchanged since the previous snapshot (same size and modification time) are hardlinked rather than copied, so unchanged data is not duplicated on disk -- the same technique used by `rsync --link-dest` and Time Machine. `list`, `prune`, and `restore` round out the workflow: listing snapshots with their real disk footprint, safely removing old snapshots, and restoring a snapshot's files back out as real copies. The rest of the RescueVault concept -- raw disk imaging, boot-sector/MBR/GPT rescue, and SMART-based drive health scans -- needs OS-privileged, low-level block-device access that isn't achievable in a portable, dependency-free Go CLI; those remain roadmap items. See ../plan.md for the full product plan. ## Build from source Requires Go 1.24+, no external dependencies. go build -o rescuevault . Cross-compile for another platform: GOOS=windows GOARCH=amd64 go build -o rescuevault.exe . GOOS=darwin GOARCH=arm64 go build -o rescuevault . ## Usage rescuevault backup [--apply] Creates a new snapshot of under /snapshots//. For each file, RescueVault looks at the most recent prior snapshot (if any): if it has a file at the same relative path with the same size AND the same modification time, the new snapshot hardlinks to that file instead of copying it (falling back to a real copy if the hardlink fails, e.g. across filesystems or devices). Otherwise the file is a new or changed file and its bytes are copied in full. This size+mtime check is a deliberate, cheap approximation -- it does NOT hash file contents. Hashing every file on every backup would turn an incremental backup back into a full read of the whole tree each time, defeating the purpose. The tradeoff (same one rsync's default quick-check uses) is that a file whose content changes while its size and mtime are both preserved exactly would be missed; this is rare in practice and normally requires deliberate tampering. Without --apply, `backup` is a dry run: it prints NEW / CHANGED / UNCHANGED for every file and the total bytes that would actually be copied, and does not create any directory on disk. With --apply it performs the backup for real and prints a summary of files copied, files hardlinked, and new bytes written. rescuevault list [--json] Lists every snapshot in , showing its ID, total file count, and "new bytes" -- the sum of sizes of files that snapshot actually copied (not hardlinked), i.e. the real incremental disk cost of that snapshot. This is read from a small per-snapshot manifest sidecar file (.rescuevault-manifest.json) written at backup time, which records for every file whether it was copied or hardlinked. That sidecar approach was chosen deliberately: detecting "is this a hardlink?" after the fact would require syscall-specific, OS-specific os.FileInfo type assertions that Go's standard library does not expose uniformly across Windows/macOS/ Linux. Recording the fact at write time is simpler, fully portable, and transparent about what actually happened. rescuevault prune --keep N [--apply] Keeps the N most recent snapshots and removes all older ones entirely. Without --apply this is a dry run listing which snapshots would be kept and which would be removed. This is always safe by design: a newer snapshot may hardlink a file into an older snapshot's directory, but removing that older directory only removes ITS directory entry for the file -- the underlying file content is only freed once every directory entry (hardlink) referencing it is gone. The newer, kept snapshot still holds its own directory entry for that file, so its data is never affected by pruning an older snapshot. This is the same invariant that makes pruning safe in rsync --link-dest and Time Machine backup chains. rescuevault restore [--apply] Copies every file from a snapshot into , preserving relative paths, as real byte copies -- never hardlinks -- so a restored tree never shares inodes with the vault. Without --apply this is a dry run listing what would be restored and the total size. All four commands support -h / --help / help for command-specific usage. ## Prebuilt binaries See ../downloads/ for prebuilt binaries (Windows/macOS/Linux) and CHECKSUMS.txt for their SHA-256 hashes. These are unsigned indie builds -- Windows SmartScreen and macOS Gatekeeper will warn on first run, which is expected until a code-signing certificate is in place.