CLI reference¶
The kneo-dash console script (installed by pip install kneo-dash) has three
subcommands: serve (the default), recover — a safety-critical break-glass flow for
recovering an instance after a database restore — and prune — operator-safe retention
for the growth tables (0.8.0). This page documents every subcommand, flag,
and exit code; the recovery model itself is ADR-012 §7
and the operator runbook is Backup & recovery.
kneo-dash [serve] # run the BFF (default)
kneo-dash recover [--reason TEXT] # ENTER recovery (arm the gate)
kneo-dash recover --status # is this instance in recovery? (deployment gate)
kneo-dash recover --reconcile --access-map FILE (--connections FILE | --keep-connections) [--reason TEXT]
kneo-dash prune --older-than-days N --export-dir DIR --by OPERATOR [--table T] [--vacuum] [--dry-run]
serve (default)¶
kneo-dash with no subcommand (or kneo-dash serve) starts the BFF. It is a convenience
launcher for local/dev use — it binds 127.0.0.1:8090 with autoreload, so it is not
how you run a real deployment.
In production, run uvicorn directly (this is what the shipped container does):
The container's CMD is exactly that; put it behind the TLS-terminating reverse proxy from
the Deployment guide. See also the post-deploy checklist.
recover — restore recovery (break-glass)¶
When the instance detects a database restore (an older backup landed, per the
restore sentinel), it arms
recovery: get_client fails closed and readyz returns 503 until an operator
reconciles it. recover is how you inspect and clear that state. It is out-of-band —
run it against the same DB (KNEO_DASH_DB_URL), not through the running server.
recover (no flags) — enter recovery¶
Manually arm the gate (e.g. before a maintenance restore). --reason TEXT sets the marker
reason (default post-restore recovery). Normally you don't need this — a detected restore
arms it automatically; SQLite is the certified topology (on Postgres, which has no local
sidecar anchor, arming is manual — see Backup & recovery).
recover --status — the deployment gate¶
Reports whether the instance is in recovery, via the exit code — designed to gate a deploy/orchestrator step:
| Exit | Meaning |
|---|---|
0 |
not in recovery — safe to serve (not in recovery — safe to serve) |
3 |
in recovery — do not serve; reconcile first (message to stderr) |
recover --reconcile — the only exit from recovery¶
Clears recovery after you supply the post-restore decisions. It is the single supported
way out (there is no --clear):
--access-map FILE— required. A JSON{role: [capabilities]}Access map to apply (validated, incl. the no-lockout guard — admin must retainsettings.write).- exactly one connection decision (required):
--connections FILE— a JSON{env: {profile: …}}that replaces the restored connections, or--keep-connections— explicitly keep the restored connections as-is.--reason TEXT— optional marker reason.
Failure is safe: if reconcile fails (bad file, invalid map, …) it exits 1 and
recovery is NOT cleared — the instance stays fenced until a successful reconcile. Requiring
an explicit connection decision prevents silently serving a restored instance against the
wrong (possibly stale/foreign) platform credentials.
prune — operator-safe retention (0.8.0)¶
Prunes the two growth tables — the audit log and launch history — with export-before-delete and a self-audit record (design: state-store design §Prune & export):
kneo-dash prune --older-than-days 90 --export-dir /backups/prune --by ops@example.com
# scope / preview / reclaim:
# --table audit_log|launches|all (default all)
# --dry-run report only; changes nothing
# --vacuum SQLite: rebuild the file so space returns to the OS
- Export first, always: candidates are written to
DIR/<table>-pruned-<utc>.jsonlplus a.sha256sidecar; the file's first line is a{"_schema": "kneo-dash-prune-export/1", …}header recording the table, store schema version, cutoff, and row count (explicitly versioned). Every target table is exported before any row of any table is deleted, so an export failure aborts with nothing deleted. Deletes target exactly the exported id set — rows appended mid-prune are untouchable. - Self-auditing: a
store.pruneaudit row records the--byoperator, cutoff, and per-table{rows, export filename, sha256}— so the log documents its own pruning and each row can be matched to its exact export artifact. - A completion receipt lands on disk first: after the deletes and before the
audit append,
DIR/prune-receipt-<utc>.jsonrecords the full per-table outcome — so even if the audit append itself fails, the deletion is never unrepresented. - If the delete or audit phase fails mid-way (deletes run as batched transactions):
the remaining old rows simply stay put — nothing unexported is ever deleted — a
best-effort
store.prune.partialaudit row records the progress, and re-running the same prune converges (the exports, and the receipt if deletes finished, are already on disk). - Back up first (a real precondition, not advice), and watch the
kneo_dash_store_rows{table=…}gauges to decide when — see Observability for the watch levels. - Postgres (best-effort lane):
--vacuumis a no-op (autovacuum owns reclamation).
Exit codes (summary)¶
| Command | 0 |
1 |
3 |
|---|---|---|---|
recover --status |
not in recovery | — | in recovery (gate) |
recover --reconcile |
reconciled + cleared | reconcile failed (still fenced) | — |
Related¶
- Backup & recovery — the full restore → reconcile runbook.
- ADR-012 §7 — the recovery/restore-detection design.
- Deployment — running the BFF in production (uvicorn + proxy).
- State store — the recovery marker + restore sentinel.