ccc-doctor

ccc-doctor is a skill for Claude Code from KevinZai/commander. It costs 40 tokens per session (6,637 once invoked), scanned D, original, MIT.

A diagnostic report generator for CC Commander, an add-on for Claude Code. It collects details about the installation, settings, sessions, connected servers, and possible differences between parts of the stack.

In plain words
What is it for?
Use it when reporting a CC Commander problem in a GitHub issue or Discord support thread, or when checking plugin versions, updates, Node, marketplace files, MCP servers, settings, sessions, and full-stack drift.
Why use it?
It gathers the information support teams usually need in one paste-ready report, including missing or outdated components. This avoids manually searching through many files and settings.

Skill for Claude Code

Written for Claude Code: allowed-tools in frontmatter. Also seen: model in frontmatter; reads .claude/ paths; mentions subagents.

Good fit Use it when reporting a CC Commander problem in a GitHub issue…

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/kevinzai/commander/ccc-doctor
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Any agent
npx skills add KevinZai/commander --skill ccc-doctor
Clone the repo
git clone --depth 1 https://github.com/KevinZai/commander

Made for: Claude Code.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for ccc-doctor

README.md
[![agentmods](https://agentmods.dev/badge/skills/kevinzai/commander/ccc-doctor.svg)](https://agentmods.dev/skills/kevinzai/commander/ccc-doctor)
Your own site
<a href="https://agentmods.dev/skills/kevinzai/commander/ccc-doctor"><img src="https://agentmods.dev/badge/skills/kevinzai/commander/ccc-doctor.svg" alt="Measured on agentmods" height="20"></a>
Per session 40 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 6,637 The whole file, excluding the scripts and references it only reads on demand.
Security scan D 2 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00040 $0.06637
Opus 5 $0.00020 $0.03318
Sonnet 5 $0.00008 $0.01327
Haiku 4.5 $0.00004 $0.00664

Measured 7d ago against content hash d579c36ae327, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-06, from the pricing page.

Security

Grade D, and why

ccc-doctor scanned grade D with 2 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 7d ago.

The scan reads SKILL.md. This mod also ships 1 executable file (lib/diagnostics.js), listed below but not scanned — reading those needs a real analyzer, not pattern matching.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Reads agent configuration directoriesmediumAgent snooping

.claude/, .codex/, .gemini/ hold keys, settings and other credentials a mod has no legitimate need for.

SETTINGS="$HOME/.claude/settings.json"

Recursive force deletehighDestructive command

rm -rf with a variable or a broad path is one typo away from removing the wrong tree.

rm -rf ~/.claude/plugins/marketplaces/commander-hub
commander/cowork-plugin-codex/skills/ccc-doctor/SKILL.md · 521 lines

How it starts

The opening of the file, as written. The whole thing — 521 lines — stays where its author put it; the contents beside it link to each section on GitHub.

$ccc-doctor — CC Commander Diagnostic Report

Generates a paste-ready diagnostic snapshot. Paste the output into a GitHub issue or Discord support thread.

What to do

Run the Bash block below in a single call. Handle every missing file gracefully — use 2>/dev/null || echo "n/a". Never crash if a file doesn't exist.

# ── Marketplace clone root ───────────────────────────────────────────
# The marketplace clone dir is named after the MARKETPLACE key
# (commander-hub), not the plugin — .git lives directly here. The repo's
# OWN top-level layout then nests the plugin source one level further at
# commander/cowork-plugin/. Both segments are real; do not collapse them.
CLONE="$HOME/.claude/plugins/marketplaces/commander-hub"
[ -d "$CLONE" ] || CLONE="n/a"

PLUGIN_SRC="n/a"
if [ "$CLONE" != "n/a" ] && [ -d "$CLONE/commander/cowork-plugin" ]; then
  PLUGIN_SRC="$CLONE/commander/cowork-plugin"
fi

# Cache-only fallback (no marketplace clone — removed by the user, or an
# install flow that never cloned): the INSTALLED runtime recorded in
# installed_plugins.json is authoritative. SHAPE DIFFERENCE: the clone nests
# the source at commander/cowork-plugin/; the cache installPath IS the plugin
# source directly — no wrapper segment.
if [ "$PLUGIN_SRC" = "n/a" ] && [ -f "$HOME/.claude/plugins/installed_plugins.json" ]; then
  PLUGIN_SRC=$(node -e "
    try {
      const j=JSON.parse(require('fs').readFileSync(process.env.HOME+'/.claude/plugins/installed_plugins.json','utf8'));
      const rows=(j.plugins&&(j.plugins['commander@commander-hub']||j.plugins['commander']))||[];
      const r=Array.isArray(rows)?rows[0]:rows;
      if(r&&r.installPath) process.stdout.write(r.installPath);
    } catch(e) {}
  " 2>/dev/null || echo "")
  [ -z "$PLUGIN_SRC" ] && PLUGIN_SRC="n/a"
  [ "$PLUGIN_SRC" != "n/a" ] && [ ! -d "$PLUGIN_SRC" ] && PLUGIN_SRC="n/a"
fi

# Desktop-managed (account-synced) fallback: Cowork/Claude Desktop provisions the
# plugin per session under Application Support — no clone AND no
# installed_plugins.json entry is a HEALTHY state in that mode, not a broken
# install. Report the mode; do not advise CLI marketplace commands (there is no
# clone for them to act on). Update path in this mode: Desktop → Settings →
# Plugin Marketplace (stuck versions: remove at claude.ai web → Cmd+Q → reinstall).
INSTALL_MODE="cli-marketplace"
if [ "$PLUGIN_SRC" = "n/a" ]; then
  DESKTOP_MANIFEST=$(/bin/ls -t "$HOME/Library/Application Support/Claude/"local-agent-mode-sessions/*/*/rpm/plugin_*/.claude-plugin/plugin.json 2>/dev/null | head -50 | while read -r f; do
    if /usr/bin/grep -q '"name"[[:space:]]*:[[:space:]]*"commander"' "$f" 2>/dev/null; then echo "$f"; break; fi
  done)
  if [ -n "$DESKTOP_MANIFEST" ]; then
    INSTALL_MODE="desktop-managed"
    PLUGIN_SRC=$(dirname "$(dirname "$DESKTOP_MANIFEST")")
  fi
fi
echo "INSTALL_MODE=$INSTALL_MODE"

# ── Plugin version (from the marketplace clone's own plugin.json) ────
PLUGIN_JSON="$PLUGIN_SRC/.claude-plugin/plugin.json"
PLUGIN_VERSION="n/a"
[ "$PLUGIN_SRC" != "n/a" ] && PLUGIN_VERSION=$(node -e "
  try { process.stdout.write(JSON.parse(require('fs').readFileSync('$PLUGIN_JSON','utf8')).version || 'n/a'); }
  catch(e) { process.stdout.write('n/a'); }
" 2>/dev/null || echo "n/a")

# ── Node + system ────────────────────────────────────────────────────
NODE_VER=$(node --version 2>/dev/null || echo "n/a")
OS_INFO=$(uname -srm 2>/dev/null || echo "n/a")

# ── git HEAD SHA of the marketplace clone (git root is $CLONE, NOT
#    $CLONE/commander — there is no .git one level deeper) ───────────
GIT_SHA="n/a"
[ "$CLONE" != "n/a" ] && GIT_SHA=$(git -C "$CLONE" rev-parse --short HEAD 2>/dev/null || echo "n/a")

# ── Marketplace clone presence ──────────────────────────────────────
if [ "$CLONE" != "n/a" ]; then CLONE_PRESENT="yes — $CLONE"; else CLONE_PRESENT="NO — directory missing"; fi

# ── Temp dirs (mid-clone drift indicator) ───────────────────────────
TEMP_DIRS=$(ls "$HOME/.claude/plugins/marketplaces/" 2>/dev/null | grep '^temp_' | tr '\n' ' ')
if [ -z "$TEMP_DIRS" ]; then TEMP_DIRS="none"; fi

# ── installed_plugins.json ──────────────────────────────────────────
# Shape: { version, plugins: { "<plugin>@<marketplace>": [{ installPath,
# version, installedAt, lastUpdated, gitCommitSha, scope }] } }. installPath
# points into plugins/cache/<mp>/<plugin>/<version>/ — the ACTUAL executing
# copy, distinct from the marketplace source clone above.
INSTALLED_JSON="$HOME/.claude/plugins/installed_plugins.json"
INSTALLED_VERSION="n/a"
INSTALLED_PATH="n/a"
if [ -f "$INSTALLED_JSON" ]; then
  INSTALLED_COMMANDER=$(node -e "
    try {
      const d = JSON.parse(require('fs').readFileSync('$INSTALLED_JSON','utf8'));
      const k = Object.keys(d.plugins||{}).find(k => k.startsWith('commander@'));
      if (k && d.plugins[k][0]) {
        const e = d.plugins[k][0];
        process.stdout.write('found — ' + k + ' v' + e.version + ' @ ' + e.installPath);
      } else {
        process.stdout.write('not found in installed list');
      }
    } catch(e) { process.stdout.write('parse error: ' + e.message); }
  " 2>/dev/null || echo "parse error")
  INSTALLED_VERSION=$(node -e "
    try {
      const d = JSON.parse(require('fs').readFileSync('$INSTALLED_JSON','utf8'));
      const k = Object.keys(d.plugins||{}).find(k => k.startsWith('commander@'));
      process.stdout.write(k && d.plugins[k][0] ? (d.plugins[k][0].version||'n/a') : 'n/a');
    } catch(e) { process.stdout.write('n/a'); }
  " 2>/dev/null || echo "n/a")
  INSTALLED_PATH=$(node -e "
    try {
      const d = JSON.parse(require('fs').readFileSync('$INSTALLED_JSON','utf8'));
      const k = Object.keys(d.plugins||{}).find(k => k.startsWith('commander@'));
      process.stdout.write(k && d.plugins[k][0] ? (d.plugins[k][0].installPath||'n/a') : 'n/a');
    } catch(e) { process.stdout.write('n/a'); }
  " 2>/dev/null || echo "n/a")
else
  INSTALLED_COMMANDER="installed_plugins.json not found"
fi

# ── settings.json sanity ────────────────────────────────────────────
SETTINGS="$HOME/.claude/settings.json"
if [ -f "$SETTINGS" ]; then
  HAS_MARKETPLACE=$(python3 -c "
import json
try:
    d = json.load(open('$SETTINGS'))
    ekm = d.get('extraKnownMarketplaces', [])
    names = [m if isinstance(m, str) else m.get('name','') for m in ekm]
    found = any('commander' in n.lower() for n in names)
    print('yes — commander-hub in extraKnownMarketplaces' if found else 'NO — commander-hub missing')
except Exception as e:
    print('parse error: ' + str(e))
" 2>/dev/null || echo "parse error")

  ENABLED=$(python3 -c "
import json
try:
    d = json.load(open('$SETTINGS'))
    ep = d.get('enabledPlugins', [])
    found = any('commander' in str(p).lower() for p in ep)
    print('yes — commander in enabledPlugins' if found else 'NO — commander not in enabledPlugins')
except Exception as e:
    print('parse error: ' + str(e))
" 2>/dev/null || echo "parse error")
else
  HAS_MARKETPLACE="settings.json not found"
  ENABLED="settings.json not found"
fi

# ── MCP servers (list only, no connectivity test) ───────────────────
MCP_JSON="$PLUGIN_SRC/.mcp.json"
if [ "$PLUGIN_SRC" != "n/a" ] && [ -f "$MCP_JSON" ]; then
  MCP_SERVERS=$(python3 -c "
import json
try:
    d = json.load(open('$MCP_JSON'))
    servers = d.get('mcpServers', {})
    print(', '.join(servers.keys()) if servers else 'none')
except:
    print('parse error')
" 2>/dev/null || echo "n/a")
else
  MCP_SERVERS=".mcp.json not found at $MCP_JSON"
fi

# ── Recent sessions ─────────────────────────────────────────────────
SESSION_DIR="$HOME/.claude/sessions"
if [ -d "$SESSION_DIR" ]; then
  SESSION_COUNT=$(ls "$SESSION_DIR" | wc -l | tr -d ' ')
  LATEST_SESSION=$(ls -t "$SESSION_DIR" 2>/dev/null | head -1 || echo "none")
else
  SESSION_COUNT="0"
  LATEST_SESSION="sessions dir not found"
fi

# ── Update freshness (reuses the SessionStart nudge cache when fresh;
#    falls back to a live check via the shared update-check module) ──
REMOTE_VERSION="n/a"
if [ "$CLONE" != "n/a" ]; then
  REMOTE_VERSION=$(node "$CLONE/commander/update-check.js" --remote-only 2>/dev/null || echo "n/a")
fi
VERSION_STATUS="unknown — could not reach update server"
if [ "$REMOTE_VERSION" != "n/a" ] && [ "$INSTALLED_VERSION" != "n/a" ]; then
  VERSION_STATUS=$(node -e "
    const a='$REMOTE_VERSION'.split('.').map(Number), b='$INSTALLED_VERSION'.split('.').map(Number);
    let gt=false;
    for(let i=0;i<3;i++){ if((a[i]||0)>(b[i]||0)){gt=true;break;} if((a[i]||0)<(b[i]||0))break; }
    process.stdout.write(gt ? 'UPDATE AVAILABLE: $INSTALLED_VERSION -> $REMOTE_VERSION' : 'up to date ($INSTALLED_VERSION)');
  " 2>/dev/null || echo "unknown")
fi

# ── Installed-executable-copy cache: cache/<mp>/commander/<version>/ ─
# No auto-clean — old versions linger. List them, flag if more than one.
CACHE_ROOT="$HOME/.claude/plugins/cache/commander-hub/commander"
CACHE_VERSIONS="none"
CACHE_VERSION_COUNT=0
if [ -d "$CACHE_ROOT" ]; then
  CACHE_VERSIONS=$(ls "$CACHE_ROOT" 2>/dev/null | sort -V | tr '\n' ',' | sed 's/,$//')
  CACHE_VERSION_COUNT=$(ls "$CACHE_ROOT" 2>/dev/null | wc -l | tr -d ' ')
  [ -z "$CACHE_VERSIONS" ] && CACHE_VERSIONS="none"
fi

# ── Desktop inline copy (bypasses the marketplace clone on some installs) ─
INLINE_DIR="$HOME/.claude/plugins/data/commander-inline"
INLINE_PRESENT="no"
INLINE_VERSION="n/a"
if [ -d "$INLINE_DIR" ]; then
  INLINE_PRESENT="yes"
  INLINE_VERSION=$(node -e "
    try { process.stdout.write(JSON.parse(require('fs').readFileSync('$INLINE_DIR/.claude-plugin/plugin.json','utf8')).version || 'n/a'); }
    catch(e) { process.stdout.write('n/a (present but no cached plugin.json found)'); }
  " 2>/dev/null || echo "n/a")
fi

# ── Plugin catalog cache age (Desktop's marketplace listing cache) ───
CATALOG_CACHE="$HOME/.claude/plugins/plugin-catalog-cache.json"
CATALOG_AGE_HOURS="n/a"
if [ -f "$CATALOG_CACHE" ]; then
  CATALOG_AGE_HOURS=$(node -e "
    try { process.stdout.write(String(Math.floor((Date.now()-require('fs').statSync('$CATALOG_CACHE').mtimeMs)/3600000))); }
    catch(e) { process.stdout.write('n/a'); }
  " 2>/dev/null || echo "n/a")
fi

# ── autoUpdate flag for commander-hub ─────────────────────────────────
KNOWN_MARKETPLACES="$HOME/.claude/plugins/known_marketplaces.json"
AUTOUPDATE_FLAG="n/a"
if [ -f "$KNOWN_MARKETPLACES" ]; then
  AUTOUPDATE_FLAG=$(node -e "
    try {
      const j = JSON.parse(require('fs').readFileSync('$KNOWN_MARKETPLACES','utf8'));
      const m = j['commander-hub'];
      process.stdout.write(m ? String(!!m.autoUpdate) : 'not-registered');
    } catch(e) { process.stdout.write('n/a'); }
  " 2>/dev/null || echo "n/a")
else
  AUTOUPDATE_FLAG="known_marketplaces.json not found"
fi

# ── Output ───────────────────────────────────────────────────────────
echo "PLUGIN_VERSION=$PLUGIN_VERSION"
echo "NODE_VER=$NODE_VER"
echo "OS_INFO=$OS_INFO"
echo "GIT_SHA=$GIT_SHA"
echo "CLONE_PRESENT=$CLONE_PRESENT"
echo "TEMP_DIRS=$TEMP_DIRS"
echo "INSTALLED_COMMANDER=$INSTALLED_COMMANDER"
echo "INSTALLED_VERSION=$INSTALLED_VERSION"
echo "INSTALLED_PATH=$INSTALLED_PATH"
echo "HAS_MARKETPLACE=$HAS_MARKETPLACE"
echo "ENABLED=$ENABLED"
echo "MCP_SERVERS=$MCP_SERVERS"
echo "SESSION_COUNT=$SESSION_COUNT"
echo "LATEST_SESSION=$LATEST_SESSION"
echo "REMOTE_VERSION=$REMOTE_VERSION"
echo "VERSION_STATUS=$VERSION_STATUS"
echo "CACHE_VERSIONS=$CACHE_VERSIONS"
echo "CACHE_VERSION_COUNT=$CACHE_VERSION_COUNT"
echo "INLINE_PRESENT=$INLINE_PRESENT"
echo "INLINE_VERSION=$INLINE_VERSION"
echo "CATALOG_AGE_HOURS=$CATALOG_AGE_HOURS"
echo "AUTOUPDATE_FLAG=$AUTOUPDATE_FLAG"

Read the full file on GitHub · 521 lines

Files

What ships with it

1 file beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 7d ago First seen · 521 lines · 40 tokens per session scan D d579c36ae327

Subscribe to this mod's changes

ccc-doctor is a skill published in the GitHub repository KevinZai/commander (6 stars, last pushed today), licensed MIT. It adds 40 tokens to every session and 6,637 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it D with 2 findings (reads agent configuration directories, recursive force delete). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.

Related

Other skills, from other repositories

systematic-debugging

Use before proposing a permanent fix for bugs, test failures, or unexpected behavior with an unknown root cause—mandatory when symptoms are far from the cause, a prior fix failed, or the issue crosses components. Reproduce, trace backward to the root cause, fix once at the source, and add a regression test. Do not…

chipfighter/coding-discipline · 92 tokens

performance-profiler

Tier: POWERFUL Category: Engineering Domain: Performance Engineering.

nariatrip191/my-claude-skills · 7 tokens

advisor-strategy

Use when facing complex architectural decisions, debugging dead-ends, high-stakes code changes, security reviews, performance optimization, or when the user explicitly requests advisor consultation. Also use when context is growing large and needs management, or when a second opinion from a more capable model would…

aivsomkar/advisor-strategy-skill · 88 tokens

sandbox-unblock

Diagnostic protocol to run before reporting a sandbox blocker or asking for a configuration change. Eight checks that eliminate false positives, then a report template the person holding the settings can act on. On one measured day, six of eight reported blockers turned out to be false, all from the same handful of…

FlorianBruniaux/claude-code-ultimate-guide · 65 tokens

mcp-check

Validate MCP configuration and suggest improvements. Use when MCP servers fail to load, after editing .mcp.json, or when the user runs /mcp-check.

claude-world/director-mode-lite · 36 tokens

systematic-debugging

Use when debugging, diagnosing, or investigating any bug, test failure, flaky test, race condition, unexpected behavior, build failure, production incident, third-party breakage, root cause analysis, or performance regression before proposing fixes.

johnqtcg/awesome-skills · 49 tokens