5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コーディングエージェントの「指示書・Skill・Hooks」役割分担

5
Last updated at Posted at 2026-10-22

コーディングエージェントの「指示書・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 が候補となります。

上から順に当てはめて判断します。

  1. 一度でも破られたら困るか? → 困るなら Hooks(スクリプトで検知できる操作に限る)
    • 例:本番環境の設定ファイルを編集させない/コミット前に必ず lint を通す/秘密情報の書き込みを止める
  2. 毎回のタスクで必要な知識か? → 必要なら 指示書
    • 例:技術スタック、ディレクトリ構成、命名規約、「テストは pnpm test で実行する」
  3. 特定の作業のときだけ要る、まとまった手順や資料か? → 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つの仕組みを最初からそろえる必要はありません。次の順に、必要になったものから足していくのがおすすめです。

  1. 指示書を短く作る:技術スタック、テストの実行方法、禁止事項など、毎回伝えている前提を数行で書きます。どちらのツールも /init コマンドで雛形を作れます。
  2. 繰り返し貼っている手順を Skill に切り出す:同じ手順やテンプレートを何度も依頼文に貼り付けていると気付いたら、Skill にまとめます。description には「いつ使うか」を具体的に書きます。
  3. 守られなかったルールだけを Hooks に移す:指示書に書いたのに守られなかったルールのうち、一度でも破られたら困り、かつスクリプトで検知できるものを Hooks にします。最初は 6.3 のような deny を返す Hook を1つ作り、テスト用のリポジトリで止まることを確かめてから使い始めます。リポジトリに置いた Hook はチーム全員の環境で実行されるため、共有する前に内容をレビューします。
  4. 定期的に見直す:指示書が長くなったら作業ごとの部分を Skill に移し、使われなくなった Skill や Hook は削除します。

8. まとめ

まずは「普段のルールは指示書、作業の手順は Skill、操作時のチェックは Hooks」と覚えてください。実際に設定するときは、エージェントに判断を任せる部分と、プログラムや利用者の確認で制御する部分を分けて考えましょう。

  • LLM の判断に任せてよいもの(指示書・Skill)と、仕組みで強制すべきもの(Hooks。ただし対応範囲内)の境界をはっきりさせるのが役割分担の要点です。
  • 指示書は短く保ち、常に必要な前提だけを書きます。作業ごとの詳細は Skill に切り出します。
  • なお、Hooks に相当する仕組みがどこまで用意されているかはツールやバージョンによって異なります。導入前に、使っているツールのドキュメントで確認してください。

9. 参考URL

5
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?