はじめに:スキルは増えるが、減らす仕組みがなかった
当社(合同会社ジョインクラス)は、Claude Codeを「AI経営チーム」として運用しています。17のサブエージェントと13のカスタムスキルが .claude/ 配下に住んでおり、launchdから1日40本以上のヘッドレス実行が走ります。
スキルは便利です。/write-qiita を打てば記事ができ、/publish-kindle を打てばEPUB検査からKDP登録プロンプトまで一気に進む。だから増えます。問題は減らす判断材料がどこにもなかったことです。
筆者は「コンテキスト使用率を10〜15%に維持する」というThin Orchestrator原則をCLAUDE.mdに書いています。ところが、13スキルが毎セッションどれだけコンテキストを食っているか、実測する手段がありませんでした。原則だけあって計器がない状態です。
Claude Code 2.1.261で入った /skill-doctor は、まさにこの計器です。本記事では、/skill-doctor の読み方と、その結果を踏まえて当社で実際に動かしているチェックスクリプト、そして棚卸しを自動化した手順を紹介します。
/skill-doctor が何を見せてくれるか
/skill-doctor は対話セッション内で実行するスラッシュコマンドです。やることは単純で、現在ロードされている全スキルについて、
- 直近のセッションで呼び出されたか(未使用かどうか)
- そのスキルがコンテキストに載せている概算トークン量
-
frontmatterの不備(
descriptionがない・長すぎる、nameとディレクトリ名の不一致)
を一覧にします。ポイントは「未使用」と「コスト」を同じ表で見せてくれることです。使っていないのに重いスキルが即座に浮かび上がります。
実行前に確認すること
/skill-doctor は 2.1.261以降でないと存在しません。当社では、これが大きな落とし穴でした。
claude --version
# 2.1.261 未満なら以下で更新
claude update
当社の /upgrade-automation スキルは毎週Changelogを読んで新機能を提案するのですが、ある週の提案5件が全て本体更新を前提にしていたにもかかわらず「即実施可」と判定していました。設定ファイルを書き換えても一切効果がない状態で2週間放置されました。新機能を試す前に、まず自分のバージョンが要件を満たしているか確認してください。
読み方
実行すると、おおよそ次のような表が出ます(当社の実行結果を要約)。
| スキル | 最終使用 | 概算トークン | 診断 |
|---|---|---|---|
| validate-hypothesis | 12日前 | 約7,400 | 未使用・最大 |
| write-note | 1日前 | 約3,200 | OK |
| publish-kindle | 31日前 | 約2,300 | 未使用 |
| format-kindle-epub | 31日前 | 約1,900 | 未使用 |
| convert-to-epub | 31日前 | 約1,600 | 未使用 |
| write-qiita | 0日前 | 約1,800 | OK |
validate-hypothesis のSKILL.mdは29KBあります。6フェーズの仮説検証フレームワークを丸ごと1ファイルに書いているからで、新規事業の提案があったときにしか動きません。それが毎セッションロードされていた。これが筆者にとって最大の発見でした。
自前で診断する:スキル健全性チェックスクリプト
/skill-doctor は対話セッションでしか動きません。当社のようにlaunchdでヘッドレス運用している環境では、「月1回Slackに健全性レポートが飛ぶ」形にしたい。そこで、既存の月次品質チェック auto-agent-health-check.sh にスキル診断を組み込みました。
元のスクリプトにあったバグ
まず、既存スクリプトの該当箇所です。
AGENT_COUNT=$(ls "$AGENTS_DIR"/*.md 2>/dev/null | wc -l | tr -d '[:space:]')
SKILL_COUNT=$(ls "$SKILLS_DIR"/*.md 2>/dev/null | wc -l | tr -d '[:space:]')
エージェントは .claude/agents/foo.md と平置きですが、スキルは .claude/skills/foo/SKILL.md とディレクトリ構造です。このglobでは SKILL_COUNT が常に0になります。月次レポートに「スキル: 0個」と出続けていたのに、誰も気づかなかった。Slackに流れる数字を人間が読んでいない証拠でもあります。
/skill-doctor が13スキルを列挙してくれたことで、自前レポートの0とのズレに初めて気づきました。公式ツールの出力と自前の計測を突き合わせるのは、こういう沈黙バグを掘り出す上で有効です。
修正版:スキル健全性チェック
修正したスクリプトの主要部分です。common.sh(ログ・Slack通知・.env 読込の共通ヘルパー)をsourceする当社の標準形に合わせています。
#!/bin/bash
# .company/scripts/auto-skill-health.sh
# 月1回: スキルのサイズ・frontmatter・最終使用日を診断してSlack通知
source "$(dirname "$0")/common.sh"
load_env
SKILLS_DIR="$PROJECT_ROOT/.claude/skills"
STATE_LOG="$LOG_DIR/skill-usage.tsv" # PostToolUse hookが追記する使用ログ
SIZE_WARN_BYTES=10000 # 10KB超は要分割候補
UNUSED_WARN_DAYS=30
touch "$STATE_LOG"
NOW=$(date +%s)
REPORT=""
TOTAL_BYTES=0
for skill_md in "$SKILLS_DIR"/*/SKILL.md; do
dir="$(basename "$(dirname "$skill_md")")"
bytes=$(wc -c < "$skill_md" | tr -d '[:space:]')
TOTAL_BYTES=$((TOTAL_BYTES + bytes))
# 日本語混在なので「バイト数/3」をトークン概算とする
est_tokens=$((bytes / 3))
name=$(awk -F': *' '/^name:/{print $2; exit}' "$skill_md")
desc_len=$(awk -F': *' '/^description:/{print length($2); exit}' "$skill_md")
issues=""
[ "$name" != "$dir" ] && issues="${issues} name≠dir"
[ -z "$desc_len" ] && issues="${issues} descなし"
[ "${desc_len:-0}" -gt 200 ] && issues="${issues} desc長すぎ(${desc_len})"
[ "$bytes" -gt "$SIZE_WARN_BYTES" ] && issues="${issues} ${bytes}B要分割"
last_used=$(awk -v s="$dir" -F'\t' '$2==s{t=$1} END{print t}' "$STATE_LOG")
if [ -n "$last_used" ]; then
days=$(( (NOW - last_used) / 86400 ))
[ "$days" -gt "$UNUSED_WARN_DAYS" ] && issues="${issues} ${days}日未使用"
else
issues="${issues} 使用記録なし"
fi
[ -n "$issues" ] && REPORT="${REPORT}- ${dir} (~${est_tokens}tok):${issues}\n"
done
SKILL_COUNT=$(ls "$SKILLS_DIR"/*/SKILL.md | wc -l | tr -d '[:space:]')
MSG="[スキル健全性 $(date +%Y-%m)] ${SKILL_COUNT}スキル / 合計${TOTAL_BYTES}B (~$((TOTAL_BYTES / 3))tok)\n"
if [ -n "$REPORT" ]; then
MSG="${MSG}\n要対応:\n${REPORT}"
else
MSG="${MSG}\n全スキル正常"
fi
log_info "$MSG"
notify_slack "$MSG"
notify_slack と log_info は common.sh 側の関数です。SLACK_WEBHOOK_URL が未設定なら通知をスキップしてログだけ残すので、まずは手元で bash auto-skill-health.sh と叩いて標準出力を眺めるところから始められます。
使用ログを取る:PostToolUse hook
上のスクリプトは「最終使用日」を skill-usage.tsv から読んでいます。これはClaude Code側のhookで書き込みます。.claude/settings.json に次を追加してください。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Skill",
"hooks": [
{
"type": "command",
"command": "jq -r '[(now|floor), .tool_input.skill] | @tsv' >> \"$CLAUDE_PROJECT_DIR/.company/scripts/logs/skill-usage.tsv\""
}
]
}
]
}
}
Skill ツールが呼ばれるたびに「UNIX秒 \t スキル名」が1行追記されます。これで /skill-doctor が見せる「最終使用」を、ヘッドレス実行を含む全セッション横断で持てるようになります。
落とし穴: hookは settings.json を編集した後、新しいセッションから有効になります。既存セッションで /write-qiita を叩いても記録されず「hookが動かない」と30分悩みました。
診断結果をどう扱ったか
/skill-doctor と自前スクリプトの結果を突き合わせ、当社では次の3分類で処理しました。
1. 分割する:validate-hypothesis(29KB)
6フェーズを1ファイルに書いていたので、SKILL.md本体は「いつ使うか」と「フェーズ一覧」だけの約2KBに縮め、各フェーズの詳細は references/phase-N.md に逃がしました。Claude Codeのスキルは本体が常時ロードされ、参照ファイルは必要時にReadされるため、これだけで常時コストが約7,400トークンから約700トークンに落ちます。
.claude/skills/validate-hypothesis/
├── SKILL.md # 2KB: 起動条件 + フェーズ目次
└── references/
├── phase-1-origin.md
├── phase-2-market.md
└── ...
2. 残す:出版3スキル(convert-to-epub / format-kindle-epub / publish-kindle)
31日未使用でしたが、Kindle出版は月1回あるかないかの頻度で、使うときは3つ連鎖で動きます。削除すると次回出版時に再作成コストがかかるので残しました。ただし description を短く削り、合計約5,800トークンを約4,000トークンに圧縮しています。
判断基準: 「使用頻度が低い」だけでは消さない。「次に使うときの再構築コスト」と「毎セッションのロードコスト×セッション数」を比べる。当社は1日40セッション走るので、1,000トークン削ると月120万トークンの差になります。
3. 消す:該当なし
今回はゼロでした。13スキル全てが過去90日以内に使用記録があり、重複機能もなかった。「消すものがない」という結論も、計器があって初めて自信を持って言えます。
検証方法
変更後に効果が出ているか確かめる手順です。
# 1. スキル本体の合計サイズが減ったか
wc -c .claude/skills/*/SKILL.md | tail -1
# 変更前: 107427 total → 変更後: 約72000 total を目標
# 2. frontmatter不備がゼロか(自前スクリプトを手動実行)
bash .company/scripts/auto-skill-health.sh
# 3. 対話セッションで公式診断と照合
# /skill-doctor を実行し、自前の「要対応」と一致するか確認
# /context でスキルが占める割合が10%台に収まっているか確認
3番目が重要です。自前スクリプトはバイト数からの概算なので、/skill-doctor と /context の実測値と月1回は突き合わせてください。ズレが大きければ概算係数(上のスクリプトでは bytes / 3)を調整します。
運用に組み込む:launchd登録
月1回、月初の朝に走らせます。当社は既に17本のlaunchdジョブがあり、新規追加は慎重にしていますが、これは既存の auto-agent-health-check.sh から呼ぶ形にしてジョブ数を増やさず組み込みました。
# auto-agent-health-check.sh の末尾に1行追加
bash "$SCRIPT_DIR/auto-skill-health.sh" || true
|| true を付けているのは、スキル診断が失敗しても親の月次レポートを止めないためです。診断系は「本体の邪魔をしない」のが原則です。
まとめ
-
/skill-doctorは未使用スキルとそのコンテキストコストを同じ表で見せる計器。2.1.261以降が必要 - 公式の出力と自前計測を突き合わせると、「スキル数0」のような沈黙バグが見つかる
- 結果は「分割 / 残す / 消す」の3分類で処理する。頻度だけでなく再構築コストとロードコスト×セッション数で判断する
- 使用ログは
PostToolUsehookでSkillツールを捕まえれば、ヘッドレス実行も含めて取れる
スキルは「作る」より「育てる・刈る」の方が難しい。原則を書くだけでなく、原則を計測する手段を持つこと。/skill-doctor はその最初の一歩として十分な道具でした。
書籍のご案内
本記事で触れたスキルの設計(SKILL.md本体と references/ の分割、description の書き方、frontmatterの規約)は、当社の『Claude Skills 完全ガイド』で体系的に解説しています。スキルを「とりあえず作る」段階から「組織で運用する」段階に進みたい方に向けて書きました。
hookやlaunchdによる無人運用の全体像は『Claude Code 全自動化バイブル』、コンテキスト予算の設計は『CLAUDE.md設計パターン』で扱っています。あわせてご覧ください。