はじめに
Claude Codeを使い込んでいくと、こんなモヤモヤにぶつかることはないでしょうか。
- CLAUDE.mdにルールを書き足していったら、いつのまにかコンテキストがパンパンに…
- サブエージェント、Skills、Hooks…名前は聞くけど、結局どれを使えばいいのか分からない
- 公式ドキュメントを読んでも、実践的な使い分けのイメージがなかなか湧いてこない
私自身も同じところでつまずいたので、自分なりに整理してみました。
Claude Codeには、プロジェクトに合わせて挙動をカスタマイズするための機能が、ざっくり6つあります。
CLAUDE.md.claude/rules/- カスタムスラッシュコマンド
- サブエージェント
- Skills
- Hooks
正直、最初はどれも似たようなものに見えて混乱していました。でも「いつ読み込まれるか」「誰が実行するか」という2つの軸で見てみると、意外とすっきり整理できることに気づいたので、今回はその視点でまとめてみます。
まずは全体像から
結論を先に置いておきます。
| 機能 | 読み込まれるタイミング | 動作主体 | コンテキストへの影響 |
|---|---|---|---|
| CLAUDE.md | セッション開始時に常に読み込み | Claude(メイン) | 常に消費し続ける |
| .claude/rules/ | 条件(パス等)に一致した時だけ | Claude(メイン) | 必要な時だけ消費 |
| カスタムコマンド |
/command実行時だけ |
Claude(メイン) | 実行時だけ消費 |
| サブエージェント | Taskツールで呼び出された時 | 独立したClaudeインスタンス | メインのコンテキストは汚さない |
| Skills | タスク内容に応じてClaudeが判断 | Claude(メイン/サブ) | 必要な階層だけ段階的に消費 |
| Hooks | 特定のイベント発火時(確定的) | シェルスクリプトなど(Claudeを介さない) | コンテキストをほぼ消費しない |
表の上から下にいくにつれて、「常時ロードされるもの」から「必要な時だけ呼ばれるもの」に変わっていき、最後は「Claudeの判断すら介さない、機械的な自動化」に行き着く、という流れになっています。この流れさえ頭に入れておくと、「今書こうとしているこのルール、本当にCLAUDE.mdに常駐させる必要があるかな?」と、自然に立ち止まって考えられるようになります。
判断の目安として、こんなフローで考えるとイメージしやすいかもしれません。
そのルールは全タスクで常に必要か?
├─ Yes → CLAUDE.md
└─ No
├─ 特定のファイル/ディレクトリを触る時だけ必要か? → .claude/rules/
├─ 自分が明示的に呼び出す定型作業か? → カスタムコマンド
├─ 独立した文脈で調査・実装させたいか? → サブエージェント
├─ 複雑な手順・参照資料をまとめて持たせたいか? → Skills
└─ 「〇〇したら必ず××する」を保証したいか? → Hooks
それでは、1つずつゆっくり見ていきましょう。
1. CLAUDE.md - プロジェクト知識の土台
CLAUDE.mdは、プロジェクトのルートに置いておく、いわば「Claude Codeへの申し送りメモ」のようなものです。セッションが始まると自動的に読み込まれ、それ以降のやり取りすべてにじわっと影響を与え続けます。
ゼロから書き始めるのが大変な場合は、/initコマンドを試してみるとよいと思います。既存のコードベースを解析して、CLAUDE.mdの雛形をある程度自動生成してくれます。
/init
メモリ階層
意外と知られていないのですが、CLAUDE.mdは1箇所だけでなく、優先順位を持ついくつかの階層に分けて置くことができます。
| 優先度 | 配置場所 | 用途 |
|---|---|---|
| 高 | ./CLAUDE.local.md |
個人用のメモ(Git管理外) |
| 高 | ./CLAUDE.md |
プロジェクト共通のルール |
| 中 | 親ディレクトリのCLAUDE.md
|
モノレポ全体の共通ルール |
| 低 | ~/.claude/CLAUDE.md |
自分のマシン全体のグローバル設定 |
個人的なメモとチーム共有のルールを分けられるのは、地味にありがたいポイントです。
効果的な書き方
CLAUDE.mdでついやってしまいがちなのが、「精神論っぽい」書き方になってしまうことです。
❌ こういう書き方だと伝わりにくい
- コードは綺麗に書いてください
- テストはちゃんと書いてください
✅ こんなふうに具体的にしてみると伝わりやすい
- 関数は1つの責務のみを持たせ、30行を超えたら分割を検討する
- 新規APIエンドポイントを追加したら、必ず`tests/api/`配下に対応するテストを追加する
「守れたかどうかClaude自身が判断できる」くらいの粒度で書いてあげると、意図が伝わりやすくなる印象です。とはいえ、これを突き詰めていくと今度は「あれもこれも」とルールが増えていき、冒頭で触れたコンテキスト肥大化の問題にぶつかります。そこで頼りになるのが、次に紹介する.claude/rules/です。
2. .claude/rules/ によるルールのモジュール化
CLAUDE.mdが膨れ上がってしまう典型パターンは、「フロントエンドだけのルール」や「特定のバッチ処理だけのルール」まで、なんでもかんでもCLAUDE.mdに書き込んでしまうことだと思います。これをうまく解決してくれるのが.claude/rules/ディレクトリです。
.claude/
└── rules/
├── frontend.md
└── backend-api.md
各ルールファイルにはフロントマターでpaths(Globパターン)を指定でき、該当するファイルを触っている時だけ、そっと読み込まれる仕組みになっています。
---
description: "フロントエンドコンポーネントのルール"
paths:
- "src/components/**/*.tsx"
- "src/pages/**/*.tsx"
---
# フロントエンドルール
- コンポーネントは関数コンポーネント + TypeScriptで統一する
- スタイルはCSS Modulesを使用し、インラインstyleは禁止
---
description: "バックエンドAPIのルール"
paths:
- "src/api/**/*.ts"
---
# API実装ルール
- 全エンドポイントで入力値のZodバリデーションを必須とする
- エラーレスポンスは共通のErrorResponse型に統一する
こうしておくと、フロントエンドを触っている間はバックエンドのルールがコンテキストに乗ってこないですし、逆もまた然りです。ざっくりとした方針としては、「常に知っておいてほしいこと」はCLAUDE.mdへ、「その領域を触る時だけ知っていればいいこと」は.claude/rules/へ、くらいの感覚で振り分けていくとうまくいきやすいです。
3. カスタムコマンド - プロンプトのショートカット化
.claude/commands/配下にMarkdownファイルを置いておくと、/ファイル名でスラッシュコマンドとして呼び出せるようになります。何度も同じような指示を出している作業があれば、テンプレート化してしまうと結構楽になります。
.claude/
└── commands/
└── review-pr.md
---
description: "指定したPR番号の差分をレビューする"
allowed-tools: ["Bash(gh pr diff:*)", "Read"]
---
以下のPRの差分を確認し、セキュリティ・可読性・パフォーマンスの観点でレビューしてください。
PR番号: $1
重点的に見てほしい観点: $2
!`gh pr diff $1`
フロントマターのallowed-toolsでは、このコマンド実行時に使ってよいツールを絞り込めます。地味に安心感のある設定項目です。
引数パターン
引数の受け取り方は2種類あります。好みや用途に応じて選べます。
-
$ARGUMENTS: 呼び出し時の引数をまるごと1つの文字列として受け取る -
$1$2$3: 位置引数として個別に受け取る(上の例の/review-pr 123 "型安全性"のような呼び出しに対応)
プレフィックス記法
コマンド本文の中では、2つの特殊なプレフィックスも使えます。
-
@プレフィックス:@src/config.tsのようにファイルを直接指定して、その内容を埋め込む -
!プレフィックス:!`gh pr diff $1`のようにBashコマンドを実行して、その結果を埋め込む
この2つを組み合わせると、「PR番号を渡すだけで、差分取得からレビューまで一気に進む」といった、ちょっと便利なコマンドが作れます。
4. サブエージェント - 独立したコンテキストを使う
サブエージェントは、メインの会話とは別のコンテキストウィンドウを持つ、いわば専門特化型のClaudeです。.claude/agents/配下にMarkdownファイルを置いて定義するほか、/agentsコマンドから対話的に作ることもできます。
.claude/
└── agents/
└── test-runner.md
---
name: test-runner
description: "テストの実行と失敗原因の調査に使用する。テストが落ちた時に積極的に使うこと。"
tools: ["Bash", "Read", "Edit"]
---
あなたはテスト専門のエージェントです。
テストを実行し、失敗した場合は原因を特定して修正案を提示してください。
無関係なリファクタリングは行わないでください。
うれしいのは、大量の調査ログやテスト出力が、メインの会話のコンテキストを圧迫しないところです。たとえば「大きなログを読んで、原因を一言でまとめて報告する」ようなタスクをサブエージェントに任せてしまえば、ログの中身自体はサブエージェント側のコンテキストで完結し、メインの会話には要約だけがすっと返ってきます。
ただし裏を返すと、サブエージェントは呼ばれるたびに新しいコンテキストからスタートするので、それまでの会話の流れは共有されません。「独立した調査タスクをいくつも並行で走らせたい」場合には向いていますが、「これまでの細かいやり取りを踏まえた微調整をしてほしい」場合には、あまり得意ではない印象です。
5. Skills - 必要な時に必要な分だけ読み込む
Skillsは、「レシピ本」に例えるとイメージしやすい機能だなと感じています。レシピ本って、普段は本棚にしまってあって、必要な時だけ取り出して該当のページを開きますよね。Skillsもそれと似ていて、普段はdescription(概要)だけが認識されていて、タスクの内容にマッチしそうだとClaudeが判断した時に、はじめて本体の内容が読み込まれます。
この仕組みはProgressive Disclosure(段階的開示)と呼ばれていて、だいたい3つの層に分かれています。
-
メタデータ層:
descriptionだけが常に軽くロードされている -
本体層: 実際にSkillが呼ばれたタイミングで
SKILL.md本体が読み込まれる -
詳細資料層:
SKILL.mdから参照されるreference.mdやscripts/は、さらに必要になった時だけ読み込まれる
.claude/
└── skills/
└── pdf-report/
├── SKILL.md
├── reference.md
└── scripts/
└── generate_report.py
---
name: pdf-report
description: "PDF形式のレポートを生成する際に使用する。ユーザーがPDF出力や帳票作成を依頼した時にトリガーする。"
---
# PDFレポート生成
`scripts/generate_report.py`を使ってPDFレポートを生成してください。
テンプレートのカスタマイズ方法は`reference.md`を参照してください。
## 基本的な使い方
\`\`\`bash
python scripts/generate_report.py --input data.json --output report.pdf
\`\`\`
詳細なオプションについては reference.md を確認してください。
ここで結構大事だなと感じたのが、descriptionの書き方です。「いつ、どんな時に使うべきか」がClaude自身にも伝わるくらい具体的に書いてあげないと、せっかく用意したSkillがなかなか呼ばれない、ということが起こりがちです。カスタムコマンドが「人間が明示的に呼ぶ」ものだとすると、Skillsは「Claudeが自分で選ぶ」もの、というイメージを持っておくと、区別がつけやすくなると思います。
6. Hooks - 確実に守らせたいことは仕組みに任せる
ここまで紹介してきた5つの機能は、どれも最終的にはClaudeの推論を通って実行されるので、いわば確率論的です。CLAUDE.mdに「コミット前に必ずlintを実行して」と書いても、Claudeがうっかり忘れてしまう可能性はゼロではありません(人間も同じですよね)。
一方でHooksは、特定のイベントが発生したタイミングで、Claudeを介さずに決められたシェルコマンドを機械的に実行する、決定論的な仕組みです。「絶対に守ってほしいルール」があるなら、Hooksに任せてしまうのが一番確実だと思います。
主なフックイベントは、次の10種類ほどあります。
| イベント | タイミング |
|---|---|
PreToolUse |
ツール実行前 |
PostToolUse |
ツール実行後 |
UserPromptSubmit |
ユーザーがプロンプトを送信した時 |
Stop |
メインエージェントが応答を完了した時 |
SubagentStop |
サブエージェントが応答を完了した時 |
Notification |
通知が発生した時 |
PreCompact |
コンテキスト圧縮の直前 |
SessionStart |
セッション開始時 |
SessionEnd |
セッション終了時 |
| その他(バージョンにより追加されることも) | - |
設定は.claude/settings.json(またはユーザー設定)に書きます。たとえば「TypeScriptファイルを編集したら、必ずESLintを自動実行する」場合は、こんな感じになります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\""
}
]
}
]
}
}
matcherにはツール名の正規表現(この例ではEditかWrite)を指定して、対象を絞り込みます。CLAUDE.mdに「編集したらlintしてね」とお願いするより、こちらの方がずっと確実ですし、コンテキストもほとんど使いません。
まとめ
長くなりましたが、改めて6つの機能を「読み込まれるタイミング」「動作主体」という軸で振り返ってみると、こんなふうに整理できそうです。
-
常にプロジェクト全体で必要な、最小限のルール →
CLAUDE.md -
特定のパスや領域を触る時だけ必要なルール →
.claude/rules/ - 自分がその都度、明示的に呼び出したい定型作業 → カスタムコマンド
- 独立した文脈でまとめて調査・実装させたい作業 → サブエージェント
- 複雑な手順書やスクリプトを、必要な時だけそっと渡したい知識 → Skills
- 確率に頼らず、絶対に守らせたい自動化 → Hooks
「とりあえず全部CLAUDE.mdに書いておく」というやり方から一歩進んで、この6つを場面ごとにうまく組み合わせられるようになると、コンテキストを無駄に消費せず、しかも再現性の高い、自分だけの「専用アシスタント」に育てていけると思います。ぜひ手元のプロジェクトで、今のCLAUDE.mdを見直すところから、気軽に試してみてください。