Keeping it maintainable

The introduction made a promise about Arch: the running system is the source of truth, it drifts, and nothing but your own discipline records how it got that way. This chapter is that discipline, written down as a git repository and one command, so that it does not have to live in your head.

Log in as admin. The host repo that setup built the machine from is already there:

Run this on the new machine:
cd ~/arch
git log --oneline
(stdout)
3f9c2e1 setup install: myhost (x86_64 PC, UEFI)
a14b07d setup host: myhost
File Holds Changed by
host.env The install answers You, rarely
packages.txt Every package you asked for, beyond the base set You
units.txt Every unit you enabled You
etc/ Your files under /etc You
bin/admin The admin command itself Nobody, usually
authorized_keys Public keys admin accepts You
aconfmgr/ The same, in aconfmgr’s terms, plus what to ignore Nobody, usually
aconfmgr/10-base.sh The base packages setup picked for this hardware setup install

admin runs aconfmgr against ~/arch/aconfmgr:

Command Direction What it does
admin diff look only Lists every difference between the machine and the repo
admin save machine → repo Writes the machine’s drift into the repo, for you to sort and commit
admin apply repo → machine Makes the machine match the repo, removals included
admin upgrade both Refuses on drift, pacman -Syu, apply, reports .pacnew files
admin git ... the repo itself Runs git in the host repo, from wherever you are

admin git saves remembering where the repo lives: admin git log, admin git commit -am "...", admin git push, from any directory. Everything after git is handed to git untouched, and git’s exit status comes back, so admin git diff --quiet still works as a test.

admin help prints the same list. Every command takes aconfmgr’s own options after it: --yes answers its questions, --skip-checksums skips comparing package files with their checksums, which is much faster but misses edits to files that packages own.

What aconfmgr looks at

aconfmgr knows the whole system, not only what you told it about. It lists the packages installed explicitly (pacman -Qe; dependencies come and go with them and are never listed), every file on the system that no package owns, and every file a package owns that has changed since it was installed. Anything in that list that the configuration does not describe, or that the configuration describes and the machine lacks, is drift.

A fresh install has no drift. That is not an accident of a new system – a fresh Arch install is full of files no package owns – but the result of ~/arch/aconfmgr/, which accounts for all of them:

File Describes
00-helpers.sh The helpers the others use, including one that works out the links systemctl enable makes
10-base.sh The base packages for this hardware (written by setup install)
20-host.sh What setup wrote from host.env: hostname, locale, keymap, time zone, resolv.conf
30-repo.sh packages.txt, the files under etc/ and bin/, and the units in units.txt
40-system.sh What packages and boot leave behind: units they enable, directories they make, aconfmgr’s links
90-ignore.sh What is not configuration at all

They are bash, read by aconfmgr in order. 20-host.sh and 30-repo.sh do not copy anything: they read host.env, packages.txt, units.txt, etc/ and bin/, so those stay the files you edit and aconfmgr follows them. Adding a package is still a line in packages.txt.

What is ignored, and why

90-ignore.sh lists what aconfmgr should not report:

  • What setup owns: /boot (the bootloader, kernel and initramfs, rewritten by pacman hooks) and /etc/fstab (UUIDs of this disk).
  • Accounts: /etc/passwd, group, shadow and friends. setup makes the accounts, and password hashes never go into the repo.
  • Secrets and identity: SSH host keys, /etc/machine-id, pacman’s keyring.
  • Generated files: the CA bundle, ld.so.cache, module and hardware databases, the locale archive, the mirror list.
  • State: /var/lib, /var/log, /var/tmp, /swap, /.snapshots, the Nix store (/nix), and aconfmgr’s own checkout.

aconfmgr already ignores /home, /root, /tmp, /var/cache and the pseudo-filesystems. When something new shows up that is state rather than configuration – a database a service keeps under /srv, say – the fix is a line here, with its reason:

Edit this file: ~/arch/aconfmgr/90-ignore.sh
# The music server's library database.
IgnorePath '/srv/music/*.db'

Quote the pattern, or bash expands it before aconfmgr sees it.

Push it somewhere

The host repo is the only record of this machine that exists off its own disk – or it will be, once you push it. The next reinstall starts from it with setup host --from. Make it a private repository: it holds no secrets, but it describes your machine in detail.

Run this on the new machine:
git -C ~/arch remote add origin git@git.example.com:you/arch-myhost.git
git -C ~/arch push -u origin main
// settings
theme:
fx: