Skip to content

doctor

bunx @pivanov/agent-hooks-bridge doctor [<script>] [options]

Read-only health check across .claude/settings.json, .cursor/hooks.json, and .codex/hooks.toml. Reports which entries point at hook scripts, whether the scripts resolve, and whether each entry is wired correctly. Never writes.

Usage

bash
# inspect every managed-looking entry across all three hosts
bunx @pivanov/agent-hooks-bridge doctor

# only inspect entries that point at one specific script
bunx @pivanov/agent-hooks-bridge doctor ./.hooks/format.ts

# limit to one host
bunx @pivanov/agent-hooks-bridge doctor --hosts claude

# only check hosts that look installed on this machine
bunx @pivanov/agent-hooks-bridge doctor --hosts auto

# inspect the user-level (global) config
bunx @pivanov/agent-hooks-bridge doctor --global

# inspect a custom layout
bunx @pivanov/agent-hooks-bridge doctor --cwd ~/.claude-main --config-root --hosts claude

Options

FlagDefaultNotes
<script> (positional)unsetIf provided, doctor only inspects entries whose command is <script> or starts with <script> .
--hosts <list>claude,cursor,codexCSV of host ids, or auto to inspect only hosts that look installed on this machine.
--cwd <path>process.cwd()Resolve <cwd>/.claude/, <cwd>/.cursor/, <cwd>/.codex/.
--global, -goffInspect each host's user-level config (~/.claude/settings.json, ~/.cursor/hooks.json, $CODEX_HOME/hooks.toml). Overrides --cwd and --config-root.
--config-rootoffTreat <cwd> as the host's config dir directly.
--help, -hPrint usage.

What it checks

For every managed-looking entry (a command that starts with ./, ../, /, or ~/, or matches the <script> filter):

  • The script file at the resolved path exists.
  • The file starts with a shebang line (#!); without one, hosts can't spawn it directly.
  • The executable bit is set (chmod +x).
  • The wired command includes --host <hostId> for the right host. Without this, run() falls back to stdin scoring (slower; see Host Detection).

Exit codes

OutcomeExit
All checks pass for every host inspected0
Any error-level issue found1
Argv parse failure1

The --host mismatch is a warning (?) rather than an error (!) and does not affect the exit code.

Sample output

text
# agent-hooks-bridge doctor
# cwd:    /Users/x/proj
# hosts:  claude, cursor, codex

# claude → /Users/x/proj/.claude/settings.json
  + 5 managed entry(ies)
    SessionStart: ./.hooks/format.ts --host claude
    PreToolUse (matcher=*): ./.hooks/format.ts --host claude
    PostToolUse (matcher=*): ./.hooks/format.ts --host claude
    UserPromptSubmit: ./.hooks/format.ts --host claude
    Stop: ./.hooks/format.ts --host claude

# cursor → /Users/x/proj/.cursor/hooks.json
  - file not found (skip)

# codex → /Users/x/proj/.codex/hooks.toml
  + 5 managed entry(ies)
    ...
  ! /Users/x/proj/.hooks/format.ts is not marked executable (chmod +x)

1 issue(s) found

Programmatic API

ts
import { runDoctor } from "@pivanov/agent-hooks-bridge";

const exitCode = await runDoctor({ argv: [] });

For tests, you can inject a virtual filesystem and a scriptCheck mock:

ts
import { runDoctor, type IScriptChecker } from "@pivanov/agent-hooks-bridge";

const fakeChecker: IScriptChecker = {
  check: () => ({ exists: true, hasShebang: true, executable: true }),
};

await runDoctor({
  argv: ["--cwd", "/proj"],
  fs: virtualFs,
  scriptCheck: fakeChecker,
  log: (line) => collectedOutput.push(line),
});

Out of scope

  • Doctor does not parse .codex/hooks.toml outside the managed block. Hand-rolled [[hooks]] entries are ignored.
  • Doctor does not run the script. It checks shape, not behavior.
  • Doctor does not validate that --host <id> matches a real adapter; only that it is wired in for the host whose config it appears in.

Not affiliated with Anthropic, Anysphere, or OpenAI. Supported by LogicStar AI.