Install
Requires Node.js 22+ and git on PATH. What the tool covers, and what a successful run does not capture, is on Safety. Same install path as the README.
From npm / pnpm
pnpm add -g ingotvault
# or: npm i -g ingotvault
ingotvault init
ingotvault list
ingotvault
From a clone
git clone https://github.com/Catalyst-Forge-LLC/ingotvault.git
cd ingotvault
pnpm install
pnpm run build
pnpm link --global
First run
ingotvault init
# workspace + mirror roots → ./ingotvault.config.json
# also writes mirrorRoot/.ingotvault-vault (required on later runs)
ingotvault list # planned mirror paths
ingotvault --dry-run # no writes
ingotvault # ensure bare mirrors + push
ingotvault verify # compare tips
IngotVault does not keep running after init. A run starts when you type it, when the daily OS job fires, or when an agent runs ingotvault --repo . in one repo. Those can all be on. The vault lock keeps two runs from overlapping. Config is the nearest ingotvault.config.json walking up from the current directory, then the user config file.
On a clock
ingotvault schedule # is a daily job registered?
ingotvault schedule install # 18:00 local
ingotvault schedule install --at 21:30
ingotvault schedule remove
Windows uses Task Scheduler. macOS uses a LaunchAgent. Linux uses a systemd user timer, or cron if that user session is missing. The job runs ingotvault --scheduled with the absolute config path. It does not force-push. If the computer was off at that time, Task Scheduler, launchd, and systemd run it once later. Cron does not. Exit 2 means the drive was missing.
If you change mirrorRoot, run ingotvault init against the new path (or ensure .ingotvault-vault exists there), then ingotvault relink so each repo's backup remote matches.
Mirror naming preserves workspace paths under mirrorRoot (acme/widgets → …/acme/widgets.git).
Agents / session boundaries
# Snapshot dirty trees (untracked that are not gitignored) → refs/ingotvault/wip/…
ingotvault --capture-worktree
# Silent when the vault matches; noise only on drift
ingotvault verify --quiet-if-clean
Or set "captureWorktree": true in config. Gitignored files are not captured; use wipExclude for extra pathspecs. Longer write-up: An undo layer for autonomous edits. Coverage table, exit codes, and divergence recovery: Safety.
Restore
Clone a mirror:
git clone /path/to/mirrors/notes.git notes-restored
Other branches appear as origin/<name> until you check them out.
Restore a lost branch
A disposable two-repo fixture lives in docs/restore-demo.md. The short form:
- Capture
workspace/noteswith afeature/parserbranch intovault/notes.git. - Confirm with
ingotvault verify(ok/refs match). - Delete the local branch.
- Clone the mirror and
git switch feature/parser.
Narrow result: parser.md is back because that commit sat on a covered branch during the successful run. The fixture also leaves an uncommitted scratch.txt in the source. It is absent from the clone. Default runs do not capture uncommitted files.
Restore a WIP snapshot (fetch from the mirror if needed):
git fetch backup 'refs/ingotvault/wip/*:refs/ingotvault/wip/*'
git restore --source=refs/ingotvault/wip/<host>/<slug>/<timestamp> --worktree --staged .
# inspect only (does not write the worktree):
git show refs/ingotvault/wip/<host>/<slug>/<timestamp>
Encrypt the vault volume
Git does not encrypt repositories at rest. Encrypt the volume (or container) that holds mirrorRoot, then point config at a path inside the unlocked volume.
| OS | Typical option |
|---|---|
| Windows | BitLocker To Go on the removable drive |
| macOS | APFS encrypted volume or encrypted disk image |
| Linux | LUKS (cryptsetup) |
| Cross-platform | VeraCrypt container |
Step-by-step OS setup: docs/encryption.md. safeDirectory / exFAT notes: README → Encrypting the vault.
Full reference
| Topic | Where |
|---|---|
| Exit codes and divergence | Safety |
| Restore a lost branch (fixture) | restore demonstration |
| Flags, config, discovery, scheduling | README on GitHub |