Claude Codeのスキル使用回数はセッションログから数えられるのか調べた
Claude Codeのスキル使用回数はセッションログから数えられるのか調べた
「スキルの使用回数って ~/.claude/projects/<project>/<session-id>.jsonl のトランスクリプトから取得できるんじゃないか」と思いつき、実際に調べてみた。対象は2026-06-05〜2026-07-22の48日間、全54プロジェクト・1,273セッションのログ。結論から言うと取得できるが、記録経路が1つではなく3つあり、どれか1つだけを数えると実態を大きく取りこぼす。
結論
- Claudeが自分の判断でSkillツールを呼び出したイベントは、メインの
.jsonl内にtool_useとして記録される。この経路だけで776件検出できた - ユーザーが
/skill-nameとスラッシュコマンド形式で明示的に呼び出した場合は、Skillツールのtool_useとは別の記録形式になる。同じ.jsonl内だが、<command-name>タグを含むユーザーメッセージとして残る - Agent tool(サブエージェント)経由で起動されたエージェントが内部でSkillを呼んだ場合は、メインの
.jsonlには一切現れず、<session-id>/subagents/agent-*.jsonlという別ファイル群にのみ記録される。手元のmdx-playgroundプロジェクトだけで検証したところ、この経路だけでメイン会話とほぼ同数(602件 vs 637件)あった
つまりメインの.jsonlだけを見ていると、実際のスキル使用量の半分近くを見落とす可能性がある。
3つの記録経路
経路A: Skillツール呼び出し
Claudeが自然文の指示やSKILL.mdのトリガー条件に反応して、自分の判断でSkillツールを呼んだケース。メインの.jsonl内、type:"assistant"のメッセージのmessage.content[]にtool_useとして記録される。
{"type":"tool_use","name":"Skill","input":{"skill":"earnings-beat-scan","args":"from_date=2026-06-09 to_date=2026-06-10"},"caller":{"type":"direct"}}
input.skillにスキル名、input.argsに引数が入る。抽出は次のjqで十分。
jq -r 'select(.type=="assistant") | .message.content[]? |
select(.type=="tool_use" and .name=="Skill") | .input.skill' session.jsonl
経路B: スラッシュコマンド
ユーザーが/add-tickerのように明示的にスラッシュコマンドを打った場合の記録。同じ.jsonl内だが、type:"user"のメッセージのcontent(文字列)に、コマンド名がタグとして展開されて埋め込まれる。
<command-message>add-ticker</command-message>
<command-name>/add-ticker</command-name>
<command-args>AMAT</command-args>
これは経路AのSkillツール呼び出しとは完全に別のイベントなので、経路Aのjqだけを回しても一切ヒットしない。存在に気づかず、スラッシュコマンドで呼んでいるスキルの使用実績が丸ごと抜け落ちる。
jq -r 'select(.type=="user") |
(if (.message.content|type)=="string" then .message.content
else (.message.content // [] | map(select(.type=="text").text) | join("\n")) end) |
scan("<command-name>/([^<]+)</command-name>")' session.jsonl
経路C: サブエージェント内のSkill呼び出し
Agent toolやWorkflowで起動したサブエージェントが、その内部でさらにSkillツールを呼ぶケース。この呼び出しはメインの.jsonlには一切残らず、セッションIDと同名のディレクトリのsubagents/配下に、エージェントごとに別ファイルとして記録される。
~/.claude/projects/<project>/<session-id>/subagents/agent-a23e4....jsonl
中身の構造は経路Aと同じ(tool_useでname=="Skill")なので、抽出クエリ自体は使い回せる。問題は「そもそもこのファイル群を集計対象に含めないと存在にすら気づけない」ことにある。
実測してみた
全54プロジェクト・1,273セッションのメイン会話ログ(経路A)を走査した結果。
| スキル | 件数 |
|---|---|
| doc-communication | 120 |
| content-management | 117 |
| svg-diagram | 92 |
| learn | 49 |
| earnings-beat-scan | 42 |
| honda-sakubun | 37 |
| commit | 30 |
| qa-verification | 27 |
| その他46スキル | 262 |
合計776件、うち82%(637件)がmdx-playgroundでの利用だった。月別では6月340件、7月436件(22日時点)と増加している。learnスキルが6月0件から7月49件に急増していたのは、学習ゲート導入(2026-07-06〜)の時期とちょうど一致しており、この計測方法が実際の運用変化を正しく捉えていることの裏付けになった。
サブエージェント分はメイン会話とほぼ同規模だった
全プロジェクトのサブエージェントまで含めると容量が大きく(mdx-playground単体で687MB・1,658ファイル)、走査に時間がかかる。そこでmdx-playground 1プロジェクトに絞って経路Cも集計してみた。
| 記録経路 | 件数 |
|---|---|
| メイン会話(経路A) | 637 |
| サブエージェント内(経路C) | 602 |
ほぼ同数だった。サブエージェント側のスキル別内訳はcontent-management(209件)とvivid-writing(199件)が突出していて、これは/make-diaryが日記記事を並列サブエージェントで生成する際、各エージェントがfrontmatter整形とvivid-writing(描写変換)を毎回呼んでいることに起因していそうだ。メイン会話側ではmake-diary自体はスラッシュコマンド(経路B)として45回起動されているだけなので、経路Aだけを見ているとmake-diary実行のたびに起きているはずのcontent-management呼び出しがほとんど見えない。
スラッシュコマンドは大半がビルトインCLI操作だった
経路Bで検出した621件のうち、/clear(422件)・/model(50件)・/effort(23件)・/login(16件)・/mcp(4件)など、Claude Code組み込みのCLI操作が518件(83%)を占めた。プロジェクト固有のスキル・カスタムコマンド起動は残り103件で、内訳は/make-diary(45件)、/import-batch(14件)、/learn(6件)、/add-ticker(6件)などだった。
制限事項
- サブエージェント分の全プロジェクト走査はしていない。今回はmdx-playground 1プロジェクトのサンプルで「メイン会話だけでは取りこぼす」ことを確認したに留まる
caller.typeフィールド(経路Aの776件中770件が"direct"、6件が"unknown")の意味は今回の調査では特定できていない- 組み込みコマンドかスキルかの判別は名称からの目視分類で、
/goalや/contextのように一覧に見当たらず未分類のまま残したものもある - ログの保持期間や手動削除の影響を受けるため、今回の集計期間(2026-06-05〜2026-07-22)より前の実績は把握できない
まとめ
「トランスクリプトからスキル使用回数を数えられるか」という問い自体には、素朴にYesと答えられる。ただしその数字が「全部」だと思ってしまうと足元をすくわれる。Skillツールのtool_useだけを拾う集計は、少なくとも自分の環境では実態の半分近くを見落としていた。正確な利用実態を知りたいなら、メインの.jsonl・スラッシュコマンドのタグ・サブエージェントのsubagents/配下という3箇所を突き合わせる必要がある。