sanctum CLI Reference

sanctum is the operator surface for every Sanctum host — router, wizard, doctor in one Python binary (Typer + Rich). The public install path is the Homebrew tap ogilthorp3/sanctum (public), so brew install ogilthorp3/sanctum/sanctum-cli works directly — it auto-taps on first use. (On Bert’s own host it also exists as a dev install at ~/.local/bin/sanctum.) The everyday commands are below; a dozen deeper helpers sit one level down. sanctum --help is the canonical roster, and it moves faster than this page.
sanctum <command> [args]Most commands read ~/.sanctum/instance.yaml and fail blunt when it’s missing or invalid. The errors are deliberately curt — Sanctum is for technical-friend haushelds, and we trust you with the real line.
sanctum doctor
Section titled “sanctum doctor”The first command you run, the first when something’s wrong, and the first we’ll ask you to run when you reach out for help. It probes the three subsystems that must be healthy for the host to work.
sanctum doctorsanctum doctor --fullsanctum doctor --jsonWhat it checks
Section titled “What it checks”| Group | Probe |
|---|---|
| LaunchAgents | launchctl list, filtered to com.sanctum.*. Each row’s status is derived from its PID and last exit code |
| Providers | Reachability + latency for each configured model provider (claude, gemini, mlx_local) |
| Backup repos | restic snapshots against each configured repo (local SSD + cloud) |
It’s brevity-gated — one OK line when green, the full tables only on a DEGRADED/FAILED row or --full. --json emits the whole report, for the menu-bar plugin and CI.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Nothing worse than OPERATIONAL |
1 | At least one subsystem is DEGRADED or FAILED (or instance.yaml is missing) |
sanctum self-test
Section titled “sanctum self-test”The canonical health suite — tells you whether the install is still good after an update, a reboot, or a drift suspicion. Twelve probes, two tiers:
sanctum self-testsanctum self-test --jsonsanctum self-test --only cathedralThe twelve probes
Section titled “The twelve probes”| # | Probe | Verifies | Tier |
|---|---|---|---|
| 1 | network reachability | loopback + DNS resolve | CLI |
| 2 | node binary identity | /usr/local/bin/node is the signed Node.js Foundation binary | CLI |
| 3 | sanctum config valid | ~/.sanctum/instance.yaml parses and validates | CLI |
| 4 | recent backup snapshot | a restic snapshot exists and is recent (n/a on a fresh install) | CLI |
| 5 | Yoda cathedral (:1337) | TLS port reachable | haus |
| 6 | Coder cathedral (:1338) | TLS port reachable | haus |
| 7 | proxyd routing (:4040) | service alive (an HTTP 401 counts — it answered) | haus |
| 8 | Force Flow (:4077) | listening | haus |
| 9 | chitti samskara (:2188) | listening | haus |
| 10 | TCC grants | the expected automation grants are present | haus |
| 11 | R2D2 supervisor heartbeat | the auto-fix supervisor is beating, with a sane success rate | haus |
| 12 | audit log within budget | the audit log is under its size cap | haus |
The four CLI-tier probes run everywhere. The eight haus-tier probes only mean something once the haus services are up; on a CLI-only box they return n/a, not fail, and n/a doesn’t count.
Pass rule
Section titled “Pass rule”No percentage threshold. The suite exits 0 iff every applicable probe passes; one real failure exits 1. n/a probes are skipped either way.
[ 6/12] Coder cathedral (:1338) ···· fail no response on :1338
1 probe(s) failed. 11/12 applicable probes passed in 185 ms. Each red line above has the actionable detail.sanctum logs self-test has the full transcript if a red line’s own detail isn’t enough. --only <substr> narrows to matching probe names; --json feeds the soak harness. Run it after install, a macOS major upgrade, or a reboot you’re unsure of, and weekly as hygiene — sanctum update runs it as the gate.
sanctum status
Section titled “sanctum status”The thirty-second health glance — who am I, where’s my disk, when did I last back up, how busy have I been. The host’s own vital signs, no probes into other services. Run this if you run one command in the morning.
sanctum statussanctum status --onelinesanctum status --jsonWhat it reports
Section titled “What it reports”| Field | Source |
|---|---|
| instance / host | instance.yaml (instance name, hostname) |
| default provider | the router’s current default (e.g. claude) |
| disk | df on /System/Volumes/Data; DEGRADED at >=85% used, FAILED at >=90% |
| backups | restic snapshot count + age per repo (local SSD + cloud), oldest age wins |
| telemetry | 7-day rollup: requests and errors |
The default render is a set of Rich tables; --oneline collapses it to one line, what the menu-bar plugin and a morning glance want:
sanctum @ manoir.local · backup 7h / ? · router→claude · disk 76% (operational) · telemetry 32r/8e/7dstatus answers “is this host okay right now?”; doctor is what you reach for when it shows red.
sanctum update
Section titled “sanctum update”Upgrades the CLI via the Homebrew tap, then re-runs sanctum self-test as the gate. Run by hand on a new release; not (yet) wired into a launchd timer.
sanctum updatesanctum update --dry-runsanctum update --skip-self-testIt runs brew update, then brew upgrade ogilthorp3/sanctum/sanctum-cli, then sanctum self-test as the gate — and refuses to call the upgrade “done” unless every probe still passes.
| Flag | Behavior |
|---|---|
--dry-run | Print every action without executing |
--skip-self-test | Skip the gate. Operator-grade — use when you know what you’re doing |
brew upgrade exits 0 even when nothing changed, so an already-current install falls through harmlessly. If the gate fails after a real upgrade, the command exits non-zero and says so — investigate, then downgrade or fix forward.
sanctum uninstall
Section titled “sanctum uninstall”Removes every operational artifact — LaunchAgents, Keychain credentials, the brew tap reference — but never your data. Pass --purge if you actually want the data gone too.
sanctum uninstallsanctum uninstall --purgesanctum uninstall --dry-runWhat it removes (always)
Section titled “What it removes (always)”- Every
com.sanctum.*LaunchAgent in~/Library/LaunchAgents/—bootoutplus the plist renamed.plist.uninstalled-YYYY-MM-DD(orphan plists are worse than missing services). Discovered by glob, so it tracks the roster. - Every
sanctum/*Keychain entry, revoked viasecurity delete-generic-password. - The
ogilthorp3/sanctumbrew tap reference (a laterbrew installre-taps). SanctumBridge.app+SanctumLauncher.app, renamed with the.uninstalled-suffix.
What it preserves (without --purge)
Section titled “What it preserves (without --purge)”~/.sanctum/logs/ (audit), memory/ (agent memory + Memory Vault), backups/ (local snapshots), secrets/ (mode-600 files), and your cloud bucket — your R2/B2/gdrive target is untouched.
What --purge adds
Section titled “What --purge adds”The ~/.sanctum/ data dirs above, renamed to ~/.sanctum.purged-<timestamp> rather than rm -rf’d — a fat-fingered purge gets a few seconds of grace. It never touches /usr/local/bin/node, the Apple Installer’s domain.
sanctum logs <service>
Section titled “sanctum logs <service>”A typed shortcut around tail. Resolves a short name to its real path (some under ~/.sanctum/logs/, some ~/.openclaw/logs/) and streams it — follow, last 50 lines.
sanctum logs <service>sanctum logs --listsanctum logs proxyd --once -n 200Service names
Section titled “Service names”sanctum logs --list prints the canonical map — names, paths, which files exist — and won’t go stale:
| Name | File |
|---|---|
r2d2 | ~/.sanctum/logs/r2d2-audit.jsonl |
kitchen-loop | ~/.sanctum/logs/kitchen-loop.log |
proxyd | ~/.openclaw/logs/proxyd.log |
yoda | ~/.openclaw/logs/sanctum-mlx.log |
coder | ~/.openclaw/logs/sanctum-mlx-coder.log |
cathedral | both sanctum-mlx.log + sanctum-mlx-coder.log |
bridge | ~/.openclaw/logs/sanctum-bridge.log |
force-flow | ~/.openclaw/logs/force-flow.log |
watchdog | ~/.openclaw/logs/watchdog-rust.log |
agent-trace | ~/.sanctum/logs/agent-trace.log |
ram-sentinel | ~/.sanctum/logs/ram-sentinel.log |
launchd-health | ~/.sanctum/logs/launchd-health.log |
signal | ~/.sanctum/logs/signal-health.log |
backup | ~/.sanctum/logs/backup.log |
self-test | ~/.sanctum/logs/self-test.log |
log-rotate | ~/.sanctum/logs/log-rotate.log |
| Flag | Behavior |
|---|---|
--follow / --once, -f | Stream (default) or take a one-shot snapshot |
--lines, -n | How many lines of history to show first (default 50) |
--list | Print every known service + its path, then exit |
Anything not in the map is rejected with a pointer to --list — no fuzzy-match; know which log you want.
sanctum devices
Section titled “sanctum devices”Read-only inventory, three tables: Family (per-person), Shared, and Unassigned (auto-discovered, not yet attributed). It reads the Screen Time module’s devices.yaml — the source of truth mapping MACs to people and categories.
sanctum devicesLookup order: $SANCTUM_DEVICES_FILE (a fixture override; unset in production), then ~/.sanctum/screen-time/devices.yaml, then ~/Projects/sanctum-screen-time/devices.yaml; first existing wins. It does not mutate — assigning is sanctum screen-time assign (Family Pass Phase 2) or editing the YAML.
sanctum schedule
Section titled “sanctum schedule”Read-only view of the curfew schedule — weekday/weekend cutoffs per child, plus shared-device hard curfews. No separate file; curfews live in the same devices.yaml that sanctum devices reads.
sanctum scheduleIt shows; it does not edit. To extend a curfew once — a school event, a late movie — use the Force Flow override the command prints:
curl -X POST http://127.0.0.1:4077/screen/override \ -d '{"target":"NAME","minutes":30}'sanctum net check
Section titled “sanctum net check”Read-only audit of your network topology. It works out whether you’re behind one NAT or two, names your ISP, finds your default gateway, and explains in one line what it concluded. It changes nothing — run it as often as you like.
sanctum net checkIt prints three things: the NAT topology (single, double, or unknown), the ISP and gateway it detected, and the reasoning behind the verdict. That last line is the part to read — a double-NAT call is only as good as the evidence it cites.
sanctum net optimize
Section titled “sanctum net optimize”The guided path from double-NAT to single-NAT — the configuration where your own router (a Firewalla, typically) holds the public IP instead of the ISP’s hub. It is opt-in and reversible: it snapshots a rollback baseline before you touch anything, warns you that the cutover briefly drops your internet, and walks an ISP-specific playbook step by step.
sanctum net optimizesanctum net optimize --plan-onlysanctum net optimize --yesIt runs net check first. If you’re already single-NAT — or there’s no Firewalla to put in front — it says so and exits 0 without prompting. Otherwise it prints the plan for your detected ISP, captures the rollback snapshot, confirms you’re physically at the box (not remote — this drops the link), and then waits for you to run the steps before verifying the result.
| Flag | Behavior |
|---|---|
--plan-only | Print the ISP-specific plan and stop — no snapshot, no prompt, no verify loop. The dry-read |
--yes / -y | Skip the “are you at the box?” confirmation. For when you already know |
The verify loop
Section titled “The verify loop”After you’ve done the steps, it probes the result and renders one of three verdicts: VERIFIED (the cutover took), APIPA_ROLLBACK (the box fell back to a self-assigned 169.254.x.x address — the change failed, and it prints the rollback commands), or an inconclusive note when it can’t tell yet.
sanctum net speedtest
Section titled “sanctum net speedtest”The honest throughput doctor. A multi-gig line routinely “tests slow” because the test is the bottleneck, not the line — a single TCP stream tops out near 2 Gbps, Wi-Fi caps you around 1-2, and the ISP hub’s built-in test runs on a weak CPU over one connection. This command runs a multi-stream test, reads the link speed of every hop it can see, and names the real ceiling instead of leaving you guessing.
sanctum net speedtestsanctum net speedtest --streams 16sanctum net speedtest --no-testsanctum net speedtest --jsonIt walks the path — your NIC, whether you’re on Wi-Fi or wired, and the Firewalla’s WAN/LAN ports when it can reach them over SSH — finds the slowest known link, then runs a bounded parallel-stream download and interprets the gap. When a single stream stalls and parallel streams fly, it tells you the single number was the artifact. When you’re at the link ceiling, it says so and names the hop to fix.
| Flag | Behavior |
|---|---|
--streams N | Parallel download streams (default 8). Raise it on a very fast line or to escape a single-stream artifact |
--no-test | Ceiling audit only — read every hop’s link speed and interpret it, skip the live download entirely |
--json | Emit the full report as JSON (hops, bottleneck, verdict, advice) for the menu bar or a script |
What it exposes
Section titled “What it exposes”The interpreter encodes the field rules so the lie is visible:
| Artifact | What the doctor says |
|---|---|
| Single-stream cap | A single connection stalls near 1-2 Gbps; the multi-stream figure is the real one — trust it |
| Wi-Fi ceiling | Wi-Fi caps you at ~1-2 Gbps regardless of the line; go wired and re-test |
| Slowest port | A 1G switch or a 2.5G NIC anywhere in the chain is your ceiling — no line upgrade moves it |
| NAT topology | Single- vs double-NAT changes throughput by zero; do not chase NAT to go faster |
| ISP hub test | The hub’s built-in test is single-stream on a weak CPU and under-reports; measure from your own machine |
| PPPoE | CPU-bound on most routers, caps around ~3-3.5 Gbps; the band is named when the WAN uses it |
sanctum keys backup <path>
Section titled “sanctum keys backup <path>”Export an encrypted bundle of your Sanctum Keychain credentials — OpenRouter, Anthropic, Gemini, Firewalla-bridge, R2, B2. The single most important command in the CLI: sanctum uninstall revokes those entries and a dead disk takes them with it. The bundle re-keys a fresh Mac in seconds instead of by hand.
sanctum keys backup ~/Documents/sanctum-keys-2026-06-09.tar.gz.encIt reads each sanctum/* Keychain entry into a mode-600 file, prompts for a passphrase (twice, minimum 12 characters — the CLI neither generates nor stores it), then tar.gzs and openssl enc -aes-256-cbc -pbkdf2 -salts the lot to the .enc path you gave. No copy anywhere, no cloud call. Restore with sanctum keys restore <path>.
Options
Section titled “Options”Global options; everything else routes to the command.
| Option | Behavior |
|---|---|
--version | Print the CLI version and exit 0 |
--traceback | Print a full traceback on an uncaught exception (otherwise you get the curt line) |
-h, --help | Print the usage banner and exit 0 |
sanctum --version # → sanctum 0.10.2sanctum --help # → command rosterExit Codes
Section titled “Exit Codes”| Code | Meaning |
|---|---|
0 | Success (--help and --version included) |
1 | Command-level failure (a probe failed, a prereq is missing, a file wasn’t found) |
2 | Usage error (unknown command, missing required argument) |
Quick Reference
Section titled “Quick Reference”| Command | Purpose |
|---|---|
sanctum status | Host vital signs — one line with --oneline |
sanctum doctor | Are the LaunchAgents, providers, and backups healthy? |
sanctum self-test | Run the twelve canonical probes |
sanctum update | brew upgrade + self-test as the gate |
sanctum uninstall | Remove operational artifacts (preserve data by default) |
sanctum uninstall --purge | Also remove the ~/.sanctum/ data dirs |
sanctum logs <service> | Tail a known log — --list to see them all |
sanctum devices | Read-only haushold device inventory |
sanctum schedule | Read-only curfew view |
sanctum net check | Read-only NAT-topology + ISP audit |
sanctum net optimize | Guided, reversible double-NAT → single-NAT cutover |
sanctum net speedtest | Honest multi-stream throughput doctor — names the real ceiling |
sanctum keys backup <path> | Encrypt your Keychain credentials to a portable bundle |
sanctum chat / code / vision | Talk to the router-chosen / Claude / Gemini model |
sanctum onboard | One-shot first-run: recipe → cloud → first backup → canary |