chore: move code comments into docs, leave one-line pointers

Explanations from docker-compose.yml, .env.example and
scripts/update.sh now live in docs/architecture.md, gateway.md,
network-access.md and operations.md. Code keeps `# see docs/...`
pointers, one-line warnings (storage key, SSRF guard, WAL grace period,
git pull ordering) and "auto-filled — leave blank" markers.

Refs #55 (comment destination map #61)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
haylanandClaude Bot committed 2026-09-24 21:52:00 +02:00
1 parent a0e5e9704b
commit 05effe5c88
4 files changed
+31 -265

No files matched your search

+8 -66
View File
@@ -1,28 +1,6 @@
#!/usr/bin/env bash
# The one command to run after any change to this repo (compose file, .env,
# or a git pull) to bring the running stack in sync. Ensures secrets/keys
# exist, pulls, validates, rebuilds/re-pulls images, and recreates only what
# changed — safe to run any time, including with nothing to do.
#
# Tunable config values (LLAMA_*, ports, timeouts — anything with a real
# default in .env.example) are synced from .env.example every run. A value
# already matching is left alone silently. A value that DIFFERS from the
# server's current .env is a conflict: interactively, you're shown every
# conflict on one screen (via gum) and choose which to accept — unpicked
# keys keep the server's current value. Non-interactively (no TTY — cron,
# CI, piped), any conflict is a hard error unless --force is passed, which
# accepts every new value automatically. Secrets and host-resolved values
# (blank in .env.example — OMNIROUTE_*_SECRET/_KEY/_SALT/_PASSWORD,
# SEARXNG_LAN_IP, HOST_VIDEO_GID/RENDER_GID) are never
# touched by this — they keep going through set_if_blank as before.
#
# omniroute's own routing/provider config (llama-server, search) lives in
# its dashboard, not a checked-in file like the old litellm-config.yaml —
# see issue #31 and docs/proxy-key-onboarding.md.
#
# ponytail: no rollback/backup logic — this is a single-user homelab box,
# not a fleet. If a bad config lands, `git revert` + re-run is the recovery
# path, not this script.
# Brings the running stack in sync with this repo; safe to re-run any time.
# What it does and why: docs/operations.md
set -euo pipefail
cd "$(dirname "$0")/.."
@@ -34,25 +12,14 @@ for arg in "$@"; do
esac
done
# Must run before anything else touches a file this script itself reads
# (docker-compose.yml, .env.example, this script's own remaining lines) —
# a self-updating script isn't guaranteed atomic against its own file
# changing mid-run, so pulling later can execute a mix of old and new
# script/compose content in one pass. Bit us for real: old GID-resolution
# code ran, then this pulled in new var names docker-compose.yml now
# requires, and nothing re-ran the (now-current) resolution step for
# them — see issue #5's thread.
# Keep this first — see docs/operations.md#self-update
echo "==> git pull"
git pull --ff-only
[ -f .env ] || cp .env.example .env
echo "==> syncing tracked config values from .env.example"
# ponytail: gum (charmbracelet/gum) is a single static binary. Vendored as
# a release tarball under scripts/vendor/ (checked into git) for the R9700
# box, which has no outbound internet access — the download fallback below
# is only for other archs / when the vendored copy is missing or stale.
# Cached under .cache/gum/ (gitignored) so repeat runs don't re-extract.
# see docs/operations.md#gum
GUM_VERSION="0.14.5"
GUM_DIR="$(pwd)/.cache/gum"
GUM_BIN="$GUM_DIR/gum"
@@ -84,10 +51,7 @@ ensure_gum() {
[ -x "$GUM_BIN" ] && echo "$GUM_BIN" || echo ""
}
# Collect every key where .env.example has a real (non-blank) default:
# missing from .env -> just add it (no conflict, nothing to decide);
# present and identical -> leave alone silently; present and different ->
# a conflict to resolve below.
# see docs/operations.md#env-sync
conflict_keys=()
conflict_old=()
conflict_new=()
@@ -128,8 +92,6 @@ if [ "${#conflict_keys[@]}" -gt 0 ]; then
if [ -n "$gum_bin" ]; then
selected="$(printf '%s\n' "${labels[@]}" | "$gum_bin" choose --no-limit --selected "$(printf '%s\n' "${labels[@]}" | paste -sd,)" --header "Config differs from .env.example — selected keys take the new value, unselected keep the server's current value:")"
else
# ponytail: plain-bash fallback if gum couldn't be fetched (offline,
# unsupported arch) — same one-screen-of-conflicts idea, cruder UI.
echo "Config differs from .env.example. Enter space-separated numbers to KEEP the server's current value (all others take the new value), or press enter to take every new value:"
for i in "${!conflict_keys[@]}"; do
echo " $((i+1))) ${labels[$i]}"
@@ -155,9 +117,6 @@ if [ "${#conflict_keys[@]}" -gt 0 ]; then
fi
fi
# Handles all three cases: the KEY=value line is missing entirely (.env
# predates that var being added to .env.example — sed can't fix what isn't
# there, so this appends it), present but blank, or already set.
set_if_blank() {
local key="$1" value="$2"
if grep -qE "^${key}=.*[^[:space:]]" .env; then
@@ -172,10 +131,7 @@ set_if_blank() {
}
echo "==> filling in missing secrets"
# Random values — safe to re-run, never overwrites what's already set.
# OMNIROUTE_STORAGE_ENCRYPTION_KEY especially: never change it after first
# run, existing encrypted data becomes unreadable if you do (same caveat as
# LiteLLM's old LITELLM_SALT_KEY).
# see docs/operations.md#secrets
set_if_blank OMNIROUTE_INITIAL_PASSWORD "$(openssl rand -hex 16)"
set_if_blank OMNIROUTE_JWT_SECRET "$(openssl rand -base64 48)"
set_if_blank OMNIROUTE_API_KEY_SECRET "$(openssl rand -hex 32)"
@@ -185,9 +141,7 @@ set_if_blank OMNIROUTE_CLI_SALT "$(openssl rand -hex 16)"
set_if_blank OMNIROUTE_WS_BRIDGE_SECRET "$(openssl rand -hex 32)"
echo "==> resolving SEARXNG_LAN_IP"
# search.home is a LAN mDNS/local-DNS name — resolvable from this host, just
# not from inside the omniroute container (see docs/research/litellm-searxng-search.md,
# still the relevant background even though omniroute replaced litellm — see issue #31).
# see docs/gateway.md#web-search
searxng_ip="$(getent hosts search.home 2>/dev/null | awk '{print $1}' | head -1)"
if [ -n "$searxng_ip" ]; then
set_if_blank SEARXNG_LAN_IP "$searxng_ip"
@@ -196,11 +150,7 @@ else
fi
echo "==> resolving host video/render GIDs (shared by every GPU service)"
# Numeric GIDs, not names, in docker-compose.yml's group_add: — Docker
# resolves a *named* group_add entry against the container's own /etc/group,
# not the host's, and fails unpredictably (worse with multiple GPU services
# starting concurrently and racing on the same lookup) — see
# docs/research/rocm-gpu-pin-and-render-group.md and issue #5.
# see docs/architecture.md#gpu-access
video_gid="$(getent group video 2>/dev/null | cut -d: -f3)"
render_gid="$(getent group render 2>/dev/null | cut -d: -f3)"
if [ -n "$video_gid" ]; then
@@ -230,14 +180,6 @@ docker compose --profile tools run --rm downloader-classifier
echo "==> bringing up omniroute"
docker compose up -d --wait omniroute
# ponytail: no scripted key-minting yet, unlike the old LiteLLM /key/generate
# flow — omniroute's POST /api/keys needs a dashboard login session
# (ManagementSessionAuth), not a static bearer key, and that flow hasn't
# been verified against a live instance (see issue #37). No in-stack
# workload needs a key right now (nothing left calls the gateway besides
# coding CLIs, which mint their own by hand per docs/proxy-key-onboarding.md)
# — revisit this script once that flow is automatable.
echo "==> recreating changed services"
docker compose up -d --remove-orphans