Made on 27 Sep 2026, at M1. What it marks as planned was the design then. M2 to M5 have been built since (the watcher, the checkers, the rescue path and the .deb package; tag m5 on 2026-10-09) and differ from this design in places; M6 and M7 are not built. Where things stand now: MILESTONES.md.
A safety net for the config files that take a Linux machine down. Snapshot a file before it changes, warn before a bad edit lands, explain what broke, and put one file back from the rescue shell.
We started from an empty repo containing only go.mod. Click any step, or replay the build and watch the repository fill in.
initsnapshotlogcatdiffrestoreThin. Any error becomes one line, sc: … on stderr, and exit code 1.
InitOpenSnapshotListGetBlobRestoreUnifiedDiffContent-addressed blobs plus one SQLite row per change. Resolves id prefixes and verifies each blob's checksum before use.
ReadWithMetaWriteAtomicRefuses symlinks, non-regular files and anything over 8 MB. Writes a temp file, sets owner and mode, fsyncs, then renames it over the original.
The live config files. Only ever replaced by rename, never truncated in place.
/var/lib/smartconfig/ 0700 ├─ objects/ │ ├─ c2/c2646361… 0600 │ └─ 97/97acb3b7… 0600 └─ changes.db SQLite
id 733bd9 ts 1790469360 (unix seconds) path /etc/hosts blob c2646361… (sha256) size 273 mode 0644 (+setuid/gid/sticky) uid/gid 0 / 0 origin manual | pre-restore | restore intent "baseline"
Two rows for the same file, content and second would get the same id. When an id is taken, \n1, \n2… is appended and it is hashed again. This happened in the real acceptance run: d2b20b and 0beb81 hold the same bytes, saved in the same second.
sc snapshotsc restore 733bd9sc restore 0beb81 away.The same logic as the real tool, rewritten in JavaScript: real sha256 hashes, the same id formula and collision rule, the same messages. It works on a copy of this VM's /etc/hosts. Edit the file directly, type commands, or follow the numbered buttons.
| ID | Origin | Size | What |
|---|
Commands: sc snapshot /etc/hosts [-m "why"] [-q], sc log [-n N], sc cat <id>, sc diff <id> [<id2>], sc restore <id>, clear. Id prefixes work.
The script breaks the real /etc/hosts by adding a line, then fixes it with one command. This is the sc log /etc/hosts it ended with, newest first.
| ID | When | Origin | Size | What |
|---|---|---|---|---|
| 460e5a | 2026-09-27 00:36 | restore | 273 | restored from 733bd9 |
| 0beb81 | 2026-09-27 00:36 | pre-restore | 297 | before restoring 733bd9 |
| d2b20b | 2026-09-27 00:36 | manual | 297 | added smoke line |
| 733bd9 | 2026-09-27 00:36 | manual | 273 | baseline |
+127.0.0.1 smoke.invalid644 root:rootfile bin/sc: statically linkedToday a snapshot happens only when someone runs sc snapshot. M2 adds scd, a daemon that watches config files with inotify and records every save, whether it comes from vim, nano, sed or apt. It writes into the same store, so sc log, diff and restore work on its snapshots unchanged.