18 pages cut their per-endpoint shape, payload, port and window claims and
link [[frank-archon]] / [[frank-dragoon]] / [[frank-zealot]] instead. Several
of the cut claims had already drifted -- the stack page still described the
kingjones ROCmFP4 era on ROCmFPX, OpenWebUI carried the 27B/3-slot bench
narrative, Hermes named a retired max_model_len and the old service name, and
the OMP harness page's live-window block had drifted off frank-zealot's real
262,144 (it is now labelled a dated worked example whose authority is the
endpoint page).
Two facts gain a single owner instead of two: the up{job=~"frank-.*"} scope
lives in Infrastructure/Prometheus.md, and the blackbox/Anubis probe form in
Architecture/Stale Signal Audit.md, each cited from the other page.
Voice Packs and Frank TTS carried live-state claims that contradicted the
engine page's 2026-10-18 deploy record (nothing listening on 7772/8880, model
dir absent); they now point at the pages that own host state.
5.7 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||
|---|---|---|---|---|---|---|---|
| guide | Deployment Flow | Service-scoped Git deployment for the two homelab hosts. |
|
2026-09-03 |
Deployment Flow
Git is the single source of truth. scripts/deploy.sh pushes the committed
main branch, pulls it on one target, and applies only the runtime services
whose tracked inputs changed. A SearXNG change no longer recreates the
inference service; an LLM change no longer restarts unrelated containers.
Workflow
graph LR
A[Edit in this repo] --> B[Run tests]
B --> C[Commit main]
C --> D[deploy.sh computes plan]
D --> E[Push main]
E --> F[Target pulls with ff-only]
F --> G[deploy-remote.sh dispatches selected services]
G --> H[Per-service health check]
- Edit files locally in this repository.
- Run
./tests/run.sh, then commit the complete change onmain. - Run
./scripts/deploy.sh <target>. - The planner maps changed paths to services. Compose YAML is compared by service definition so an edit to one service does not restart its peers.
- The target pulls with
git pull --ff-only origin mainand runs the remote dispatcher with the explicit plan. - The dispatcher updates only selected Quadlet, compose, homepage, Caddy, or systemd services and records each successful service revision outside Git.
Commands
./scripts/deploy.sh dankclaw
./scripts/deploy.sh dankserver
./scripts/deploy.sh frankbook-pro --service qbittorrent # podman-machine target
./scripts/deploy.sh dankclaw --service searxng
./scripts/deploy.sh dankserver --service frank-archon
./scripts/deploy.sh dankclaw --dry-run
--service is repeatable and is an explicit retry/override. Without it, the
planner compares the local HEAD to origin/main. A documentation-only
commit produces an empty plan. The remote state directory can also replay a
service whose earlier deployment failed, but it never expands a plan to a
service on the other host.
Service managers
| Service family | Runtime manager | Scope behavior |
|---|---|---|
| Dankclaw compose services | podman-compose -f dankclaw/compose.yaml up -d --no-deps NAME |
Recreates only NAME; Caddy is handled separately because it fronts both hosts. |
| SearXNG, Gluetun, Valkey, OpenWebUI, Pi-hole, Gitea database/server | user Quadlet + systemctl --user |
Installs the selected unit and restarts only the required dependency-coupled units. Gitea's web proxy is the canonical Caddy compose service. |
frank-dragoon |
systemd + systemctl (root unit) |
Relinks and restarts only the Dankclaw iGPU inference service; waits up to 20 minutes for /health. Shape, gates and boot budget: frank-dragoon. |
frank-zealot |
systemd + systemctl (root unit) |
Relinks and restarts only the Dankclaw 3090 inference service; waits up to 20 minutes for /health. Shape, gates and boot budget: frank-zealot. |
frank-archon |
systemd + systemctl (root unit) |
deploy_llm_archon plans from repo paths and gates on the port; it does NOT see host-side unit drift (see frank-archon → Deploy / verify). |
| Dankserver media stack (RomM trio, Jellyfin, Calibre-Web, Copyparty) | user Quadlet + systemctl --user |
Installs dankserver/<svc>/quadlet/*.container, restarts the generated unit. The first cutover per service is idempotent: it retires the compose-era bare container, rescues any anonymous volume into the data root, and merge-moves /opt/<svc> to /home/dank/Containers/<svc> (mapped-uid roots move without chown). Steady state is restart-only. |
The shared chat template maps to the inference service on the selected target.
The frank-npu endpoint is retired (frank-npu) and has no deploy handler;
an unrelated large-model deployment never touches it.
Caddy safety
Caddy runs on Dankclaw and fronts both hosts, including Gitea. The former
standalone gitea-caddy Quadlet is retired; the canonical compose caddy
service is now the sole reverse-proxy owner of ports 80/443. A Caddy reload
failure falls back to a restart of only the selected caddy container.
Before deploying, verify that no retired proxy still owns either port.
Homepage files, generated deployed.js, the status checker, and the rendered
Caddyfile are updated only when their service is selected. A media-only
Dankserver deployment does not touch Dankclaw's proxy or homepage.
Per-service state
The remote runner writes one revision file per successfully completed service to:
${XDG_STATE_HOME:-~/.local/state}/serverAppConfigs/deploy-state/
The directory is outside the checkout and is never committed. A failed handler is not marked successful. On the next ordinary deployment, the runner compares the recorded revision with the new checkout and retries only a still-changed service. This prevents a failed Caddy or LLM deployment from being silently forgotten while avoiding a host-wide restart.
Targets
| Target | Host | Repository checkout |
|---|---|---|
| dankclaw | dank@dankclaw (192.168.0.143) |
/home/dank/serverAppConfigs |
| dankserver | dank@dankserver (192.168.0.235) |
/home/dank/serverAppConfigs |
SSH uses the existing key pair. No password is stored or documented in this
repository. If sudo is needed on a headless target, FRANK_SUDO_PW is read
from the environment and is never written to the repository.
Tests
Run the full suite before pushing:
./tests/run.sh
The deployment seams are in tests/deployment_scoping.bats and
tests/deployment_flow.bats. They cover path isolation, compose narrowing,
Caddy safety, inference isolation, per-service state, and legacy wrapper
routing. See Testing Policy.