sanctum-cli config (the cli block)

Open ~/.sanctum/instance.yaml expecting the usual config sprawl and the file is almost rude about how little it asks of you: two required keys and a lot of white space. That one file (instance.yaml) describes the entire constellation — networking, node topology, every service — but the sanctum CLI only ever reads two slices of it. The loader pulls out the instance: and cli: keys, validates those, and leaves every other tool to own the rest without complaint. This page is the second slice: cli:, the block the CLI itself reads.
The block is optional, which is the point. A fresh install runs entirely on defaults; you add a cli: block only when you want to steer routing, pick a provider, or point backups somewhere. sanctum onboard scaffolds a minimal instance.yaml (just instance: { name, slug }) when none exists, then walks its numbered steps — it never opens an editor. And when a key is wrong, sanctum config validate names the offender out loud, before anything downstream gets the chance to fail more interestingly. The whole design assumes you will get it wrong at least once; it just refuses to be quiet about it.
Minimal Example
Section titled “Minimal Example”The smallest input the CLI accepts is just the instance: metadata — no cli: block at all, every setting on its default:
instance: name: "Manoir Sanctum" slug: "manoir-sanctum" timezone: "America/Montreal"Only instance.name and instance.slug are required; timezone is optional. Everything else in this reference is a key you add under cli: to override a default. Skip the cli: block entirely and you get Claude routing, telemetry on, and the built-in family and operator backup recipes — which, after watching one long cloud outage in real time, is a defensible place to start.
instance (metadata the CLI reads)
Section titled “instance (metadata the CLI reads)”The CLI pulls three fields out of the instance: block; the rest of that block (users, network, services, nodes) belongs to other tools and the CLI ignores it without complaint. slug is the URL-safe identifier; name shows up in sanctum status and alerts.
| Key | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable instance name. Surfaced in sanctum status and alert subjects. |
slug | string | Yes | URL-safe identifier. Lowercase, no spaces — used in paths and hostnames. |
timezone | string | No | IANA zone, e.g. America/Montreal. Used for schedule and report timestamps. |
instance: name: "Manoir Sanctum" slug: "manoir-sanctum" timezone: "America/Montreal"cli.default_provider and cli.routing
Section titled “cli.default_provider and cli.routing”Which model seat answers by default, and the rules that override it. default_provider is the floor; routing.rules are the ordered exceptions (first match wins); routing.fallback catches what no rule matched or what is unreachable.
| Key | Type | Default | Description |
|---|---|---|---|
default_provider | claude | gemini | mlx_local | claude | Provider used when no routing rule matches. |
routing.rules | list | [] | Ordered when/then rules. First match wins. |
routing.fallback | claude | gemini | mlx_local | claude | Provider used if no rule matched or the primary is down. |
cli: default_provider: claude routing: rules: - when: { offline: true } then: mlx_local fallback: claudeA then: value names a seat — claude, gemini, or mlx_local — not a specific model. Which model sits behind each seat lives in the provider block below, so you can swap the model without rewriting every rule. It is the same seat vocabulary the Smart Router speaks one layer up.
cli.providers
Section titled “cli.providers”The three model backends, each with its own endpoint, model, and — where it talks to a paid API — a Keychain pointer. Secrets never live in this file; only a {service, account} tuple that the CLI resolves at runtime.
| Provider | Key | Default | Description |
|---|---|---|---|
claude | via | proxy | proxy shells through the local claude CLI (bills the Max subscription); direct uses the Anthropic SDK (bills the API key). |
claude | endpoint | http://127.0.0.1:2001 | Local OpenAI-compatible proxy address for via: proxy. |
claude | keychain | {service: anthropic-api-key, account: sanctum} | Keychain entry for via: direct. |
gemini | model | gemini-2.5-pro | Google model; key at {service: google-ai-api-key, account: sanctum}. |
mlx_local | endpoint | http://127.0.0.1:8900 | Local cathedral. always_available: true — no key, never the bottleneck. |
cli: providers: claude: via: proxy keychain: { service: "anthropic-api-key", account: "sanctum" } mlx_local: endpoint: "http://127.0.0.1:8900" model: "council-secure"The canonical Keychain lookup carries both halves of the tuple — account and service. The CLI shells exactly this (sanctum_cli/keychain.py):
security find-generic-password -a sanctum -s anthropic-api-key -wcli.telemetry
Section titled “cli.telemetry”A local, append-only CLI usage log. On by default, prompts redacted by default, never leaves the machine.
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Write a JSONL line per invocation. |
path | string | ~/.sanctum/telemetry/cli.jsonl | Where the log lands. |
redact_prompts | bool | true | Strip prompt text before writing. |
aggregate_window_days | int | 7 | Rolling window for status aggregates (1–365). |
cli.cloud_backup
Section titled “cli.cloud_backup”Restic/borg/kopia repo pointers for sanctum backup: a primary repo, an optional secondary, and a retention policy. This is the one cli: sub-block configured on this machine; everything else runs on defaults.
| Key | Type | Default | Description |
|---|---|---|---|
primary.kind | restic | borg | kopia | restic | Backup engine. |
primary.repo | string | — | Repo path or rclone remote. |
primary.keychain | {service, account} | — | Keychain entry holding the repo password. |
retention.keep_daily | int | 7 | Daily snapshots to keep. |
cli: cloud_backup: primary: kind: restic repo: "/Volumes/T9/sanctum-restic" keychain: { service: "sanctum-backup-key", account: "sanctum-backup" } secondary: kind: restic repo: "rclone:gdrive-sanctum:sanctum-restic" keychain: { service: "sanctum-backup-key", account: "sanctum-backup" } retention: { keep_daily: 7, keep_weekly: 4, keep_monthly: 12 }cli.recipes and cli.ui
Section titled “cli.recipes and cli.ui”Recipes are named bundles of backup sources/excludes for an audience (family, operator); ui is cosmetic. Both ship sane built-ins, so most operators never touch either.
| Key | Type | Default | Description |
|---|---|---|---|
recipes | map | built-ins | Named source/exclude bundles. Override family/operator or add your own. |
default_recipe | string | unset | Recipe used when sanctum backup is called bare. |
ui.color | auto | always | never | auto | Color output policy. |
ui.json_default | bool | false | Emit JSON without passing --json. |
cli.modules
Section titled “cli.modules”A per-module enable/disable map, keyed by module name. The only field today is enabled (YAGNI — the rest is intentionally absent). Driven by the sanctum module list / status / install / uninstall command group.
| Key | Type | Default | Description |
|---|---|---|---|
modules.<name>.enabled | bool | true | Whether the named module is active. |
cli: modules: backup: enabled: falseEnvironment Variable Overrides
Section titled “Environment Variable Overrides”The env vars the CLI actually honors at runtime, grepped straight from sanctum_cli/. Useful for tests, sandboxes, and one-off runs. None are needed for normal operation.
| Variable | Overrides | Notes |
|---|---|---|
SANCTUM_INSTANCE_FILE | Path to instance.yaml | Default: ~/.sanctum/instance.yaml |
SANCTUM_DEVICES_FILE | Devices file path | Read by sanctum devices |
SANCTUM_MODULES_DIR | Installed-modules directory | Where sanctum module looks |
SANCTUM_PROVIDER | cli.default_provider | Force a provider for one invocation |
SANCTUM_PROVIDERS_CLAUDE_ENDPOINT | cli.providers.claude.endpoint | Direct-SDK endpoint override |
SANCTUM_PROVIDERS_CLAUDE_PROXY_ENDPOINT | Claude proxy endpoint | The via: proxy address |
SANCTUM_BRIDGE_URL | Firewalla bridge URL | Local bridge address |
SANCTUM_PREFIX | Install prefix | Where the CLI looks for its own files |
SANCTUM_SPLASH | Startup splash toggle | Cosmetic |
That is the whole cli: block: five keys on one ring, each earning its place, and not a single secret riding along on any of them — the tokens stay in Keychain, exactly as the secrets trifecta demands. When something downstream misbehaves, this file is where you start, because sanctum config validate reads it first and will tell you which key is lying. The rest of the constellation waits next door in instance.yaml; it just no longer has an opinion about how the CLI is run.