Skip to content

Diagnose with firma doctor

firma doctor prints a structured diagnostic report: what’s installed, what’s reachable, what’s configured. It is read-only — no state is mutated — so it is safe to run against a live stack at any time.

  • After a fresh install — confirm the binary is on PATH and the sandbox backends you care about are present.
  • Before opening a bug report — attach firma doctor --json to the issue for a reproducible baseline.
  • In CI — gate on exit code 0 to catch configuration drift before tests run.
  • Any time firma sidecar status looks wrong — doctor tells you why.
Terminal window
firma doctor # pretty output, all checks
firma doctor --json | jq . # machine-readable, pipe-friendly
firma doctor --config /etc/firma/firma.toml # use an explicit unified config
firma doctor --state-dir /run/user/1000/firma # override runtime state dir
firma doctor --timeout-ms 1500 # slower network probe (ms)
FlagEnvDefaultDescription
--configFIRMA_STACK_CONFIGdiscoveredUnified firma.toml. When unset, auto-discovery uses $FIRMA_CONFIG or walk-up to <dir>/.firma/firma.toml; selected files must load successfully.
--state-dirFIRMA_STATE_DIRresolvedOverride the runtime state directory.
--jsonoffEmit a single JSON object instead of pretty text.
--timeout-ms500Per-probe network timeout (TCP / UDS connect) in milliseconds.
StatusMeaning
OKCheck passed.
WARNNot applicable on this host, or not yet configured. No action needed.
FAILConfigured and broken. Operator action required.

A fresh install with no firma.toml is expected to produce a mix of OK and WARN — never FAIL. FAIL always points to something the operator already declared that is now misbehaving.

firma doctor
=============
[OK] firma binary /usr/local/bin/firma (v0.1.0)
[OK] sandbox bwrap bubblewrap 0.8.0 available
[WARN] sandbox vz not used on linux
[WARN] sandbox wsl2 not used on native Linux (runtime selects bwrap)
[OK] sandbox firecracker Firecracker v1.7.0 available
[OK] sidecar reachable 2 live per-run instances (firma run)
[OK] authority reachable 2 live per-run instances (firma run)
[OK] config parsed ./.firma/firma.toml
[OK] capability seed not present (optional; capabilities disabled by default)
[OK] state dir /run/user/1000/firma: mode 0700
[OK] data dir ~/.local/share/firma: not present (created on first use)

Categories are emitted in a fixed order; columns are padded so a diff between two runs only shows lines that actually changed.

Verdicts match what firma run actually does

Section titled “Verdicts match what firma run actually does”

Doctor does not rely on a static OS → backend table, and does not probe only the configured daemon. Its verdicts mirror the runtime:

  • Sandbox backends use the same selection and preflight logic as firma run. On WSL, sandbox bwrap is not OK (the runtime refuses bubblewrap there — unprivileged user namespaces are unavailable) and sandbox wsl2 is OK (the backend the runtime auto-selects), instead of the misleading “not supported on linux”. On a hardened native-Linux kernel where unprivileged user namespaces are disabled by sysctl, sandbox bwrap is FAIL — matching the error firma run would raise.
  • Live per-run instances are cross-checked against the same runtime markers firma sidecar status reads. While an agent runs under firma run, sidecar reachable and authority reachable report the live per-run instances as OK even though no long-lived daemon is listening.
  • No long-lived daemon is not a failure in a firma run-only workflow. When nothing is reachable and no per-run instance is live, these checks are a WARN (“no long-lived daemon reachable (normal if you only use firma run)”), never a FAIL.
  • Optional, created-on-demand paths (capability seed, data dir) report OK when absent — they are expected to be missing on a healthy install.
{
"checks": [
{
"category": "firma binary",
"status": "ok",
"reason": "/usr/local/bin/firma (v0.1.0)",
"detail": { "path": "/usr/local/bin/firma", "version": "0.1.0" }
},
{
"category": "authority reachable",
"status": "fail",
"reason": "127.0.0.1:50051: connection refused",
"detail": { "address": "127.0.0.1:50051" }
}
],
"worst": "fail",
"exit_code": 1
}

worst is ok | warn | fail. exit_code mirrors the OS-level exit code. The detail map is omitted when empty; keys are category-specific.

CodeMeaning
0Every check is OK or WARN.
1At least one check is FAIL.
2Internal error (render failure, runtime failure). Not a check failure.

CI pattern: firma doctor --json > report.json && jq -e '.exit_code == 0' report.json