Skip to content

koryph doctor

koryph doctor checks the health of the koryph installation. Without --project it runs global checks against ~/.koryph. With --project <id> it runs project-scoped checks against the named project.

Usage

koryph doctor [--json] [--fix]
koryph doctor --project <project-id> [--json]
Flag Description
--project <id> Run project-scoped checks for the named registered project
--json Emit the report as a JSON object instead of a text table
--fix Remove zombie slot lease files and stale demand heartbeats (global mode)

Exit codes

Code Meaning
0 All checks passed
1 One or more warnings
2 One or more errors

Checks

layout

Verifies that ~/.koryph exists with the required subdirectory skeleton (registry.d/, quota/, slots/). A missing home directory or subdirectory is an error — run koryph init to repair.

binaries

Checks that git, claude, and bd are on PATH. Missing binaries are warnings (the CLI can still run for some commands).

registry

Parses every *.json file in registry.d/. A file that is not valid JSON is an error.

governor

Validates governor.json when present. An absent file is fine — koryph falls back to the default cap. A corrupt or zero-value file is an error/warning respectively.

zombie-leases

Scans slots/*.json for lease files whose tracked PID is no longer alive. Each zombie is a warning; pass --fix to remove them immediately.

koryph doctor --fix

stale-demand

Scans slots/demand/*.json for demand heartbeats whose engine PID is dead or whose updated_at timestamp is older than 10 minutes. Each stale entry is a warning; pass --fix to remove them.

quota-calibration

Reads each quota/<account>.json and checks whether both window_ceiling_usd and weekly_ceiling_usd are greater than zero. An uncalibrated account is a warning — the governor runs in advisory-only mode until calibrated:

koryph quota calibrate --account personal --window 5h \
    --observed-usd 4.20 --observed-pct 21

vault-providers

When ~/.koryph/vault.json is present, checks that the first binary in each provider's fetch template (e.g. pass-cli for ProtonPass, op for 1Password) is on PATH. A missing binary is a warning.

Project-mode checks

When --project <id> is given, koryph doctor runs against the project's repository root instead of ~/.koryph. These checks mirror what koryph onboard validates structurally (no network calls, no subprocess invocations):

project-config

Loads and validates koryph.project.json. A missing or corrupt file is an error.

git-repo

Verifies that .git exists at the project root. A missing .git is an error.

hooks-wiring

Checks .claude/settings.json for the three koryph hook markers: bd prime (SessionStart), agent-boundary-guard.sh (PreToolUse Bash), and worktree-guard.sh (PreToolUse Bash|Edit|Write). Each missing marker is a warning — run koryph rules install to repair.

signing

Inspects the project's signing block in koryph.project.json: - Absent block → ok (signing not configured). - Provider set but public_key not captured → warning (run koryph signing setup). - Invalid config shape (caught by project-config parse) → error.

protected-paths

Validates the protected_paths list for empty entries (error) and duplicate entries (warning).

stalled-runs

Scans the project ledger (.plan-logs/koryph/) for runs in running status where any non-terminal slot has not been updated for more than 30 minutes. Each stalled slot is a warning. Investigate manually — stalled agents may need to be stopped with koryph stop.

koryph doctor --project koryph

orphan-worktrees

Lists git worktrees registered under the project's worktree root (default <parent>/<repo>-worktrees/) whose branch starts with agent/ but have no corresponding active slot in any currently-running ledger run. Each orphan is a warning. Koryph never removes a dirty worktree automatically; review and remove manually:

git worktree remove --force path/to/orphan

JSON output

{
  "at": "2026-07-02T12:00:00Z",
  "home": "/Users/you/.koryph",
  "findings": [
    { "check": "layout", "level": "ok", "message": "layout ok" },
    { "check": "zombie-leases", "level": "ok", "message": "fixed",
      "fixed": true }
  ],
  "fixed_count": 1
}

In project mode the response includes a "project" field and "home" is the project's repo root:

{
  "at": "2026-07-02T12:00:00Z",
  "home": "/Users/you/src/myproject",
  "project": "myproject",
  "findings": [
    { "check": "project-config", "level": "ok", "message": "project_id=myproject work_source=bd" },
    { "check": "stalled-runs",   "level": "warn", "message": "stalled slot: run=20260702-100000 phase=bead-x status=running age=1h30m0s" }
  ]
}

The top-level fixed_count is non-zero only when --fix was passed and files were actually removed (global mode only).