Skip to content
Development
Command

/doctor

Check deliberation's health - config, provider CLIs, sessions/debug, and path drift - and suggest fixes. Read-only; never changes anything.

shell
$ npx -y skills add antonbabenko/deliberation --agent claude-code

Ships with deliberation. Installing the plugin gets this command.

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/doctor

Context preview

What this command does when you run it.

Check deliberation's health - config, provider CLIs, sessions/debug, and path drift - and suggest fixes. Read-only; never changes anything.

Command definition

doctor.md
name: doctor
description: Check deliberation's health - config, provider CLIs, sessions/debug, and path drift - and suggest fixes. Read-only; never changes anything.
allowed-tools: Bash, Read, mcp__deliberation__analyze
timeout: 60000

Doctor

A quick health check for deliberation. It looks at what is actually set up on this machine - your config, the provider CLIs, the session store - and tells you what is fine, what is off, and the exact command to fix each problem.

It never changes anything. Every fix is yours to run.

How it works

Two steps in order:

1. **One Bash call** - all the local checks (config, CLIs, keys, sessions dir, stale registrations). Run it with the **sandbox disabled** - it reads `~/.claude.json`, `~/.config`, and `~/.cache`, which a sandbox blocks. 2. **One `analyze` tool call** - to learn the path the *running server* resolved, so we can catch the one drift bug a local check can't see on its own.

Render a `flutter doctor`-style report: one line per check, tagged `[OK]`, `[WARN]`, or `[FAIL]`, and a fix line under anything that is not OK. End with a one-line summary. If everything passes, say so in one line - do not pad it.

Step 1: Local checks (ONE Bash call, sandbox DISABLED)

set -u

ok(){ printf '[OK]   %s\n' "$1"; }
warn(){ printf '[WARN] %s\n' "$1"; }
fail(){ printf '[FAIL] %s\n' "$1"; }

# --- plugin root + version: env -> marketplace cache (highest semver) -> checkout ---
resolve_plugin_root() {
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -f "$CLAUDE_PLUGIN_ROOT/server/mcp/index.js" ]; then printf '%s' "$CLAUDE_PLUGIN_ROOT"; return 0; fi
  local c; c=$(find "$HOME/.claude/plugins/cache" -maxdepth 6 -path '*/deliberation/*/server/mcp/index.js' -type f 2>/dev/null | sort -V | tail -1)
  if [ -n "$c" ]; then printf '%s' "${c%/server/mcp/index.js}"; return 0; fi
  if [ -f "$PWD/server/mcp/index.js" ] && grep -q '"name": "deliberation"' "$PWD/.claude-plugin/plugin.json" 2>/dev/null; then printf '%s' "$PWD"; return 0; fi
  return 1
}
echo "== deliberation doctor =="
PR="$(resolve_plugin_root || true)"
if [ -n "$PR" ]; then
  VER="$(node -e "process.stdout.write(require('$PR/package.json').version||'?')" 2>/dev/null || echo '?')"
  ok "plugin found ($PR, v$VER)"
else
  fail "plugin root not found"; echo "       fix: reinstall with /plugin, then /deliberation:setup"
fi

# --- config: env override > canonical XDG ---
CFG="${DELIBERATION_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/deliberation/config.json}"
case "$CFG" in /*) ;; *) CFG="$HOME/.config/deliberation/config.json";; esac
if [ -f "$CFG" ]; then
  if node -e "JSON.parse(require('fs').readFileSync('$CFG','utf8'))" 2>/dev/null; then
    ok "config valid ($CFG)"
    node -e '
      const c=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));
      const s=c.sessions||{}, d=c.debug||{};
      console.log((s.persist?"[OK]   ":"[WARN] ")+"sessions.persist: "+(!!s.persist)+(s.persist?"":"  fix: set sessions.persist:true for /analyze Lens B"));
      console.log((d.enabled?"[OK]   ":"[WARN] ")+"debug.enabled: "+(!!d.enabled)+(d.enabled?"":"  fix: set debug.enabled:true for /analyze Lens A"));
    ' "$CFG"
  else
    fail "config is not valid JSON ($CFG)"; echo "       fix: correct the JSON, or move it aside and run /deliberation:setup"
  fi
else
  warn "no config at $CFG"; echo "       fix: run /deliberation:setup"
fi

# --- provider CLIs (presence + version only; auth is confirmed by a real /ask-* call) ---
if command -v codex >/dev/null 2>&1; then ok "codex CLI on PATH ($(codex --version 2>/dev/null | head -1))"; else warn "codex (GPT) not on PATH"; echo "       fix: install the Codex CLI, or ignore if you don't use GPT"; fi
if command -v agy >/dev/null 2>&1; then ok "agy CLI on PATH (Gemini)"; else warn "agy (Gemini) not on PATH"; echo "       fix: install the Antigravity CLI, or ignore if you don't use Gemini"; fi
[ -n "${XAI_API_KEY:-}" ] && ok "XAI_API_KEY set (Grok)" || warn "XAI_API_KEY unset - Grok calls return missing-auth"
[ -n "${OPENROUTER_API_KEY:-}" ] && ok "OPENROUTER_API_KEY set" || warn "OPENROUTER_API_KEY unset - OpenRouter models will error"

# --- sessions dir the SHELL resolves (compared to the server's in step 2) ---
SD="${DELIBERATION_SESSIONS:-${XDG_CACHE_HOME:-$HOME/.cache}/deliberation/sessions}"
case "$SD" in /*) ;; *) SD="$HOME/.cache/deliberation/sessions";; esac
echo "SHELL_SESSIONS_DIR=$SD"
if [ -d "$SD" ]; then
  N=$(ls -1 "$SD"/*.json 2>/dev/null | wc -l | tr -d ' ')
  ok "sessions dir exists ($SD, $N record(s))"
else
  warn "sessions dir not found ($SD) - nothing persisted there yet"
fi

# --- stale user-scope MCP registrations (the inline plugin manifest is the SSOT) ---
LEFT="$(node -e 'try{const fs=require("fs"),h=require("os").homedir();const j=JSON.parse(fs.readFileSync(h+"/.claude.json","utf8"));const m=j.mcpServers||{};process.stdout.write(Object.keys(m).filter(k=>k==="deliberation"||k.indexOf("deliberation-")===0).join(" "))}catch(e){}')"
[ -n "$LEFT" ] && { warn "user-scope MCP entries shadow the plugin manifest: $LEFT"; echo "       fix: /deliberation:uninstall (then they load from the plugin)"; } || ok "no shadowing user-scope MCP registrations"
echo "== end local checks =="

Step 2: Runtime path drift (ONE `analyze` call)

Call the tool, then compare the server's resolved sessions dir to the shell's:

mcp__deliberation__analyze({})
  • Read `meta.sessionsDir` (the dir the **running server** uses) and compare it to

`SHELL_SESSIONS_DIR` from step 1.

  • **Match** -> `[OK] sessions path: server and shell agree`.
  • **Differ** -> this is the drift bug:
    [FAIL] sessions path drift
           server reads: <meta.sessionsDir>
           shell wrote:  <SHELL_SESSIONS_DIR>
           cause: XDG_CACHE_HOME / DELIBERATION_SESSIONS differs between the shell
                  that wrote records and the process that launched the MCP server.
           fix: set DELIBERATION_SESSIONS to one path in both places, t
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withdeliberation

Get a second opinion in Claude Code from GPT, Gemini, and Grok - plus 400+ more models through OpenRouter, including Qwen, Kimi, and DeepSeek.

Get the whole plugin, auto-invoked
Stats
123
Stars
0
Views
8
Forks
Active
Maintenance
JavaScript
Language
MIT
License
7d ago
Last commit
2mo ago
Created

Repo: antonbabenko/deliberation