Panama learns what a server is: from a root login to running containers

A machine's role is now the interview's first question and the one answer
Panama records. Servers get the same shell minus the screen: core packages,
nvm, Bun, Claude Code and Codex (desktops get Codex too), linger, rootless
ports from 80, firewalld, the nginx-bridge network, and a nightly image
updater that replaced watchtower for cause.

server/containers/ carries junior's 23 compose services -- secrets moved to
per-machine .env files that never enter this public repo, every transformed
compose proven to render byte-identical to what is live. 'panama server'
enables, disables and relinks them; nothing here restarts a running service.
'boot --server' walks a fresh VPS from its root login to a normal install.

Five new contracts pin the secrets rule, the catalog's shape, panama-server's
behavior, the role plumbing, and the dotfile classification.

Claude-Session: https://claude.ai/code/session_01NU5JGiN3JfzqrLQB6wmJ1E
This commit is contained in:
Gabriel Brown
2026-08-25 23:11:49 -04:00
parent 9b338608ef
commit f33da41cc6
93 changed files with 4735 additions and 247 deletions
+32 -1
View File
@@ -29,6 +29,22 @@ It pulls, applies any repairs this machine has not had, and runs the stages
below that need no answers. `./install` remains what it is: how a machine is
built, and how you change an answer you gave.
The first question the interview asks is what the machine is: a **desktop**
gets everything below; a **server** — a VPS, a headless box — gets the same
shell environment minus everything that needs a screen, plus rootless podman
and the compose services in [`server/`](server/README.md). The answer is the
one thing Panama records durably (`~/.local/state/panama/role`), because
`panama update` asks nothing and still has to know. A fresh server skips the
question entirely:
```sh
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server
```
That command also works from a brand-new VPS's **root** login: it creates
your user with sudo, moves the SSH key over, offers to harden sshd, and hands
off to a normal install as that user.
`install` asks its questions first and then runs the stages in `setup/scripts/`
in order, without stopping again:
@@ -43,6 +59,15 @@ in order, without stopping again:
| `link-vicinae-scripts` | Publishes the Vicinae script commands |
| `setup-identity` | git config, `gh auth login`, an SSH key — whichever were asked for |
| `install-hardware` | NVIDIA, Secure Boot enrollment, Fedora's extras, firmware — each only if it was asked for. Last, because enrollment and firmware are consumed at the next boot |
| `setup-server` | Server role only: linger, unprivileged ports from 80, firewalld (80/443/81), the `nginx-bridge` network, and the nightly image-update timer |
| `link-server` | Server role only: creates `~/Server` and refreshes the links of whatever services this machine has enabled |
A server runs the shared stages plus its own two, and skips the rest —
`link-skills`, `change-settings`, `link-vicinae-scripts` and
`install-hardware` are desktop concerns. `link-dotfiles` links only the
universal dot dirs there (bash, nvim, tmux, btop and tmux theming, the hook
samples), and `install-packages` takes a short path: the core tools, nvm,
Bun, Claude Code and Codex — no third-party repos, no desktop, no flatpaks.
Then `panama migrate` applies any repairs this machine has not had yet. That is
the half of an upgrade installing cannot do: the stages above only ever add, so
@@ -157,6 +182,9 @@ config/
extensions, linked into ~/.local/share
old/ Backups of whatever was replaced (gitignored)
wallpapers/ Copied into ~/Pictures/Wallpapers when absent
server/ The server role: compose services (one directory per
service), the nightly image updater, and its units. See
server/README.md
skills/ Agent skills for operating this desktop, linked into
~/.claude/skills
setup/
@@ -170,7 +198,7 @@ docs/ Settings reference, and the design specs behind the work
## Tests
180 of them, under `tests/`. Run the lot, or a subset by pattern:
185 of them, under `tests/`. Run the lot, or a subset by pattern:
```sh
panama test # everything
@@ -190,6 +218,8 @@ been ones that source text looked fine for.
tests/setup/ The installer: the interview, package lists, hardware, extras
tests/quickshell/ The shell and its settings pages
tests/hypr/ The compositor config
tests/server/ The server role: the service catalog's shape, the secrets
rule that keeps a public repo safe, and panama-server
```
## Projects
@@ -220,6 +250,7 @@ panama migrate # apply repairs this machine has not had yet
panama upgrade # re-run ./install from anywhere, interview and all
panama apps # choose applications to install, by category
panama app # applications no repository carries; build one by name
panama server # the services a server runs: list, enable, disable, status
```
`panama update` and `panama sync` are separate verbs on purpose. One acts on