Skip to main content

crewship doctor

Runs a battery of checks against the local Crewship install and prints one row per check with a status. Designed for the “is everything OK before I file an issue?” workflow.

Exit codes

WARN does not fail the command — you can wire crewship doctor into a healthcheck without false alarms on transient external state (e.g. Sentry endpoint briefly unreachable). FAIL means a core requirement for starting Crewship is missing or broken; treat the non-zero exit as a hard gate.

Check categories

Server-dependent checks (server reachable, episodic recall mode, cli server scheme) resolve the same effective server other commands dial: --server flag → active profile (--profile / CREWSHIP_PROFILE) → CREWSHIP_SERVER env → config. An active profile that has no server: entry fails closed — the scheme check reports INFO instead of silently diagnosing a different host than your API calls use.

Container runtime

Detects which Docker-compatible runtime is available — Docker, Podman, Colima, OrbStack, Apple Containers, or Rancher Desktop. Auto-probes each candidate socket; the first reachable one wins.

Port binding

Confirms the HTTP port (default 8080 or CREWSHIP_PORT) is free.
  • PASS — port is bindable.
  • FAIL — port in use. lsof -i :8080 to find the squatter, or change CREWSHIP_PORT.

Database file permissions

Stats ~/.crewship/ directory and the SQLite DB file. Expects:
  • Parent directory: 0700
  • DB file: 0600
  • WAL + SHM sidecars (if present): 0600
Drift here usually means a backup was restored via tar without preserving mode bits. Fix:

NEXTAUTH_SECRET

Surfaces where the JWT signing secret lives (env var vs <dataDir>/secrets.env) and validates the value is at least 32 characters. As of PR #446 the secret is auto-bootstrapped on first start, so a missing value is no longer a failure — doctor reports INFO and the next crewship start generates it.

Episodic recall mode

Reads the episodic field from the running server’s /healthz. Reports whether episodic memory recall runs with a vector embedder or degraded to keyword/FTS only.
  • PASS — vector + sparse recall — an embedder is configured (KEEPER_OLLAMA_URL); the boot-time indexer sweeper is embedding journal entries and recall serves vector + BM25 results.
  • FAIL — vector-degraded — an embedder is configured but its calls are failing, so the index is not growing and recall is silently BM25-only. The server includes the underlying error as episodic_error and this check prints it. The usual cause is an Ollama host that is reachable but not serving the model — ollama pull nomic-embed-text on that host. This is a FAIL rather than a WARN because it is worse than sparse-only: that one is a deliberate choice that still serves keyword recall, whereas this looks configured and delivers nothing.
  • WARN — sparse-only — no embedder configured. Recall still works on keywords, but vector similarity is off. Set KEEPER_OLLAMA_URL to an Ollama host serving nomic-embed-text.
  • INFO — server not reachable / older server — the daemon is down (the server reachable check already FAILs for that) or predates the episodic health field.

Legacy crew resources

Calls the authenticated GET /api/v1/admin/legacy-resources endpoint to detect orphaned pre-C1 (slug-only) crew docker resources that survive crewship seed --nuke and make every agent in the affected crew fail to start — surfaced to users only as a generic “failed to start agent container”. (Detection runs on this admin endpoint rather than the unauthenticated /healthz path, so a slow docker daemon can’t stall health probes.)
  • PASS — clean — no orphaned legacy volumes/containers for any current crew slug.
  • WARN — present — at least one orphaned pre-C1 resource exists. Agents in the affected crew(s) will fail to start. Run crewship admin prune-legacy to remove them.
  • INFO — not logged in / unreachable / non-docker server — the check needs an authenticated session (crewship login); or the daemon is down (the server reachable check covers that) or the container provider isn’t docker.

Telemetry status

Reads app_settings.telemetry_opt_in from the local DB. Reports:
  • PASS — ENABLED + DSN — telemetry is on and a DSN is wired in. Shows the endpoint host (vendor default vs CREWSHIP_SENTRY_DSN override).
  • PASS — DISABLED — operator opted out via crewship telemetry off.
  • WARN — ENABLED but no DSN — consent recorded but no DSN available. Local dev builds without ldflag injection; not an error, just informational.
  • WARN — not configured — fresh DB, never asked. Will default to ENABLED on the next crewship start (v0.1 beta behaviour).
See Telemetry for opt-out and routing-override recipes.

DSN reachability

Only runs when telemetry is enabled AND a DSN is set. Best-effort TCP connect (5s timeout) to the resolved endpoint at port 443.
  • PASS — endpoint reachable; events will ship.
  • WARN — endpoint unreachable. Crashes won’t ship until network heals. Not a Crewship health signal — could be local firewall, DNS issue, or Sentry outage. crewship doctor does not fail on this; you’d be silently angry at the wrong layer.

Update available

Calls the GitHub Releases API for the project (cached 24h locally).
  • PASS — running latest stable, or running a newer pre-release.
  • WARN — newer stable available; output shows current → latest with install hint (brew upgrade crewship or docker pull).
  • INFO — running a dev build, version check skipped.
Suppress with CREWSHIP_SKIP_UPDATE_CHECK=1.

Example output

PR #441 added a version + OS/arch header banner and a “Next steps” footer that points the operator at the three commands that actually move them forward (or at the troubleshooting page on FAIL). Presentation-only — no check behaviour changes.

Output formats

  • --no-color — disable ANSI colors. Auto-detected when stdout is not a TTY (so log-collection scripts get plain text without any flag).
  • Status codes (PASS/WARN/FAIL/INFO) are always in left-padded brackets and parseable with awk '{print $1}'.

Auto-repair (--fix)

--fix opts into safe, narrowly-scoped repair side-effects during the check run. Currently scoped to:
  • Database directory missing — creates $CREWSHIP_DATA_DIR (or ~/.crewship) with 0700 perms instead of failing the check. The detail column then reads (created via --fix) so you can see what changed.
Anything destructive (file overwrites, mode-bit flips on existing files, DB schema repairs) is intentionally out of scope — --fix is for first-run onboarding, not running surgery on a populated install.

When to run

  • Before opening a GitHub issue — attach crewship doctor --no-color output. Saves a back-and-forth diagnostic round.
  • After upgrading the binary — pre-migration snapshot has run by this point; doctor confirms the new binary is happy with the existing DB.
  • In CI smoke tests — the .github/workflows/smoke-test.yml workflow runs crewship doctor against the freshly-released binary on each release tag to catch broken binaries before they reach users.