| 1 | #!/usr/bin/env sh |
| 2 | # π€ ops β the one operator command surface for deploying and managing the |
| 3 | # fleet. Every verb encodes knowledge that used to live only in prose spread |
| 4 | # across CLAUDE.md, docs/server-releases.md, docs/multi-edge-dev-cutover.md and |
| 5 | # the operator runbook β prose drifts silently; a script that runs drifts |
| 6 | # loudly. When a verb's advice goes stale, fix it IN THE SCRIPT, not in a doc. |
| 7 | # |
| 8 | # This file is deliberately nothing but a signpost: each verb stays a readable |
| 9 | # standalone script beside it (the outlive-AI rule β a human can open any one |
| 10 | # of them and understand it in a sitting), and this dispatcher only routes. |
| 11 | # Add a verb = add a script + one case arm + one usage line. |
| 12 | set -eu |
| 13 | |
| 14 | here="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" |
| 15 | |
| 16 | usage() { |
| 17 | cat <<'EOF' |
| 18 | ops β the operator command surface |
| 19 | |
| 20 | ./deploy/ops doctor [section] can I deploy right now? (read-only preflight) |
| 21 | ./deploy/ops validate [section] run every local check (go|web|shell|infra) |
| 22 | ./deploy/ops provision <units|apex|status|operator> [args] |
| 23 | refresh box systemd units / set the short-link apex / |
| 24 | create an operator account on a box |
| 25 | ./deploy/ops publish "notes" build main -> release -> point edge at it |
| 26 | ./deploy/ops promote <ver> <chan> move beta/stable to a published version |
| 27 | ./deploy/ops ship [box...] make every box's instances catch up NOW |
| 28 | ./deploy/ops canary <create|deploy|reset|destroy|list> [slug] |
| 29 | per-session test instances (test-<slug>.11ch.at) |
| 30 | ./deploy/ops dev <plan|apply|deploy|rebuild> |
| 31 | the two-node dev mesh (tofu / scp+stage+swap) |
| 32 | ./deploy/ops ledger "why..." draft the public SSH-access why-entry |
| 33 | ./deploy/ops mesh seed [--prune] <peer> [box] |
| 34 | replicate routes (+env) to a mesh peer |
| 35 | ./deploy/ops pages push [file...] push committed web/status data files to the |
| 36 | status box (default: carbon.json) |
| 37 | |
| 38 | Start with `ops doctor` β it checks every credential and access path the other |
| 39 | verbs need, and prints the fix under each failure. `ops validate` is its |
| 40 | code-side twin: every local check (Go, web, shell, tofu) in one pass, needing |
| 41 | no credentials and touching no box β run it before opening a PR. Verbs that open box SSH |
| 42 | sessions (ship, canary, dev deploy) incur a why-entry in the public access |
| 43 | ledger; `ops ledger` drafts it. |
| 44 | |
| 45 | Env overrides (defaults live in the verb scripts): |
| 46 | LCHAT_BOXES fleet box ssh aliases (doctor, ship) |
| 47 | LCHAT_CANARY_BOX the box canaries live on (default: the dev mesh; prod is the deliberate exception) |
| 48 | LCHAT_RELEASES_REPO the public releases repo |
| 49 | |
| 50 | No verb for your task? EXTEND ops β a new verb or flag in a small PR |
| 51 | (deploy/README.md Β§ The operator surface) β never a hand-run sequence |
| 52 | reconstructed from docs or runbooks. |
| 53 | EOF |
| 54 | } |
| 55 | |
| 56 | verb="${1:-}" |
| 57 | [ $# -gt 0 ] && shift |
| 58 | case "$verb" in |
| 59 | doctor) exec "$here/doctor.sh" "$@" ;; |
| 60 | validate) exec "$here/ops-validate.sh" "$@" ;; |
| 61 | provision) exec "$here/ops-provision.sh" "$@" ;; |
| 62 | publish|promote|ship) |
| 63 | exec "$here/ops-release.sh" "$verb" "$@" ;; |
| 64 | canary) exec "$here/ops-canary.sh" "$@" ;; |
| 65 | dev) exec "$here/ops-dev.sh" "$@" ;; |
| 66 | ledger) exec "$here/ops-ledger.sh" "$@" ;; |
| 67 | mesh) exec "$here/ops-mesh.sh" "$@" ;; |
| 68 | pages) exec "$here/ops-pages.sh" "$@" ;; |
| 69 | ""|-h|--help|help) usage ;; |
| 70 | *) |
| 71 | printf 'ops: unknown verb %s\n\n' "$verb" >&2 |
| 72 | usage >&2 |
| 73 | exit 2 ;; |
| 74 | esac |
| 75 | |