Successor Handbook#
This page is for a technical person who has to run or wind down this fleet without Ben. The family-facing version is If Something Happens to Ben. Everything here is in the repository; nothing depends on a chat history or a private note.
Read in this order:
- This page.
- Accounts & Credentials — what you need access to and what breaks when each lapses.
- In-flight work — what is half-done or deliberately parked.
- SDLC & Policies — how changes are proven and shipped.
- The machine and service pages for whatever you touch first.
Fleet at a glance#
Source of truth: hosts/default.nix (the easy-hosts registry). Everything not
in that file is outside the flake and listed in the second table.
| Host | Hardware / role | System | Config path | Tags | Notes |
|---|---|---|---|---|---|
| ereshkigal | Dell R720xd server: media, Paperless, PKI, telemetry, binary cache, deploy node, and the only closure-building CI (om ci) |
x86_64-linux | hosts/x86_64-nixos/ereshkigal/ |
server, media-acquisition, cache, builder | Loud and optional for the family; critical for maintaining the fleet |
| mokou | Ben’s desktop; Ollama fallback; Tailnet Lock signing node | x86_64-linux | hosts/x86_64-nixos/mokou/ |
desktop, builder | LUKS + FIDO2 root (YubiKey recovery) |
| shinobu | ThinkPad P14s laptop; imports the private corp compliance module |
x86_64-linux | hosts/x86_64-nixos/shinobu/ |
laptop, builder | LUKS (passphrase) |
| razer | 2014 Razer Blade; Tdarr node | x86_64-linux | hosts/x86_64-nixos/razer/ |
laptop, builder | Can be retired without impact |
| myon | BuyVM 1 GB VPS; Tailscale exit node for acquisition egress | x86_64-linux | hosts/x86_64-nixos/myon/ |
exit-node | Never builds on-box; paid monthly |
| octopi | Raspberry Pi 3B: OctoPrint, barcode and document scanners | aarch64-linux | hosts/x86_64-nixos/octopi/ (historical path; arch comes from the registry) |
rpi | Reflash only for partition changes |
| haxo | Pi Zero 2 W Haxophone (declared; the physical unit still runs Raspberry Pi OS) | aarch64-linux | hosts/aarch64-nixos/haxo/ |
rpi | Not live yet |
| work-laptop-m4 | Jamf-managed MacBook Pro M4; primary Ollama; the only aarch64-darwin builder | aarch64-darwin | hosts/aarch64-darwin/work-laptop-m4/ |
laptop, builder | Employer-owned |
| bedford-drdillo-mbair | MacBook Air at the Bedford site | aarch64-darwin | hosts/aarch64-darwin/drdillo-mbair/ |
laptop | |
bootable-iso |
Installer/rescue ISO configuration, not a machine | x86_64-linux | hosts/x86_64-nixos/bootable-iso/ |
— | nix build .#nixosConfigurations.bootable-iso.config.system.build.isoImage |
| bedford-kitchen-macmini, bedford-office-macmini | Catalina Intel Mac minis | x86_64-darwin | commented out in hosts/default.nix |
— | Paused 2026-08-14: nixpkgs 26.11 dropped x86_64-darwin; still sops recipients |
Outside the flake (change them in their own consoles, never in .nix):
| System | What it is | Where to change it | Docs |
|---|---|---|---|
| voile | Synology DS1621+ NAS: BorgWarehouse (/volume1/BorgWarehouse, docker compose), the Forgejo mirror (:8418, the ref hosts converge from), Kiwix (/volume2/Kiwix), RADIUS/LDAP for FalseBlue Wi-Fi, TaskWarrior sync, media shares, the inaba.network portal cloudflared, OpenArchiver |
DSM at https://voile:5001, or SSH | Backups, Forgejo, Kiwix |
| yukari | UniFi Dream Machine Pro: router, VLANs, Wi-Fi SSIDs | UniFi OS at https://192.168.0.1 | Wi-Fi |
| Home Assistant | HAOS virtual machine on ereshkigal (libvirt). The flake owns the VM; HA and its add-ons are configured in the HA UI | http://192.168.0.55:8123 | Home Assistant, VM runbook |
| Cloudflare / Entra | DNS, tunnel, and Access policies for *.inaba.network; generated from Nix by nix run .#terraform-cloudflare but apply is run by a human |
dash.cloudflare.com, entra.microsoft.com | Authentication, Accounts |
You cannot do anything without#
- An age key that is a recipient of
secrets.yaml..sops.yamllists the recipients. Every host build decrypts secrets at activation, andjust preflightfails at its first check without one. A new person becomes a recipient only when someone who already holds a recipient key adds the new public key to.sops.yamland runsjust sops-updatekeys(Adding a collaborator user). Recipients today are Ben’s personal keys plus the host keys, so the bootstrap paths are: a host you can log into (its/etc/ssh/ssh_host_ed25519_keyis an age identity viassh-to-age), or an offline copy of Ben’s key.TODO(owner): where is the offline copy of a recipient age key (printed, USB, vault item), and who may retrieve it? pki/dbis narrower still. The CA database decrypts only to two of Ben’s personal keys (.sops.yamlrule^pki/db). Holding asecrets.yamlkey does not help. See CA escrow and break-glass.- Bitwarden. Wi-Fi passwords, the XCA database passphrase (
FalseBlue Root CA Key), and the LUKS recovery passphrase for mokou’s/poollive in Ben’s personal vault.TODO(owner): how does a successor reach the vault (emergency-access contact, recovery-key location)? - Tailscale admin and Tailnet Lock. Every host is reached over the
armadillo-banfish.ts.nettailnet. Tailnet Lock is enabled: a new node joins, shows Online, and has zero peer connectivity untiltailscale lock sign <nodekey> <tlpub>is run from a node holding a trusted signing key (mokou, with sudo).TODO(owner): if mokou is gone, which other node or offline key can sign? - The YubiKeys. mokou’s root disk unlocks with a YubiKey (FIDO2), SSH to every host uses the Nano 5C’s OpenPGP auth key, and the CA keys are on both keys. What each key gates and what still works without it: YubiKey recovery.
- GitHub. The repository is private under
tsunaminoai. CI needs thesc2benmachine-account key for the privatecorpinput; ereshkigal’s scheduler needsgithub/automation-token. Details in Accounts.
Build and deploy safely#
Never deploy what you did not build. The local gate is one command:
just gate <host> # format check → host toplevel → telemetry/gatus checks (when the host has them) → docs
It does not replace om ci on ereshkigal, which is the only pipeline that
builds every host closure — GitHub’s nix flake check builds no host
toplevels (om ci triage).
Deploy one host, from a clean tree, with a long confirm timeout:
nix run .#deploy -- .#<host> -s --confirm-timeout 120
The traps (working-tree deploys, -dirty revisions, mokou refusing
SSH-to-self) are in
the battle-tested invocation.
Roll a host back with nix run .#deploy-rollback <host>.
Facts that bite first-time operators:
- Dirty-tree builds see git-tracked files only:
git addnew files before anynix build, or the build silently uses the old tree. docs/is a symlink topkgs/docs/content/; edit andgit addthe real path.- A sops secret must exist in
secrets.yamlbefore you build a host that declares it (sops-nix validates at eval time). Add a placeholder first. - Evaluating any host fetches the private
git+ssh://…/sc2in/corpinput (every flake input is in every host’snix.registry). Without the sc2ben SSH key, stub it:--override-input corp path:./ci/stub-corp(flake/corpunderom ci, because omnix nests the target flake as inputflake). - Do not read the four >1000-line files whole
(
modules/nixos/telemetry/server.nix,modules/nixos/media/weather-channel.nix,modules/nixos/containers/doc-pipeline/default.nix,hosts/x86_64-nixos/ereshkigal/default.nix); grep for a# ── … ──section marker and read that section.
How the fleet updates itself (five lines)#
- ereshkigal, 1st and 15th at 03:00:
nix run .#updatebumps the public inputs, runs a fullom ci, opens PRautomation/flake-update, and auto-merges on green. release.ymltags CalVer and fast-forwardsrelease— only for commits that landed via a merged PR.- Each NixOS host’s
nixos-upgrade(04:30) fetchesreleasefrom the voile Forgejo mirror and switches only when provably behind (fail-closed guard). - Guard verdicts are metrics;
AutoUpgradeCompareFailed/AutoUpgradeStuckBehindReleasepage after 48 h / 72 h. - Everything else is a deliberate
deploy-rspush.
Triage, retracting a bad release, and the gotchas: Fleet convergence runbook.
The builder concentration risk#
All remote builders (ereshkigal, mokou, razer, shinobu,
work-laptop-m4 — the builder tag in hosts/default.nix), the binary cache
(ereshkigal :11111), and the only closure-building CI (om ci on ereshkigal)
are Ben’s own machines. If ereshkigal is off, nothing builds the fleet
automatically and the cache is gone. The emergency guide tells
the family they may power it down; that is true for the household and false
for anyone maintaining the other machines.
Degraded mode, when builders or the cache are unreachable:
- Build locally only: append
--builders "" --max-jobs 4tonix build. - Stop offloading permanently: remove the
buildertag from dead hosts inhosts/default.nix(tag discovery generatesnix.buildMachines), then rebuild. - Shrink the scheduled CI:
tsunaminoai.ci.autoUpdate.ciCommand = "om ci run '.#default'"(Automated flake updates). - Expect long builds. Without the cache a host toplevel takes hours, and the
octopi kernel only stays cheap because
nixos-raspberrypi.cachix.orgserves it: before flashing, confirmnix build --dry-runlists nothing containinglinux-rpiunder “will be built”.
When a host will not boot#
A hub — each link is the detailed procedure.
| Host | First move | Then |
|---|---|---|
| Any NixOS host | Pick the previous generation in the systemd-boot menu | nix run .#deploy-rollback <host> once SSH is back |
| mokou | The LUKS prompt needs the YubiKey (FIDO2) or an enrolled passphrase — YubiKey recovery → If the nano5c is lost. Plymouth is off in initrd so the prompt is visible | mokou storage for the /pool recovery slots |
| shinobu | LUKS passphrase at boot (two volumes in hardware-configuration.nix) |
— |
| ereshkigal | iDRAC virtual console and power at https://192.168.0.21/ (iDRAC) | Storage & health runbook |
| myon | BuyVM Stallion panel → console / rescue ISO; never kexec or install on-box (1 GB OOMs) | myon install runbook |
| octopi | Pull the SD card, just flash-octopi, reinsert; mint a fresh Tailscale auth key first |
Deploying changes |
| Anything, from scratch | Build the installer ISO (bootable-iso; Adding a Host, Step 6) |
Sops bootstrap after a wipe, then Restore |
Winding down instead#
If the decision is to stop running this fleet, the family guide’s wind-down table is the order of operations. Add these technical steps:
- Cancel myon at BuyVM and remove its node in the Tailscale admin console.
- Export Paperless (
paperless-export/on voile already holds archival copies) and the Jellyfin library before powering ereshkigal off. - Run the decommissioning runbook per host so disks are cryptographically erased and the log has a row.