Skip to content

`colibri doctor` — self-diagnosis & self-upgrade

index

Status: Shipped (v0.12.0+). 10 checks, two auto-fixable targets, client-side colibri upgrade. Cross-platform (Linux + FreeBSD, one #[cfg] for service restart).

status is a passive snapshot (counts). doctor is a battery of active checks — each verifies one thing that has to be true for the control plane to work, and reports PASS/WARN/FAIL. It’s the task-dispatch-flow “why won’t my task run?” checklist, executable. Scope is concrete — check only what we actually have, never claim a check we can’t back with a data source.

struct CheckResult {
check: String, // e.g. "database", "registration_linkage"
status: String, // "pass" | "warn" | "fail"
detail: String, // human-readable one-liner
hint: Option<String>, // optional operator-facing tip (→ displayed)
fixable: bool, // can `colibri doctor --fix` act on it?
}

hint is always displayed as a → tip in table output. fixable is the hinge between diagnosis and action: only fixable: true checks are acted on by --fix. Today two checks are fixable: binary_vs_git_versioncolibri upgrade, registration_linkagecolibri agents prune.

CheckWhat it verifiesfixable
databaseStore opens and queries cleanlyno
providersAt least one cloud provider key setno
agentsAt least one live agent handleno
dispatch_readinessAgents are in RPC mode (can receive tasks)no
registration_linkageStore agents map to live handles (stale if not)yescolibri agents prune
model_selectionPhase 3 model selection enabled/disabledno
local_evalollama available for local-llm evalno
disk_freedf -k on data_dir — <100MiB FAIL, <1GiB WARNno
binary_vs_git_versionBinary version matches git tag at build timeyescolibri upgrade
doas_nopasswd (FreeBSD) / sudo_nopasswd (Linux)Passwordless escalation configured for daemon controlno
git_behindClient-side: commits behind origin/mainno (shown by client, not daemon)

The daemon emits 10 checks. git_behind is client-side only — the client runs git rev-list --count HEAD..origin/main after fetching. The escalation check (doas_nopasswd on FreeBSD, sudo_nopasswd on Linux) was added after real-world testing showed colibri upgrade failing mid-flight when the escalation tool required a password.

  • DNS resolution — daemon has no DNS config; would need a /etc/resolv.conf or host probe.
  • TLS/ACME cert expiry — no cert knowledge in the daemon; an nginx concern.
  • PostgreSQL health — not in the colibri installer scope.
  • Mother reachablessh colibri@mother requires key setup that isn’t guaranteed on every node.

The doctor never prints a check it can’t back. Adding one of these means adding its data source first.

colibri upgrade — client-side self-rebuild

Section titled “colibri upgrade — client-side self-rebuild”

The upgrade flow is entirely client-side. The daemon never touches its own binary.

colibri upgrade --check # just the git-behind count, no build
colibri upgrade --yes # git pull → cargo build --release → stop → install → start
colibri upgrade # interactive (prompts before build)

Platform restart: service colibri_daemon restart (FreeBSD rc.d) vs systemctl restart colibri-daemon (Linux) — one #[cfg] block.

Binary install uses install(1) (not cp) to avoid ETXTBSY (“Text file busy”) when overwriting the running client binary on FreeBSD.

Passwordless escalation requirement (doas on FreeBSD, sudo on Linux)

Section titled “Passwordless escalation requirement (doas on FreeBSD, sudo on Linux)”

colibri upgrade needs passwordless escalation for the daemon stop/install/start cycle. The doas_nopasswd (FreeBSD) / sudo_nopasswd (Linux) check detects this.

The check (and the upgrade pre-flight) probe the scoped service-status commanddoas -n service colibri_daemon status (FreeBSD) / sudo -n systemctl status colibri-daemon (Linux) — not esc -n true. The installer writes command-limited rules, so a blanket true probe would fail even on a correctly-configured host.

Preferred provisioning — the clawdie installer writes the scoped rules for you. Run it with the operator account that should control upgrades:

Terminal window
clawdie apply --operator-user YOUR_ACCOUNT --yes

FreeBSD (rc.d + doas) — the installer appends permit nopass rules to /usr/local/etc/doas.conf for the operator account:

/usr/local/etc/doas.conf
permit nopass YOUR_ACCOUNT cmd service
permit nopass YOUR_ACCOUNT cmd install

Linux (systemd + sudo) — the installer writes a NOPASSWD drop-in for the operator account:

/etc/sudoers.d/colibri
YOUR_ACCOUNT ALL=(root) NOPASSWD: /usr/bin/systemctl * colibri-daemon
YOUR_ACCOUNT ALL=(root) NOPASSWD: /usr/bin/install *

The rules are scoped by command, not blanket — doas matches by command name (service covers any service invocation), while sudoers uses arg wildcards.

colibri doctor --fix — two auto-fixable targets

Section titled “colibri doctor --fix — two auto-fixable targets”
colibri doctor --fix

Runs all checks, then acts on fixable: true ones:

  1. binary_vs_git_versioncolibri upgrade (pull + build + restart). Forces rebuild even when git is at origin/main — the binary can be stale from a pre-tag build.
  2. registration_linkagecolibri agents prune — removes store agents that have no live daemon handle. Stale agents accumulate on every daemon restart because agent IDs are ephemeral.

After fixes, re-runs doctor to show the new state.

colibri doctor # run all checks, print table with → hints
colibri doctor --json # machine-readable (MCP / dashboard)
colibri doctor --fix # run checks + act on fixable ones
colibri upgrade # interactive self-rebuild
colibri upgrade --check # git-behind count only
colibri upgrade --yes # non-interactive self-rebuild
PieceWherePlatform
Checks enginecrates/colibri-daemon/src/doctor.rscross-platform
Client displaycolibri-client (colibri doctor)cross-platform
Self-upgradecolibri-client (colibri upgrade)one #[cfg] block
Stale-agent prunecrates/colibri-daemon/src/daemon.rscross-platform

The daemon gets exactly one command: DoctorVec<CheckResult>. The client formats it and runs fixes. Upgrade and prune are separate — they compose through --fix, not through a shared daemon API.

Each node runs colibri doctor locally. Mother queries all nodes with ssh <node> colibri doctor --json — the SSH keychain + MCP-over-SSH already carry arbitrary socket commands.