원클릭으로
toolkit-doctor
Use when diagnosing toolkit health issues or optimizing configuration.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when diagnosing toolkit health issues or optimizing configuration.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when updating the toolkit to a new version.
Use when code changes need review before merging or completing.
Use when contributing generic improvements back to the toolkit repo.
Use when setting up or reconfiguring the toolkit for a project.
Use when existing code needs iterative quality improvement.
Use when working on one or more GitHub issues.
| name | toolkit-doctor |
| description | Use when diagnosing toolkit health issues or optimizing configuration. |
| user-invocable | true |
Perform a deep health evaluation of the toolkit installation. Goes beyond the CLI toolkit.sh doctor (which checks infrastructure basics) by analyzing configuration coherence, live-testing commands, auditing dependencies and API keys, checking CLAUDE.md content, identifying optimization opportunities, and testing hook behavior in depth.
Relationship to
toolkit.sh doctor: The CLI command remains available for quick terminal/CI checks. This skill flow includes everything the CLI checks as Phase H0, then goes much deeper with AI-assisted analysis and interactive fixes.
User Interaction Principle: Present all findings before applying fixes. Categorize by severity so the user can prioritize. Never auto-fix without confirmation.
/toolkit-doctor # Run deep health evaluation and optimization
Note: This skill is interactive and requires user input at decision points (fix approval, etc.). For automated or CI health checks, use bash .claude/toolkit/toolkit.sh doctor (non-interactive) or bash .claude/toolkit/toolkit.sh validate instead.
When NOT to use (the skill will detect these and redirect):
/toolkit-setup instead/toolkit-update instead| Rule | Description |
|---|---|
| 1. Report findings by severity | Categorize every finding as ERROR, WARN, OPT, or INFO using the severity system; never mix severities. |
| 2. Offer fixes interactively | Present all findings to the user before applying any fixes; let the user choose which fixes to apply. |
| 3. Never auto-fix without confirmation | Even for obviously safe fixes, always ask the user before modifying files or running commands. |
| 4. Test fixes before applying | After applying a fix, re-run the relevant check to verify the fix actually resolved the issue. |
All findings across all phases use this four-tier severity system:
| Severity | Symbol | Meaning | Action |
|---|---|---|---|
| Error | [ERROR] | Something is broken or misconfigured and will cause failures | Must fix (auto-fix offered where possible) |
| Warning | [WARN] | Potential problem that may cause unexpected behavior | Should fix (auto-fix offered where possible) |
| Optimization | [OPT] | Working but could be improved for better experience | Optional (auto-fix offered where possible) |
| Info | [INFO] | Informational observation, no action needed | No action |
Accumulate findings throughout all phases. Each finding records: severity, phase, description, and whether an auto-fix is available.
Execute these phases in order. Do NOT skip phases.
Run the existing CLI doctor command as a foundation. No point doing deep analysis if the basics are broken.
ls .claude/toolkit/toolkit.sh
If the file does not exist, the toolkit is not installed. Tell the user:
The toolkit is not installed in this project. Use
/toolkit-setupto install and configure it first.
Stop here if the toolkit is not installed.
If .claude/toolkit.toml does not exist, the toolkit was installed but never configured. Tell the user:
The toolkit subtree exists but has not been configured yet. Use
/toolkit-setupto complete the initial configuration. The doctor skill requires a configured toolkit to diagnose.
Stop here if toolkit.toml does not exist.
First verify the CLI doctor command exists (older toolkit versions may not have it):
bash .claude/toolkit/toolkit.sh help 2>&1
If the help output does not list doctor as a command, skip this step and proceed directly to Phase H1 — the deep analysis phases do not depend on CLI doctor output. Report [INFO] ("CLI doctor not available in this toolkit version — running deep analysis only").
If available, run it:
bash .claude/toolkit/toolkit.sh doctor
Capture the full output. Parse the summary line for pass/fail/warning counts.
If doctor reports failures:
| Doctor Failure | Auto-Fix |
|---|---|
| Missing required tool (git, jq, python3) | [ERROR] from CLI. Manual install required. Provide platform-specific install commands: git (xcode-select --install / apt install git), jq (brew install jq / apt install jq), python3 (brew install python3 / apt install python3). Cannot auto-fix — stop deeper analysis if jq or python3 is missing (needed for subsequent checks). |
| Python version < 3.11 | [ERROR] from CLI. Manual upgrade required. Inform user: "Python [version] requires upgrade to 3.11+ for tomllib support. Install via brew install python@3.11 (macOS) or apt install python3.11 (Ubuntu/Debian) or from python.org." |
| Missing config cache | python3 .claude/toolkit/generate-config-cache.py --toml .claude/toolkit.toml --output .claude/toolkit-cache.env |
| Stale config cache | Same as above |
| Broken symlinks | bash .claude/toolkit/toolkit.sh init --force |
| Non-executable hooks | chmod +x .claude/toolkit/hooks/*.sh |
| Stale settings.json | bash .claude/toolkit/toolkit.sh generate-settings |
| Manifest corrupted | bash .claude/toolkit/toolkit.sh init |
If critical failures persist after fix attempts (e.g., required tools missing, toolkit directory not found), ask the user whether to continue with deeper analysis or abort.
Map doctor results to the severity system: doctor failures become [ERROR], doctor warnings become [WARN], doctor info items become [INFO].
Detect contradictions, staleness, and drift between the various configuration sources.
Run the detection script and compare detected stacks against configured stacks:
python3 .claude/toolkit/detect-project.py --project-dir .
Parse the JSON output. Read the configured stacks from .claude/toolkit.toml ([project] stacks).
[WARN] ("Stack '[name]' configured in toolkit.toml but not detected in project")[OPT] ("Stack '[name]' detected but not configured -- add to toolkit.toml for stack-specific tooling")[project] stacks in toolkit.toml to match detectionGenerate what settings.json should contain by running the merge logic in-memory, then compare against the actual file. If they differ, identify which sections diverge (hooks, deny patterns, env vars, etc.) and report:
[WARN] ("settings.json is stale -- [section] differs from what generate-settings would produce")bash .claude/toolkit/toolkit.sh generate-settingsCompare toolkit.toml mtime against toolkit-cache.env mtime. Additionally, regenerate the cache in-memory and compare content against the current file. This catches cases where the file was touched but content is wrong.
[WARN] ("Config cache is stale or has incorrect content")python3 .claude/toolkit/generate-config-cache.py --toml .claude/toolkit.toml --output .claude/toolkit-cache.envCompare the commands configured in toolkit.toml against what detect-project.py would produce:
| toolkit.toml key | Detection field |
|---|---|
[hooks.post-edit-lint.linters.<ext>] cmd | lint.<stack>.cmd |
[hooks.task-completed.gates.tests] cmd | test.cmd |
[hooks.task-completed.gates.lint] cmd | lint.<stack>.cmd |
[INFO] (likely intentional customization)[OPT] ("Detected '[cmd]' as lint command, but toolkit.toml still uses example default '[default_cmd]'")python3 .claude/toolkit/generate-config-cache.py --validate-only --toml .claude/toolkit.toml
This validates the TOML against the schema without generating output. If it returns non-zero, the TOML has validation errors.
[ERROR] with the specific schema error messageTest that configured commands actually work -- not just "is the binary available" but "does the command succeed when invoked."
toolkit-cache.env or by parsing toolkit.toml: [hooks.task-completed.gates.lint] cmd)/), check with test -x <path> -- if the path references a virtual environment (e.g., .venv/bin/ruff) that does not exist, report [ERROR] ("Lint command references '.venv/bin/ruff' but '.venv/' does not exist")command -v <exe><exe> --version to verify it works[ERROR] with install guidance[ERROR][INFO] ("Lint command works -- found lint issues in sample file, which is expected")[INFO] ("Lint command works correctly")[hooks.task-completed.gates.tests] cmd)make test-changed), verify the Makefile has that target:grep -qE '^test-changed[[:space:]]*:' Makefile 2>/dev/null
Note: Makefile targets may have optional whitespace before the colon. The pattern ^target[[:space:]]*: handles both test-changed: and test-changed : variants.
timeout parameter set to 60000 (60 seconds) to avoid hanging on long-running test suites (consistent with toolkit-setup's 60s timeout). The || true ensures the Bash tool does not report a non-zero exit as an error:<test-command> 2>&1 || true
Note: If the command is still running when the timeout expires, the Bash tool will terminate it — this is expected and counts as a successful "starts correctly" verification.
[ERROR][ERROR] ("Test command 'make test-changed' references missing Makefile target")[INFO] ("Test command works -- some tests fail, which may be expected")[INFO] ("Test command starts correctly -- timed out after 60s, which is normal for full test suites")[INFO]For each extension configured in [hooks.post-edit-lint.linters.<ext>]:
fmt commandfallback is configured, check if the fallback is available too[WARN] ("Format command for .[ext] files references '[exe]' which is not found")[WARN]Same pattern as H2.3 but for the cmd field in each linter extension section.
Check that external dependencies and credentials referenced across the configuration are available.
Read .mcp.json and check each configured MCP server:
Read the base MCP configuration dynamically using the Read tool on .claude/toolkit/mcp/base.mcp.json. Extract all server names:
jq '.mcpServers // {} | keys[]' .claude/toolkit/mcp/base.mcp.json
For each base server, extract its command and check availability. Known API key requirements (update this table as new servers are added):
| Server | API Key Check | If Missing |
|---|---|---|
| codex | OPENAI_API_KEY env var set? | [WARN] OPENAI_API_KEY not set -- codex MCP may not authenticate |
For all base servers (including any new ones not in the table above), extract the command from the config:
jq -r '.mcpServers.<name>.command // .mcpServers.<name>.args[0] // "unknown"' .claude/toolkit/mcp/base.mcp.json
Check if the command is available: command -v <exe>. If not found -> [WARN].
For any additional MCP servers found in .mcp.json that are NOT in the base config:
command field (first element of args or the command key)command -v <exe>[WARN] ("MCP server '[name]' references command '[cmd]' which is not found")[INFO] ("MCP server '[name]' command '[cmd]' is available")brew install node", "Set OPENAI_API_KEY: export OPENAI_API_KEY=...")Read from the toolkit config:
[hooks.setup] required_tools -- each missing tool -> [ERROR] with install guidance[hooks.setup] optional_tools -- each missing tool -> [INFO][hooks.setup] security_tools -- each missing tool -> [OPT] with install guidanceFor each missing tool, provide platform-appropriate install commands where possible:
| Tool | macOS | Linux |
|---|---|---|
| ruff | pip install ruff | pip install ruff |
| jq | brew install jq | apt install jq |
| gitleaks | brew install gitleaks | brew install gitleaks |
| semgrep | pip install semgrep | pip install semgrep |
| shellcheck | brew install shellcheck | apt install shellcheck |
Based on the configured stacks in toolkit.toml, check for expected tools:
| Stack | Expected Tools |
|---|---|
| python | python3, pip or pip3 |
| typescript | node, npm or npx |
| ios | xcrun, swift |
Each missing expected tool for a configured stack -> [WARN] ("Stack 'python' is configured but 'pip3' is not found")
Check that the project's CLAUDE.md (at the project root) is consistent and complete. Skip this phase entirely if no project CLAUDE.md exists -- report [INFO] ("No project CLAUDE.md found -- consider creating one with /toolkit-setup") and proceed.
Important: Analyze the project's root CLAUDE.md, NOT the toolkit's own CLAUDE.md at .claude/toolkit/CLAUDE.md.
Read the project's CLAUDE.md and search for:
{{...}}<!-- ... --> (indicates sections not yet customized)Each unfilled placeholder -> [OPT] ("CLAUDE.md has unfilled placeholder: '{{PLACEHOLDER_NAME}}'")
Each template comment -> [OPT] ("CLAUDE.md has template comment that should be replaced with project content")
Extract command references from CLAUDE.md -- look for lines inside code blocks (``` sections) that appear to be shell commands (lines starting with common command prefixes or containing tool names).
Cross-reference extracted commands with toolkit.toml configuration:
make test but toolkit.toml test gate uses pytest -> [WARN] ("CLAUDE.md references 'make test' but toolkit.toml test gate uses 'pytest' -- these should be consistent")ruff check but toolkit.toml uses .venv/bin/ruff check -> [INFO] (minor path difference)This check is heuristic. Report only clear contradictions, not stylistic differences.
For each command found in CLAUDE.md code blocks, do a quick availability check:
make <target>, check if the Makefile has that targetcommand -v <exe>Each unreachable command -> [WARN] ("CLAUDE.md references '[command]' but it is not available")
Do not flag commands that are clearly examples or placeholders (e.g., lines with <placeholder> syntax).
If CLAUDE.md exists but does not mention "toolkit" anywhere (case-insensitive search), report:
[OPT] ("CLAUDE.md does not mention the toolkit -- consider adding a section. Run /toolkit-setup to add one automatically.")Identify configuration that works but could be improved.
Read .claude/toolkit.toml and compare key fields against the example template defaults (templates/toolkit.toml.example):
| Field | Example Default | Finding if Unchanged |
|---|---|---|
[project] name | "my-project" | [OPT] "Project name is still the example default 'my-project'" |
[hooks.subagent-context] critical_rules | [] | [OPT] "No critical rules configured -- subagents will not receive project-specific rules" |
[hooks.subagent-context] available_tools | [] | [OPT] "No available tools configured for subagent context" |
[hooks.subagent-context] stack_info | "" | [OPT] "No stack info configured -- subagents will not know the project's tech stack" |
[toolkit] remote_url | "git@github.com:user/claude-toolkit.git" | [OPT] "Toolkit remote URL is still the example placeholder" |
Auto-fix available: For [project] name, offer to set it to the detected project name (from detect-project.py). For stack_info, offer to auto-generate from configured stacks.
Read the configured auto-approve write paths and check each glob pattern against the actual project structure:
# For each pattern like "*/app/*", check if the directory exists
ls -d app/ 2>/dev/null
Patterns that do not match any existing directory -> [INFO] ("Auto-approve path pattern '/app/' does not match any directory in this project -- it will have no effect until an 'app/' directory is created")
This is informational only -- the paths might be created later.
For each stack detected by detect-project.py, check if a corresponding stack overlay JSON exists at .claude/toolkit/templates/stacks/<stack>.json:
[INFO] ("No stack overlay found for detected stack '[name]' -- the toolkit does not yet have built-in support for this stack")[WARN] ("Stack '[name]' configured in toolkit.toml but no overlay file exists at templates/stacks/[name].json")Read the manifest at .claude/toolkit-manifest.json. For each file marked as customized, check for drift:
For agents and rules: Compare the manifest's recorded toolkit_hash against the current toolkit source hash:
shasum -a 256 .claude/toolkit/<source_path> | cut -d' ' -f1
If the hash differs from the manifest's toolkit_hash, the toolkit source has changed since customization (drift).
For skills: The manifest does NOT store toolkit_hash for skills (only status, files, and project_files). To detect drift, compare each file in the customized skill directory against the corresponding toolkit source file using diff.
Drift findings:
[OPT] ("Customized file '[path]' has upstream drift -- the toolkit source was updated since you customized it. To resolve: run /toolkit-update which includes Phase U4 Drift Resolution, where you can choose to keep your customization, merge upstream changes, or revert to the managed version.")If the manifest does not exist, skip this check and report [WARN] ("Manifest not found -- cannot check for customization drift. Run toolkit.sh init to create a manifest.")
Test hooks more thoroughly than the CLI doctor's 2-sample test, and check for potential conflicts between hooks.
Step H6.1.0: Ensure config cache is fresh (prerequisite for all hook tests below)
Hooks source _config.sh which reads toolkit-cache.env. Before running any hook tests, check if toolkit-cache.env exists and is fresh:
ls -la .claude/toolkit-cache.env 2>/dev/null
If the file does not exist or was flagged as stale in Phase H1.3, regenerate it now (do not wait for Phase H7):
python3 .claude/toolkit/generate-config-cache.py --toml .claude/toolkit.toml --output .claude/toolkit-cache.env
After regeneration, verify the file was created successfully:
ls -la .claude/toolkit-cache.env 2>/dev/null
If regeneration failed (file still missing or empty), report [ERROR] ("Config cache regeneration failed — hook tests cannot produce reliable results") and skip all hook tests in H6.1.1. Proceed to H6.2 (conflict detection does not depend on cache).
Without a fresh cache, hooks will use default values that produce unexpected test results.
Also verify hook scripts are executable before running tests:
find .claude/toolkit/hooks/ -name '*.sh' ! -perm -u+x 2>/dev/null
If any hooks are not executable, report [ERROR] ("Hook scripts are not executable — run chmod +x .claude/toolkit/hooks/*.sh") and skip all hook tests in H6.1.1. Non-executable hooks produce cryptic "Permission denied" errors that obscure the real issue. This should have been caught in Phase H0, but permissions can change between phases.
Step H6.1.1: Run hook tests
Test guard-destructive.sh with multiple sample inputs:
| Input | Expected | Category |
|---|---|---|
{"tool_name":"Bash","tool_input":{"command":"ls -la"}} | exit 0 (allow) | Safe command |
{"tool_name":"Bash","tool_input":{"command":"git push origin main --force"}} | deny JSON | Destructive git |
{"tool_name":"Bash","tool_input":{"command":"git reset --hard HEAD"}} | deny JSON | Destructive git |
{"tool_name":"Bash","tool_input":{"command":"rm -rf src/"}} | deny JSON | Destructive rm |
Test guard-sensitive-writes.sh with:
| Input | Expected | Category |
|---|---|---|
{"tool_name":"Write","tool_input":{"file_path":"src/main.py"}} | exit 0 (allow) | Safe write |
{"tool_name":"Write","tool_input":{"file_path":".env"}} | deny JSON | Secret file |
{"tool_name":"Write","tool_input":{"file_path":".claude/settings.json"}} | deny JSON | Toolkit config |
Test auto-approve-safe.sh with:
| Input | Expected | Category |
|---|---|---|
{"tool_name":"Read","tool_input":{"file_path":"README.md"}} | approve JSON | Safe read |
{"tool_name":"Bash","tool_input":{"command":"git status"}} | approve JSON | Safe bash |
For each test, pipe the sample input to the hook via stdin with CLAUDE_PROJECT_DIR set:
echo '<input_json>' | CLAUDE_PROJECT_DIR="$(pwd)" bash .claude/toolkit/hooks/<hook>.sh
Check the exit code and stdout. Each unexpected result -> [ERROR] ("Hook '[hook]' returned unexpected result for '[category]' input: expected [expected], got exit code [actual]")
Analyze the logical relationship between guard hooks and auto-approve:
toolkit-cache.env (variable TOOLKIT_AUTO_APPROVE_WRITE_PATHS) or parse from toolkit.toml [hooks.auto-approve] write_paths.claude/toolkit/hooks/guard-sensitive-writes.sh — search for case statements or regex patterns that match file paths (e.g., .env, credentials, .ssh, settings.json). Also check the permissions.deny list in .claude/settings.json for additional denied patterns.For example, if auto-approve includes */.claude/* and guard-sensitive-writes denies .claude/settings.json, that is a potential conflict where the auto-approve would approve a write that the guard would subsequently deny.
Each conflict found -> [WARN] ("Potential conflict: auto-approve pattern '[pattern]' overlaps with guard-sensitive-writes deny pattern for '[file]' -- the guard takes precedence, but the auto-approve entry is misleading")
Read hook timeouts from .claude/settings.json (the hooks array, where each hook entry may have a timeout field):
guard-) with timeout > 30000ms -> [INFO] ("Guard hook '[name]' has a [N]s timeout -- guards should respond quickly")[INFO] ("Task-completed gate has a [N]s timeout -- tests may need more time")[INFO] ("Hook '[name]' has a [N]s timeout -- this is unusually long")Present all accumulated findings and offer fixes.
Present all findings grouped by severity:
Doctor Report
Errors ([count])
# Phase Finding Fix Available 1 H2 Lint command '.venv/bin/ruff' not found -- .venv/ does not exist Yes 2 H3 Required tool 'jq' not found Manual: brew install jqWarnings ([count])
# Phase Finding Fix Available 1 H1 settings.json is stale -- hooks section differs Yes 2 H4 CLAUDE.md references 'make test' but toolkit.toml uses 'pytest' Manual Optimizations ([count])
# Phase Finding Fix Available 1 H5 Project name still 'my-project' Yes 2 H5 No critical rules configured for subagent context Manual Info ([count])
# Phase Finding 1 H3 Gemini CLI not installed (optional) 2 H5 Auto-approve path '/app/' matches no directory Total: [N] errors, [N] warnings, [N] optimizations, [N] info
If there are zero findings across all categories, report:
Doctor Report
All clear. No issues, warnings, or optimization opportunities found. The toolkit installation is healthy.
Categorize all fixable findings into three groups:
Auto-fixable (can be applied safely with a single command):
Interactive (need user input to determine the correct fix):
Manual (require user action outside the session):
Present the auto-fixable items first:
Auto-fix available for [N] issues:
- Regenerate config cache (toolkit-cache.env stale)
- Regenerate settings.json (out of date)
- Fix 2 broken symlinks
Apply all auto-fixes? [yes / no / select individually]
If the user chooses "select individually", present each fix one at a time.
Then step through interactive fixes one by one, presenting the choice and waiting for user input.
Finally, list manual fixes:
Manual action needed:
- Install gitleaks:
brew install gitleaks- Set OPENAI_API_KEY environment variable for codex MCP
- Fill in CLAUDE.md placeholder: {{PROJECT_DESCRIPTION}}
After applying any fixes:
bash .claude/toolkit/toolkit.sh validate to confirm fixes workedtoolkit.toml, regenerate the config cachePost-fix verification: [N]/[N] fixes applied successfully. Validation: [passed/failed].
If validation still reports issues after fixes, present the remaining issues.
Unlike the Setup and Update flows, the Doctor flow does NOT commit changes automatically. Config file modifications should be reviewed by the user first.
List all modified files at the end:
Modified files (not committed):
.claude/toolkit.toml(updated stacks, project name).claude/toolkit-cache.env(regenerated).claude/settings.json(regenerated)Review the changes and commit when ready.
| Error | Recovery |
|---|---|
toolkit.sh doctor fails entirely | Report [ERROR] with the error output. Ask user whether to continue with deeper analysis or abort. |
python3 not found or < 3.11 | Report [ERROR] from CLI doctor. Stop deeper analysis — python3 is required for detection (H1), config cache (H1.3), and TOML validation (H1.5). Provide install guidance: brew install python@3.11 (macOS) or apt install python3.11 (Linux). |
detect-project.py fails | Skip H1.1 and H1.4 (stack and command comparison). Report [WARN] ("Detection script failed -- some coherence checks were skipped"). Continue with remaining phases. |
| toolkit.toml parse error | Report [ERROR] in H1.5. Skip H1.4 and H5.1 (these require parsed TOML). Continue with remaining phases. |
| CLAUDE.md does not exist | Skip Phase H4 entirely. Report [INFO] ("No project CLAUDE.md found"). |
.mcp.json does not exist | Skip H3.1. Report [INFO] ("No .mcp.json found -- run toolkit.sh generate-settings to create one"). |
| Hook sample input test crashes | Report [ERROR] for the specific hook. Continue testing remaining hooks. |
| Manifest not found | Skip H5.4 (drift check). Report [WARN] ("Manifest not found -- cannot check for customization drift"). |
| settings.json does not exist | Skip H1.2 and H6.3 (settings freshness and timeout checks). Report [WARN]. |