SmartConfig

The SmartConfig journey

How the project started, which path we chose at each turn and why, and where we have moved away from the plan. For the day-to-day log see WORKLOG.md; for decisions and recovery, PROJECT_LOG.md. Every fact here comes from those files, the reviews and git history.

Last updated: 2026-10-09, M5 done. Sections 1 to 7 tell M1 and M2 in full, as written on 2026-10-01 (section 7 as it stood then); section 8 tells M3 to M5 in brief, and section 9 says where we are now.

1. The idea

A safety net for the Linux config files that take a machine down (fstab, GRUB, sshd, sudoers, PAM). Snapshot a file before it is edited, warn before a bad edit is applied, explain what broke, and restore one file from a rescue shell. Target: Ubuntu 24.04, on a VirtualBox VM used as the lab.

It is built in seven milestones, strictly one at a time and never ahead of the current one, not even as stubs (MILESTONES.md): M1 store and CLI, M2 watcher, M3 checkers, M4 rescue path, M5 .deb package, M6 incident set, M7 local model.

Ground rules chosen at the start (CLAUDE.md), and why:

Choice Why
Go, one static binary (CGO_ENABLED=0) It must run from a broken system with nothing else working.
SQLite through modernc.org/sqlite (pure Go) Keeps the binary static; no C library needed.
Write a config file back only by temp file, fsync, rename A crash can never leave a half-written fstab.
Tests never touch /etc or the real store The lab machine must stay bootable.
Small commits, WORKLOG updated and pushed after every step Anyone, human or Claude, can pick the work up cold.
Stop and ask before touching the real system, adding a dependency or changing an approved plan The owner decides anything that is hard to undo.

2. M1: the store and the sc command (2026-09-27 to 28)

Hardening: four review rounds, five rounds of fixes. Instead of calling M1 done after its tests passed, it was attacked on purpose. Each round, AI reviewers ran the code and tried to break it, and two skeptics had to confirm each finding before it counted.

Round Findings What they were about
1 14 Concurrency and security of the first two follow-up fixes
2 15 Transactions, restore atomicity
3 (gate) 18 Restore logic, signals, spec conformance
4 7 Ctrl-C handling; led to a second design of signal handling

Round 2 found one way to lose data: a restore that failed or was killed right after replacing the file lost its undo point (finding U1, a regression of a round-2 fix); round 3 fixed it. The gate and signal reviews found no data loss. The fixes made sc safe to run next to the future watcher: every write is one locked transaction, a restore records an undo point before it touches the file, and Ctrl-C always tells the truth about whether the file changed. M1 was tagged m1 on 2026-09-28, and backups of the binary, the store, /etc and /boot/grub were made.

3. Planning M2: the watcher (2026-09-27 to 28)

4. Building M2

Overnight run, 2026-09-28 to 29 (unattended). Setup first: local hooks that refuse secrets, make race, Go 1.26.8 (the old 1.22.2 had three known vulnerabilities), CLAUDE.md edits. A very slow disk that night exposed a real M1 race (two lines after a double Ctrl-C) and two timing-dependent tests; all three were fixed. Then:

Resumed interactively, 2026-09-30.

5. Where we moved away from the plan

All changes since approval, with reasons, are kept in one place: M2_PLAN.md Appendix C. In short:

  Change Why
C1 Overnight run stopped in step 3 Unknown; finished interactively
C2 No overlapping reviews Owner: one step at a time
C3 Light review by one reviewer agent plus Claude as skeptic Enough for a light review, far cheaper; same method
C4 Backup read through SQLite; process-level lock tests Review finding D1 (high)
C5 New known limit for never-migrated stores on read-only disks Accepted: the real store is migrated long before M4
C6 SC_HOME excluded by a path check, not a glob Glob characters in a path cannot misfire
C7 Record alternatives; fingerprint private keys and secrets Owner, after reviewing the excluded list
C8 Fingerprint host-key temp names; more consumer directories in block D Chunk C review findings D1-D6
C9 Record ~/.ssh/rc and environment; fingerprint dropbear, WireGuard, apt auth and LUKS key files Owner, on two questions from the chunk C review
C10 Step 6 reuses M1’s Meta.Stamp and LstatStamp No second copy of an API the store already uses
C11 Computed intents only for watcher rows sc snapshot -m stays what the user typed
C12 Obs.Suffix; the CLI turns log priorities into journald or time prefixes Plan had no field for the suffixes
C13 A rescan for a moved root waits Cap A root moved away and back was dropped for an hour
C14 SIGHUP rescans; unit reload and remote-fs ordering; acceptance fixes Chunk E review
C15 Digest rows get a random id, not one derived from their fingerprint Final review: a journal reader could test guesses at a short secret
C16 A row budget per system file: 20 rows, then one every 5 min Final review: a file rewritten every second gave about 86,000 rows a day

6. Lessons so far

7. Where we were on 2026-10-01

M1 done. M2: built (steps 1-16 of 17) and every chunk reviewed and closed. What is left is the owner’s part: the acceptance run, the M1 smoke run, the real store (S2), the owner scenario, a reboot, failure paths and a 24-hour soak, each with a VM snapshot first. Step 17 (tag m2) closes M2.

8. M2’s end to M5, in brief (2026-10-02 to 10-09)

  When What happened, and the turns that mattered Changes from the plan
M2 tag m2 2026-10-02 Signed off on the dev VM: the acceptance and smoke runs, the real store migrated, a reboot, kill -9 in a dpkg burst. The 24-hour soak was closed after 5.6 h (your call, 2026-10-03). M2 Appendix C, C15-C16 above
Order 2026-10-03 The roadmap’s question 1 was answered: M3 before M4. M4’s boot tests need QEMU without KVM, which is slow on this VM, and M3 could be built while the soak ran.  
M3 plan approved and tag m3 2026-10-03 Checkers, sc check, sc edit, sc scope. Probing first changed the design: a stock Ubuntu already fails some validators, so an edit is judged by the findings it adds. netplan generate asks systemd to reload, so the generator binary is used instead. findmnt misses a misspelt option, so sc has rules of its own. Four agents built chunk C’s checkers in parallel worktrees (your call). The final review found two high findings (files that lock the owner out or stop the boot with no word from sc); both were fixed before the tag. M3 section 15, C1-C9
M4 plan approved 2026-10-04, tag m4 2026-10-07 The rescue path: a GRUB entry, sc status above the rescue shell’s prompt, boot verdicts, the menu back after a failed boot. The QEMU lab (lab/, make lab-e2e) proves it end to end under TCG. The lab showed that Ubuntu 24.04’s sulogin opens a root shell at the console even with root locked (PROJECT_LOG D6). Host stalls cost many lab runs their verdict, so the lab gained verdict classes (PASS, FAIL, INCONCLUSIVE) and retries a boot only for known lab flakes (a stall, TCG’s own panic). M4 section 12, C1-C8
Follow-ups 2026-10-07 to 08 The M3 and M4 follow-up lists, in three reviewed chunks (F, G, H). Signed off with the lab in both modes (with the GRUB password recipe) and accept-m2/m3/m4 as root. MILESTONES
M5 plan drafted 2026-10-08, tag m5 2026-10-09 The package, built with dpkg-deb rather than nfpm (no new tool). Your call was that M5 starts whether or not you had read the plan, so its questions ran on the recommended answers. On the dev VM, the image’s policy-rc.d stopped every package script from restarting scd. It was found in the sign-off and moved aside on your answer. M5 section 9, C1-C8

Lessons from these milestones, added to section 6’s:

9. Where we are (2026-10-09)

M1 to M5 are done and tagged; this VM runs the package, 0.5.0. Next is M6, the incident factory and eval set. Its plan is drafted (~/smartconfig-work/M6_PLAN.draft.md) and being revised after a review of the whole plan on 2026-10-09; nothing of M6 is built. M7, a local model (sc why), is not planned yet. That review also found work that no milestone owns, among it retention, secrets kept in the store, and a restore that writes without a check. It is listed at the end of MILESTONES.md for your decision.