Appearance
Install-Script Discipline
Every host, VM, and container Hinata stands up must commit a runnable install script to this directory at the moment of standing it up. Not retrofitted. Not screenshotted. Not "I'll remember." If it's not a script, it doesn't exist.
This is the operational embodiment of the three-tier documentation axis in self-hosted-architecture §2.
The contract
A script in this directory must satisfy all five:
Idempotent — running it twice produces the same end state, never duplicates or breaks
Clean-slate runnable — assumes a freshly installed base OS at a stated version; bootstraps everything from there
Self-documenting — header block declares: target host class, base OS, what it installs, expected runtime, prerequisites
No interactive prompts — every value either hardcoded, env-var driven, or read from a stated source
Named per naming register — once the register is published, scripts adopt its host/role naming
File layout
install-scripts/
├── understanding_install-script-discipline.md ← this file
├── <hostname>-<role>.sh ← top-level: build a named host
├── <hostname>-<role>.md ← optional: design notes for that host
└── components/ ← reusable fragments sourced by host scripts
├── bootstrap-debian-12.sh ← OS-level setup
├── install-tailscale.sh
├── install-docker.sh
└── …Rule: if the same setup appears in two host scripts, extract it into components/ and source it. Don't copy-paste.
Required header for every script
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# Host: <hostname-from-naming-register>
# Role: <one-line description>
# Base OS: <distro + version>
# Provider: <e.g. "GCP europe-west2-b e2-micro" or "Raspberry Pi 5 / 8GB">
# Built: <YYYY-MM-DD when first run>
# Last edit: <YYYY-MM-DD>
# Runtime: <expected wall-clock for fresh run>
# Prereqs:
# - <e.g. "Vaultwarden CLI session token in $BW_SESSION">
# Idempotent: yes
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefailWhat does NOT belong here
Vault scripts (Telegram bots, normalisers, audit runners) — those live in
/opt/jimmy-brain-ops/scripts/One-off commands run interactively
LaunchAgent plists — those live in
~/Library/LaunchAgents/
When to write the script
At build time. Not after.
Concretely: the first time Jimmy Neutron stands up a host, the build session produces (a) the running host and (b) the committed script as parallel deliverables. A completed build that does not commit a script is not a completed build — it's a debt.
Credential handling
* Scripts must not hardcode secrets. Reference them by name.
* Read from `$ENV_VAR_NAME` at invocation time
* Header documents the expected env vars under Prereqs
* Never `echo` a secret value, even in dry-run mode