Skip to content
Back to skills

Doctor

ASecurity

Diagnose and repair a broken or degraded skill-concierge install. Use this skill when the skill-search MCP won't connect, search_skills returns nothing or stale results, skills have gone dark, the MCP seems to run old code after a plugin update, or anything about skill-concierge misbehaves after setup or a plugin update. Runs scripts/doctor.py to check the deployment layer (engine venv, engine freshness, the local index owner, MCP wiring, settings overrides, ledger) and delegates retrieval he...

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 19, 2026
ai-agentspythonrustgobashsqldocker

Works with

  • claude code
  • cli
  • mcp

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add thinhkhuat/skill-concierge --skill doctor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Doctor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Doctor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thinhkhuat-doctor/badge)](https://www.skillsdirectory.com/skills/thinhkhuat-doctor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: doctor
user-invocable: true
description: Diagnose and repair a broken or degraded skill-concierge install. Use this skill when the skill-search MCP won't connect, search_skills returns nothing or stale results, skills have gone dark, the MCP seems to run old code after a plugin update, or anything about skill-concierge misbehaves after setup or a plugin update. Runs scripts/doctor.py to check the deployment layer (engine venv, engine freshness, the local index owner, MCP wiring, settings overrides, ledger) and delegates retrieval health to the engine; with --fix it applies safe repairs (start the index owner, reindex, re-apply overrides).
argument-hint: "[--fix]"
next-skills: skill-concierge:flywheel
license: MIT
metadata:
  version: 0.2.2
---

# skill-concierge doctor

A deployment-layer health check with safe auto-fixes. It diagnoses what `setup.sh`
provisions and delegates the retrieval diagnostic (embedder, index, dark/stale skills) to
the engine's own `skill-search --health`, so the two never drift.

## Steps

1. **Diagnose (read-only)** from the plugin root:

   ```bash
   python3 "$CLAUDE_PLUGIN_ROOT/scripts/doctor.py"
   ```

   It prints a check matrix and an overall `status: OK | WARN | FAIL` (exit `1` on FAIL).

2. **Read the matrix.** Each row is `[✓|!|✗] <check>  <detail>`:

   | Check | What it verifies |
   |-------|------------------|
   | Python 3.10-3.12 | a usable interpreter (only when the venv is missing) |
   | Engine venv | the stable venv + `skill-search` bin exist |
   | Engine freshness | the venv's COPIED engine matches the deployed vendored source — catches a **stale MCP serving old code after `/plugin update`** (the venv is built once by setup.sh and never refreshed by an update); WARN → rerun setup.sh |
   | MCP wiring | `.mcp.json` is valid + `bin/skill-search-mcp` is executable |
   | Index owner | the local index owner (ADR-0070; replaces the Qdrant container and the Docker embed shim) answers its Qdrant-compatible REST port + `/health`, its `code_version`, and its SQLite file's integrity/point counts |
   | Retrieval health | engine `--health`: embedder reachable, no dark/stale skills, index fresh |
   | Multi-vector layer | trigger points present (MAX-pool retrieval, ADR-0012); WARNs if `SKILL_MULTIVECTOR` is on but none exist |
   | Corpus health | per-skill calibration `ok`/`weak`/`no-signal` counts from `eval/thresholds.json` |
   | Retrieval flywheel | is the utterance-generation LLM configured + reachable, per-skill utterance coverage (which skills lack utterances), and the **last flywheel run** from the global manifest (`~/.claude/skill-concierge/flywheel-manifest.json`). Read-only, **fail-open** (never FAIL — the flywheel is optional). [ADR-0027](../../docs/adr/0027-flywheel-first-class-multi-provider.md) |
   | Trigger hygiene | junk **already stored** in the utterance layer — empty / one-char / repeated phrases a degraded model wrote. Coverage only measures *presence*, so such a skill still counts as "covered" and the generator then skips it forever; this row is what catches it. WARN + auto-fix (purge). Read-only, fail-open |
   | Settings overrides | `skillOverrides` applied to `~/.claude/settings.json`; now **detects drift** from the installed catalogue (`apply-overrides.py --check`) → WARN + auto-fix (ADR-0025) |
   | Ledger dir | the telemetry log directory is writable |
   | Duplicate MCP | warns if a leftover user-scope `skill-search` MCP also exists |
   | MCP reachable | warns when the skill-search MCP is installed but **not connected here** — disabled for the project via `/mcp`, pending approval, or failed. Every other row answers *is the index healthy*; this one answers *can the agent reach it*, and the two come apart: a project-disabled MCP leaves the engine fully green while `search_skills` / `get_skill` do not exist for that session. The enforcer's per-turn offer is unaffected (it queries Qdrant over REST), so WARN not FAIL. Read-only, fail-open, no auto-fix — re-enabling is a user action |

3. **Auto-fix the safe failures:**

   ```bash
   python3 "$CLAUDE_PLUGIN_ROOT/scripts/doctor.py" --fix
   ```

   `--fix` applies only fast, safe repairs, then re-checks: start a stopped index owner
   (also stopping + disabling a revived `skill-search-qdrant`/`skill-concierge-embed-shim`
   container if an old harness copy brought Docker back onto the owner's ports),
   `--reindex` a stale/dark index, re-apply the settings overrides, purge
   junk utterance layers. It never builds or refreshes the keep-off map — that is consent-only
   (ADR-0077); the `Keep-off` row only reports.

   > **Heads-up:** the overrides fix writes `~/.claude/settings.json` (backed up first) via
   > `scripts/apply-overrides.py`. The user invoking doctor is consent for that; mention it
   > before running `--fix` so the change isn't a surprise.
   >
   > **The `Trigger hygiene` fix DELETES data** — it drops each junk utterance layer from
   > the canonical corpus `~/.claude/skill-concierge/triggers.json` (backed up to `triggers.json.bak-junk-<ts>` first) and clears that
   > skill's generation-cache key, then reindexes. It does **not** regenerate: doctor never
   > calls the LLM. A purged skill falls back to description+body retrieval (no worse than
   > junk phrases pointing the wrong way) until the next flywheel run rewrites it — which it
   > now will, because the cleared cache key stops the generator skipping it as "covered".

4. **Handle what `--fix` can't.** doctor never auto-builds the venv or the container
   (slow, heavyweight). If `Engine venv` is FAIL **or `Engine freshness` is WARN**, run the
   **`skill-concierge:setup`** skill (or `./setup.sh`) — that rebuilds/refreshes the stable
   venv from the deployed source. For a duplicate MCP, run the printed `claude mcp remove`
   command. After any fix, **restart Claude Code** if the MCP wiring or engine changed.

5. **Doctor is a precondition, not the proof.** A green doctor shows files and config exist. It does not show
   that a harness runs the concierge: OpenCode's plugin failed to load, and Codex skipped the enforcer hook,
   while doctor stayed green (ADR-0090). To prove a harness works, run the live smoke:

   ```bash
   python3 "$CLAUDE_PLUGIN_ROOT/scripts/smoke.py"
   ```

   It runs one real headless turn per harness and passes a harness only when its temp ledger holds an `offer`
   row and a `search` row. It spends one model call per harness. A missing CLI is FAIL; ZCode has no command
   line and shows UNPROVEN. A harness in `--advisory` (default `$SMOKE_ADVISORY`) still reports but does not block. Do not claim a harness works on doctor
   alone.

## Symptom → check shortcuts

- **`/mcp` shows skill-search not connected** → `Engine venv` / `MCP wiring`. Fix: run setup.
- **search behaves like an OLD version after a plugin update** → `Engine freshness`. The MCP venv
  is stale (copied engine, not refreshed by `/plugin update`). Fix: rerun setup.sh, then restart.
- **search returns nothing or stale** → `Index owner` / `Retrieval health`. Fix: `--fix` (reindex)
  — note the SessionStart `auto_reindex` hook now self-heals index staleness in the background.
- **`Keep-off` row** only reports; `--fix` never touches the map (ADR-0077). No map, or a map
  without `"approved_by_user": true`, hides nothing and is OK (an unapproved map's names are
  reported as ignored). WARN means the file is invalid JSON or has no `keep_off` list. To get
  suppression, run `python3 scripts/build_keep_off.py` to see a proposal and `--apply` only after
  Thinh says yes. A skill you take inline that gets dropped → add it to keep-on (exempt).
- **skills you expect aren't offered / a new skill leaks its full description** → `Settings overrides`
  (now flags override **drift**). Fix: `--fix` (re-apply) — or nothing: the SessionStart
  `auto_overrides` hook self-heals the budget on drift (ADR-0025).

- **Doctor is green but a harness shows no menu or no search** → run `scripts/smoke.py`. A Codex row that fails
  with no offer row means Codex skipped a changed hook: open Codex and trust the skill-concierge hooks again
  (`docs/caveats.md` §27).

Full landmine reference: `docs/caveats.md`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.