Version control, minus the code

git for files.

Snapshot anything. Write a note about the moment. Diff two points in time, byte-for-byte. Restore any moment. Never lose a file again.

NO ACCOUNTSNO TELEMETRYYOUR FILES STAY YOURS

The chain

Every moment, linked.

Each commit is derived from the one before it. Touch the journal and the chain breaks, loudly. That is the whole trick.

a1b2c3 · rev 12

"beat the Elite Four, Mewtwo next"

4 files · 38 KB · verified

d4e5f6 · rev 13

"draft finished"

2 files · 9 KB · verified

9c0ab1 · rev 14

"pre-restore auto-backup"

auto-saved before a restore · verified

77f2e9 · rev 15 · HEAD

"restored a1b2c3 — undid the bad grind"

undoable, always · verified

Six commands

That's the whole interface.

No dashboard. No settings maze. Six verbs between you and never losing a file.

commit

Snapshot the moment, in your words. Identical tree? Nothing to commit.

$ chains commit -m "beat the Elite Four" committed a1b2c3 (rev 12) — 4 files, 38 KB

diff

What changed between two moments, byte-for-byte.

$ chains diff a1b2c3 d4e5f6 ~ saves/pokemon.sav 1,204 of 131,072 bytes differ

restore

Go back. Your current state is auto-backed up first, so restores are undoable.

$ chains restore a1b2c3 pre-restore backup saved. restored a1b2c3

verify

Prove the journal and every snapshot are untampered. Scriptable: exits non-zero on failure.

$ chains verify chain intact — 15 commits, 61 blobs, hashes match

patterns

Track anything. Two glob lists decide what a vault versions.

$ chains patterns -SetInclude "*.md;*.ps1" tracking docs now, history untouched

push / fetch

Move history through any folder: USB stick, LAN share, mounted cloud drive. Offline-first, no network code in the engine.

$ chains push -Remote E:\vault-remote pushed 3 commits, 11 blobs

Not just saves

Born from a lost game save.
Grown into everything.

Chains started the night a game save vanished, so save data ships as the default: battery saves and save states across SNES, GBA, N64, PSX, PS2, GameCube, PSP, NDS, and BizHawk.

But a vault's tracked set is just two glob lists. Point it at essays, configs, art, anything. Changing patterns never touches history.

Only your files are ever stored. Never ROMs, never firmware.

// .chains/config.json
{
  "includePatterns": ["*.srm", "*.sav",
    "*.state*", "*.mcr", "*.ps2"],
  "excludePatterns": ["*.tmp", "~$*"],
  // exclude wins. .chains itself is never scanned.
}

Sync

Your history, everywhere you are.

Content-addressed blobs and an append-only journal map 1:1 onto sync. Same shape as git, minus the DAG.

LAN vault

Keep the vault on a network share and every machine on the LAN sees the same history.

WORKS NOW

USB-stick sync

Push and fetch through any directory: stick, share, mounted cloud drive. Preview first with a read-only plan.

WORKS NOW

Offsite vault

Encrypted offsite replication, so your files survive a house fire.

ON THE ROADMAP

FAQ

Five honest answers.

What can Chains track?
Anything. Game saves are the default, but a vault's include/exclude glob patterns can point it at any files: essays, configs, art. Whatever you point it at, it versions.
Does it store ROMs or game files?
No. Chains versions only your files, never ROMs or firmware. Those live in a separate project entirely.
Do I need an account?
No. No accounts, no telemetry, no cloud required. A vault is a folder on your machine. Sync moves through any directory you choose.
What if I restore the wrong moment?
Restore auto-commits your current state first, so every restore is undoable. The journal is append-only: history is never rewritten.
How do I know my history is intact?
Every commit id is derived from its parent, timestamp, message, and file list, and every blob is re-hashed against its SHA256. Run verify and it proves the whole chain is untampered.

Stop losing files.

Free and open source. Six commands. Your files stay yours.

Get Chains on GitHub
Get Chains