コーディングエージェントの「指示書・Skill・Hooks」役割分担
Claude Code や Codex などのコーディングエージェントには、エージェントの振る舞いを調整する仕組みとして 指示書・Skill・Hooks の3つがあります。本記事では、それぞれの役割と使い分けの考え方を整理します。
本記事での呼び方
-
指示書:エージェントがセッション開始時に読み込む設定ファイル(Claude Code の
CLAUDE.md、Codex のAGENTS.mdなど) - Skill:特定の作業の手順や資料をまとめたもの
- Hooks:決まったタイミングでスクリプトを動かす仕組み全体。個々の登録やスクリプトは「Hook」と呼びます
確認日:2026年10月15日。確認日時点の最新版(Claude Code v2.1.300、Codex CLI v0.162.1)の公式ドキュメントをもとにしています。仕様の更新が速いため、導入前に第9節の公式ドキュメントで最新の情報を確認してください。
1. それぞれの役割
エージェントに仕事を依頼するときは、「普段から守るルール」「作業ごとの進め方」「実行時のチェック」を分けて考えると整理しやすくなります。人の業務に置き換えると、指示書はチームの共通ルール、Skill は業務手順書、Hooks は操作時のチェック機能に当たります。
| 仕組み | 役割 | ひとことで |
|---|---|---|
| 指示書(CLAUDE.md / AGENTS.md など) | 常に守ってほしい前提を伝える | このプロジェクトでは何を前提に考えるか |
| Skill | 必要になったときだけ読み込む手順書 | この種の作業はどうやるか |
| Hooks | 決まったタイミングで自動的に動くスクリプト | 対象の操作では、毎回こうなる |
ポイント:指示書は「方針」、Skill は「手順と知識」、Hooks は「機械的な検査・強制」を担う。ただし Hooks が強制できるのは、対応するイベントで検知できた操作に限られる(詳しくは第2節の補足と 6.4)。
2. 比較表
同じ「エージェントへの設定」でも、AI が文章を読んで判断するものと、プログラムが決められた処理を行うものでは性質が異なります。表中の LLM は文章を理解・生成する AI、コンテキストは AI が判断のために参照する情報を指します。「いつ使われるか」「誰が処理するか」に注目して比べてください。
| 観点 | 指示書 | Skill | Hooks |
|---|---|---|---|
| 読み込まれるタイミング | セッション開始時に毎回 | 内容がタスクに合うと判断されたとき | ツール実行の前後、終了時などのイベント |
| 担い手 | LLM が読んで解釈する | LLM が読んで解釈する | LLM ではなくプログラムが実行する |
| 確実さ | 高めだが、守られないこともある | 呼ばれるかどうかは説明文の書き方次第 | 対象のイベントでは確実に実行される(対応範囲内) |
| コンテキストの消費 | 常に消費する(短く保つ必要あり) | 呼ばれたときだけ(大量に置いても負担が少ない) | ほぼ消費しない |
| 向いている内容 | 方針・規約・構成の説明・禁止事項 | 手順・テンプレート・スクリプト・専門知識 | 検査・強制・自動処理・通知 |
Hooks の「確実」の範囲:Hooks の「確実」は、対応するイベントが発生し、スクリプトがその操作を検知できた場合の話です。対応するツールやイベントは製品・バージョンによって異なり、検知できなかった操作は止められません。また、Hooks は「実行する・止める」までを機械的に行うもので、状況に応じた判断はできません(6.3・6.4参照)。
3. 迷ったときの判断基準
新しいルールを追加するときは、まず「何を防ぎたいか」「どの作業で必要か」を考えます。たとえば、日本語で回答してほしいなら指示書、レビューの進め方を揃えたいなら Skill、特定の操作を実行前に止めたいなら Hooks が候補となります。
上から順に当てはめて判断します。
-
一度でも破られたら困るか? → 困るなら Hooks(スクリプトで検知できる操作に限る)
- 例:本番環境の設定ファイルを編集させない/コミット前に必ず lint を通す/秘密情報の書き込みを止める
-
毎回のタスクで必要な知識か? → 必要なら 指示書
- 例:技術スタック、ディレクトリ構成、命名規約、「テストは
pnpm testで実行する」
- 例:技術スタック、ディレクトリ構成、命名規約、「テストは
-
特定の作業のときだけ要る、まとまった手順や資料か? → Skill
- 例:リリース手順、帳票 PDF の作り方、API 設計レビューの観点、社内フォーマットでのドキュメント作成
4. よくある失敗
設定がうまく機能しないときは、文章の書き方だけでなく、書く場所が適切かも確認しましょう。「詳しく書いたから伝わる」「禁止と書いたから必ず止まる」とは限らないため、目的に合った仕組みに分けることが大切です。
| 失敗 | 何が起きるか | 対策 |
|---|---|---|
| 指示書に何でも書く | 長くなるほど重要な指示が埋もれ、毎回のコンテキストも圧迫する | 作業ごとの手順は Skill に移す |
| 「必ず〜すること」を指示書だけに書く | LLM への依頼にすぎず、確実には守られない | 絶対に必要なもののうち、検知できる操作は Hooks で強制し、指示書には理由を書く(二段構え) |
| Hooks に判断をさせる | 文脈に応じた柔軟な判断ができない | Hooks は決まった処理に限定し、判断が要るものは Skill/指示書へ |
| Skill の説明文があいまい | 呼ばれるべき場面で呼ばれない | 「いつ使うか」を具体的に書く |
5. 組み合わせの例:PR を出す作業
PR(Pull Request。GitLab では MR:Merge Request)は、コードの変更をチームに共有し、レビューを依頼するためのものです。この作業では、共通ルールに沿って説明を書き、決められた手順で準備し、必要なチェックを通すという流れを、3つの仕組みで分担できます。
| 仕組み | 担当すること |
|---|---|
| 指示書 | 「ブランチ名は feature/xxx。PR は日本語で書く。main への直接 push はしない」 |
| Skill | PR 説明文のテンプレート、レビュー観点のチェックリスト、変更差分を要約するスクリプト |
| Hooks | main / master への直接 push と強制 push を、実行前に止める |
第6節では、この分担を実際の設定ファイルに落とし込みます。
6. 設定の記載例
役割の違いを理解したら、次は設定ファイルにどのような内容を書くのかを見てみましょう。コードの細部をすべて理解するよりも、「方針を伝える文章」「作業を進める手順」「操作に反応する設定」の違いをつかむことが、この章の目的です。
ここでは第5節の「PR を出す作業」を例に、Git 操作を安全に進めるための指示書・Skill・Hooks の書き方を示します。
コードブロックは役割を説明するための部分的な記載例です。そのまま導入できる一式ではないため、使用するツールの仕様に合わせて設定とスクリプトを用意してください。
以降の配置例は Codex を基準にしています。Claude Code での対応は次のとおりです(ユーザー単位の配置。カッコ内はリポジトリ単位)。
| 仕組み | Claude Code | Codex CLI |
|---|---|---|
| 指示書 |
~/.claude/CLAUDE.md(CLAUDE.md または .claude/CLAUDE.md) |
~/.codex/AGENTS.md(各階層の AGENTS.md) |
| Skill |
~/.claude/skills/<名前>/SKILL.md(.claude/skills/) |
~/.agents/skills/<名前>/SKILL.md(.agents/skills/) |
| Hooks の登録 |
~/.claude/settings.json の hooks(.claude/settings.json) |
~/.codex/hooks.json または config.toml の [hooks](.codex/hooks.json) |
| PreToolUse で返せる判定 |
allow / deny / ask / defer
|
allow / deny(ask は未対応) |
- Hooks の設定は、どちらも「イベント → matcher → 実行する処理」の3階層で書きます。
- Claude Code は、リポジトリに
CLAUDE.mdがない場合、AGENTS.mdを指示書として読み込めます(v2.1.277 以降)。両方のツールを使うチームでは、AGENTS.mdに共通の内容をまとめる方法もあります。
6.1. 指示書:常に守ってほしい方針を書く
指示書には、作業を依頼するたびに繰り返し伝えたい前提を書きます。たとえば「変更を記録・共有する前に決められた手順を確認する」「利用者の依頼なしに共有しない」といった、エージェントが判断するときの基準を短くまとめます。
配置例:~/.codex/AGENTS.md
## Git / 変更管理
- ブランチ名は `feature/xxx` とする
- PR/MR のタイトルと説明は日本語で書く
- コミット・push・ブランチ操作の前に `git-ops` Skill を呼び出す。手順と確認項目をチームでそろえるため
- コミットや push は、明示的な依頼がある場合に行う
- 破壊的な操作は避け、必要な場合は意図を明確にする
- main / master への直接 push と強制 push(`--force` など)は行わない。レビューを経ずに共有ブランチを壊さないためで、Hook でも止めている
- 変更ファイルと要点を簡潔に報告する
指示書では、いつ Skill を使うか、どの操作に利用者の依頼が必要かを伝えます。GitHub と GitLab の使い分けや PR の作成手順までは書かず、Skill に任せています。
「必ず」と書いても強制にはなりません。 指示書は LLM への依頼なので、「git-ops Skill を呼び出す」と書いても、呼び出されない場合があります(第 4 節)。一方、Hook が受け取るのは実行しようとしているコマンドなどの情報で、Skill を呼び出したかどうかを確実に判定するのは困難です。そのため、この項目は Hooks で強制せず、理由を添えて依頼するにとどめています。例外なく止めたい「main / master への直接 push と強制 push」だけを、6.3 の Hook で強制します。
6.2. Skill:特定の作業の手順と参照資料をまとめる
Skill は、ある種類の作業を進めるときに開く手順書です。毎回の依頼文に長い手順を貼り付ける代わりに、「何を確認し、どの順番で進めるか」を一つにまとめることで、作業の進め方をそろえやすくなります。
配置例:Codex CLI では ~/.agents/skills/git-ops/SKILL.md、Claude Code では ~/.claude/skills/git-ops/SKILL.md
ファイル先頭に名前・説明文を置き、本文に標準フローを書きます。
---
name: git-ops
description: Git リポジトリの Issue 確認、ブランチ運用、コミット、PR/MR 作成、レビュー依頼を一貫して進めるための Skill。GitLab・GitHub・ローカルのみの環境に対応し、利用可能な手段に応じて操作案を組み立てたい時に使う。
---
## 標準フロー
1. 対象 Issue とベースブランチを確認する
2. 指示書のブランチ命名規則に沿って作業ブランチを作る
3. 差分、テスト、未コミット変更を確認してコミット・push する
4. PR/MR のタイトルと説明を整理して作成する
5. レビュアー依頼と共有事項を整える
-
descriptionで、どの作業で使う Skill かを具体的に示します。 - 本文で作業の順序を示し、第 5 節で挙げた PR 説明文のテンプレートやレビュー観点のチェックリストは、
references/merge-request.mdなどの別ファイルに分けると、手順を整理しやすくなります。 - 標準フローは、すべての操作を自動実行する許可ではありません。指示書にある「コミットや push は明示的な依頼がある場合」という前提と合わせて使います。
6.3. Hooks:守らせたい操作を検知して止める
Hooks は、エージェントが操作しようとしたタイミングで、あらかじめ用意したチェック処理を呼び出す仕組みです。この例では、git push の宛先が保護ブランチ(main / master)の場合と、強制 push(--force など)の場合に、実行前に拒否します。登録設定は「いつ何を呼ぶか」、スクリプトは「何を検知してどう応答するか」を担当します。
6.1 の「コミットや push は明示的な依頼がある場合に行う」は、LLM が状況を見て守る方針です。一方、「依頼があっても main への直接 push と強制 push はしない」のように例外のないルールは、判断を挟まず機械的に止められるので Hooks に向いています。これが第 4 節で触れた「二段構え」(指示書に理由を書き、Hooks で強制する)の例です。
配置例:~/.codex/hooks.json、~/.codex/hooks/guard_git_push.py
スクリプトを、ツール実行前のイベントに登録する例です。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$HOME/.codex/hooks/guard_git_push.py\"",
"statusMessage": "Checking git push target"
}
]
}
]
}
}
この定義は、Bash ツールの実行前にスクリプトを呼び出します。スクリプトは git push を検知し、条件に当てはまる場合は、次の処理で拒否を返します。何も出力せずに終了した場合は、そのまま実行が続きます。
def deny(reason: str) -> int:
json.dump(
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": reason,
}
},
sys.stdout,
ensure_ascii=False,
)
return 0
スクリプト全体(クリックで展開)
#!/usr/bin/env python3
"""PreToolUse Hook: 保護ブランチへの push と強制 push を拒否する。"""
import json
import re
import shlex
import subprocess
import sys
PROTECTED = {"main", "master"}
FORCE_OPTIONS = {"-f", "--force", "--force-with-lease"}
def deny(reason: str) -> int:
json.dump(
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": reason,
}
},
sys.stdout,
ensure_ascii=False,
)
return 0
def current_branch(cwd: str) -> str:
result = subprocess.run(
["git", "branch", "--show-current"],
cwd=cwd, capture_output=True, text=True,
)
return result.stdout.strip()
def push_args(segment: str):
"""`git ... push <引数>` なら引数のリストを、それ以外は None を返す。"""
try:
tokens = shlex.split(segment)
except ValueError:
return None
while tokens and re.match(r"^\w+=", tokens[0]): # FOO=1 git push ...
tokens.pop(0)
if not tokens or tokens[0] != "git":
return None
i = 1
while i < len(tokens) and tokens[i].startswith("-"): # git -C dir push など
i += 2 if tokens[i] in ("-C", "-c") else 1
if i < len(tokens) and tokens[i] == "push":
return tokens[i + 1:]
return None
def check(command: str, cwd: str):
"""拒否する理由を返す。問題がなければ None。"""
for segment in re.split(r"&&|\|\||[;|\n]", command):
args = push_args(segment.strip())
if args is None or "--dry-run" in args or "-n" in args:
continue
if any(a in FORCE_OPTIONS or a.startswith("--force-with-lease=") for a in args):
return "強制 push は禁止されています。"
positional = [a for a in args if not a.startswith("-")]
refspecs = positional[1:] # 先頭は push 先のリモート名
if not refspecs: # 宛先省略 = 現在のブランチ
if current_branch(cwd) in PROTECTED:
return "保護ブランチへの push は禁止です。作業ブランチから PR/MR を作成してください。"
continue
for ref in refspecs:
if ref.startswith("+"):
return "強制 push は禁止されています。"
dest = re.sub(r"^refs/heads/", "", ref.split(":")[-1])
if dest == "HEAD":
dest = current_branch(cwd)
if dest in PROTECTED:
return "保護ブランチへの push は禁止です。作業ブランチから PR/MR を作成してください。"
return None
def main() -> int:
event = json.load(sys.stdin)
if event.get("tool_name") != "Bash":
return 0
command = event.get("tool_input", {}).get("command", "")
reason = check(command, event.get("cwd", "."))
return deny(reason) if reason else 0
if __name__ == "__main__":
sys.exit(main())
ask ではなく deny を使う理由:Codex の PreToolUse では、permissionDecision の ask は未対応です。ask を返すと Hook が失敗扱いになり、ツール呼び出しはそのまま続行されます(2026年10月時点の公式ドキュメントの記載)。そのため、この例では deny を使っています。利用者に確認を求めたい操作は、Hooks ではなく承認設定(approval)や指示書で扱います。Hooks が返せる値は製品・バージョンによって異なるので、導入前に使用環境のドキュメントで確認してください。
この Hook が止められる範囲は限られます。 git push を直接実行するコマンドを文字列として検知するため、sh -c "git push ..." のように別のシェルを経由する実行や、エイリアスなどはすり抜けます。また、git-ops Skill を呼び出したかどうかは判定しません。git push --dry-run は対象から除外しています。コミットやブランチ操作もこの Hook の検知対象ではありません。Hooks は「検知できた操作を止める」ものであり、すべての経路を保証するものではありません(6.4 も参照)。
「push の前にテストと lint を実行し、失敗したら止める」といった処理も、同じ登録方法でスクリプトを差し替えれば実現できます。Hook の登録ファイルだけでなく、検知処理を含むスクリプト全体も配置する必要があります。
6.4. 機密ファイル保護も一つの仕組みに任せない
API キーやパスワードなどをエージェントに渡さないためには、「読まないで」と伝えるだけでなく、アクセスを止める仕組みや、そもそも作業場所に置かない工夫も必要です。安全なサンプルを使って作業できるようにし、複数の対策を重ねることが基本になります。
機密ファイルの保護でも、指示書と Hooks を組み合わせて役割を分けます。
| 仕組み | 記載・設定例 | 担当する役割 |
|---|---|---|
| 指示書 |
AGENTS.md に機密ファイルを扱わないこと、.env.template やマスク済みサンプルを使うことを記載 |
禁止事項と安全な代替手段を LLM に伝える |
| Hook 登録 |
hooks.json の PreToolUse に block_secret_paths.py を登録 |
対応するツール実行前に検査を呼び出す |
| Hook 本体 | 機密パスへのアクセスを検知すると permissionDecision: "deny" を返す |
検知できた操作を拒否する |
適用範囲に注意:Hooks が対応するイベントやツールは、製品やバージョンによって異なります。matcher: "*" の登録やスクリプト内の対応だけで、すべてのツールを保護できるとは限りません。使用環境で有効な範囲を確認し、指示書に加えて、sandbox(エージェントが読み書き・実行できる範囲を制限する機能)、approval(操作の前に利用者の承認を求める設定)、ワークスペース分離(機密ファイルを作業ディレクトリに置かない運用)を組み合わせます。
このように、指示書は方針、Skill は手順、Hooks は対応するイベントでの検査・拒否を担います。Hooks は万能な保証ではなく、検知対象と適用範囲を明確にして使うことが重要です。
7. 導入の進め方
3つの仕組みを最初からそろえる必要はありません。次の順に、必要になったものから足していくのがおすすめです。
-
指示書を短く作る:技術スタック、テストの実行方法、禁止事項など、毎回伝えている前提を数行で書きます。どちらのツールも
/initコマンドで雛形を作れます。 -
繰り返し貼っている手順を Skill に切り出す:同じ手順やテンプレートを何度も依頼文に貼り付けていると気付いたら、Skill にまとめます。
descriptionには「いつ使うか」を具体的に書きます。 -
守られなかったルールだけを Hooks に移す:指示書に書いたのに守られなかったルールのうち、一度でも破られたら困り、かつスクリプトで検知できるものを Hooks にします。最初は 6.3 のような
denyを返す Hook を1つ作り、テスト用のリポジトリで止まることを確かめてから使い始めます。リポジトリに置いた Hook はチーム全員の環境で実行されるため、共有する前に内容をレビューします。 - 定期的に見直す:指示書が長くなったら作業ごとの部分を Skill に移し、使われなくなった Skill や Hook は削除します。
8. まとめ
まずは「普段のルールは指示書、作業の手順は Skill、操作時のチェックは Hooks」と覚えてください。実際に設定するときは、エージェントに判断を任せる部分と、プログラムや利用者の確認で制御する部分を分けて考えましょう。
- LLM の判断に任せてよいもの(指示書・Skill)と、仕組みで強制すべきもの(Hooks。ただし対応範囲内)の境界をはっきりさせるのが役割分担の要点です。
- 指示書は短く保ち、常に必要な前提だけを書きます。作業ごとの詳細は Skill に切り出します。
- なお、Hooks に相当する仕組みがどこまで用意されているかはツールやバージョンによって異なります。導入前に、使っているツールのドキュメントで確認してください。