Skip to main content

conduit doctor

conduit doctor runs a set of offline, non-destructive checks against your Conduit configuration and environment and answers one question: would conduit run succeed here? It factors out the exact primitives the runtime uses at startup — config validation, database open and ping, address binding, plugin directory scan — and runs each as an isolated probe. It never boots a Runtime and leaves no files behind.

This is distinct from the running server's /healthz and /readyz probes, which answer "is the running engine serving?". doctor is a pre-flight; the probes are for a process that is already up.

conduit doctor
Config
✓ config.resolve conduit.yaml found at ./conduit.yaml
✓ config.validate configuration is valid
Store
✗ store.reachable cannot open badger store at ./conduit.db
└ db.badger.path
→ Check the directory exists and is writable, or set db.badger.path.
Network
✗ network.grpc address :8084 is already in use
└ api.grpc.address
→ Stop the process holding it, or set api.grpc.address to a free port.
Plugins
⚠ plugins.connectors_dir ./connectors not found — built-ins still available
✓ plugins.builtin built-in connectors and processors available

Summary: 4 passed · 1 warnings · 2 failed
✗ items failed. Fix them, then re-run `conduit doctor`.

doctor accepts the same config-affecting flags as conduit run (--db.badger.path, --api.grpc.address, --connectors.path, and so on), so it checks exactly the configuration run would use. Results are grouped by category — Config, Store, Network, Plugins, Engine — and each carries the failing config path () and a suggested fix (). Glyphs fall back to [OK]/[!]/[X] when the output is not a TTY or --no-color is set.

What it checks

CheckQuestion it answersVerdict on trouble
config.resolveWas a config file found and parsed?warn if defaults were used
config.validateIs the resolved configuration valid?fail on a bad field (exit 2)
store.reachableCan the configured database be opened and pinged?warn for in-memory; fail if it can't open (exit 3)
network.grpcIs the gRPC API address free to bind?fail on EADDRINUSE (exit 3)
network.httpIs the HTTP API address free to bind?fail on EADDRINUSE (exit 3)
plugins.connectors_dirIs the standalone connectors directory readable?warn if missing (built-ins still work)
plugins.processors_dirIs the standalone processors directory readable?warn if missing
plugins.builtinIs the built-in plugin registry populated?fail if empty
engine.reachableIs a running Conduit API reachable?warn by default; fail with --require-server
plugins.standalone_compatDo standalone plugin binaries dispense correctly?--deep only; runs each in an isolated subprocess

A missing plugin directory is deliberately a warning, not a failure: built-in connectors and processors are always available, so a CI machine without a ./connectors directory is not a broken environment. engine.reachable is a warning by default because doctor is an offline preflight — you usually run it before there is a server to reach.

Every check is wrapped so that a check which errors, panics, or hangs becomes a fail (with an internal.error code) rather than crashing or blocking the run.

Flags

FlagEffect
--jsonEmit the machine-readable result envelope instead of the rendered report.
--check <name>Run only the named check. Repeatable. See the check names in the table above (or conduit doctor --help).
--deepAlso run plugins.standalone_compat, which dispenses standalone connector plugin binaries in an isolated subprocess.
--require-serverFail (instead of warn) if the Conduit API server isn't reachable.
-q, --quietSuppress passing checks; print only warnings, failures, and the summary.
--no-colorDisable colored output.

Plus the config-affecting flags shared with conduit run (--db.badger.path, --api.grpc.address, --connectors.path, …).

Passing an unknown --check name fails the command and lists the valid names. Selecting --check plugins.standalone_compat without --deep is likewise rejected — that check only runs under --deep.

Exit codes

doctor uses the standard deterministic exit codes. Warnings never fail the process; only a does, and the exit code is the worst failing check's classification:

Exit codeMeaning
0Every check passed (warnings are allowed).
2A check found invalid configuration.
3A required dependency — the database, a network address, or (with --require-server) the API server — is unreachable.

Precedence is environment (3) over validation (2) over runtime (1), so a run with both a bad config field and a port already in use exits 3.

JSON output

--json emits the shared result envelope. The result object carries the full list of check results; the summary counts them:

{
"command": "doctor",
"ok": false,
"summary": { "total": 7, "passed": 4, "warned": 1, "failed": 2 },
"result": {
"checks": [
{
"name": "store.reachable",
"status": "fail",
"message": "cannot open badger store at ./conduit.db",
"suggestion": "Check the directory exists and is writable, or set db.badger.path.",
"code": "common.unavailable",
"configPath": "db.badger.path",
"category": "store"
}
]
},
"error": null
}

Each check result carries a status of pass, warn, or fail, and failures carry a stable code, the failing configPath, and a suggestion — the same fields the structured error model uses everywhere. This is the same check set the MCP doctor tool wraps, so an agent and the CLI see identical results.

Using it in scripts and CI

Because the exit codes are stable, doctor slots into a startup gate or a container entrypoint:

if ! conduit doctor --require-server=false --quiet; then
echo "environment not ready for conduit run" >&2
exit 1
fi
conduit run

Or branch on the failure kind, mirroring exit-code scripting:

conduit doctor --json > doctor.json
case $? in
0) echo "ready" ;;
2) echo "fix your configuration" ;;
3) echo "a dependency is unreachable" ;;
esac

scarf pixel conduit-site-docs-using-other-features