Read OSS

プラグインシステム — Commands、Agents、Skills、Hooks

中級

前提知識

  • 第1回:アーキテクチャの概要
  • YAMLとMarkdownのfrontmatterの基礎知識
  • 基本的なシェルスクリプトの知識

プラグインシステム — Commands、Agents、Skills、Hooks

第1回で見たように、claude-codeリポジトリには設定より規約(convention-over-configuration)のアーキテクチャに基づいた13の公式プラグインが収録されています。しかし、ディレクトリ構造を把握することと、各コンポーネントが実際にどう動作するかを理解することは別の話です。Commands、Agents、Skills、Hooksという4種類のコンポーネントはそれぞれ、独自のディスカバリーメカニズム、設定インターフェース、実行セマンティクスを持っています。

この記事では、公式プラグインの実例をもとに各タイプを詳しく掘り下げます。プラグイン形式とsettings形式のhookの重要な違いについても整理し、最終的にすべてを統合したライフサイクルモデルとしてまとめます。

Commands:ユーザーが起動するワークフロー

Commandsはプラグイン機能への主要なエントリーポイントです。YAMLのfrontmatterを持つMarkdownファイルとして定義され、Claude Codeのスラッシュコマンドとして利用できるようになります。ユーザーが /feature-dev と入力すると、Claude Codeは対応する .md ファイルを読み込み、その内容をプロンプトの指示として使用します。

frontmatterが核心です。feature-devコマンドを見てみましょう:

plugins/feature-dev/commands/feature-dev.md#L1-L4

---
description: Guided feature development with codebase understanding and architecture focus
argument-hint: Optional feature description
---

description はコマンド一覧に表示され、argument-hint はコマンド名の後ろに何を渡すかをユーザーに伝えます。さらに高度な設定を見たければ、code-reviewのfrontmatterが参考になります:

plugins/code-review/commands/code-review.md#L1-L4

---
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh pr comment:*), Bash(gh pr diff:*), Bash(gh pr view:*), Bash(gh pr list:*), mcp__github_inline_comment__create_inline_comment
description: Code review a pull request
---

allowed-tools フィールドはパターンマッチングを持つホワイトリストです。Bash(gh pr view:*) は「Bashツールの呼び出しを許可するが、コマンドが gh pr view で始まる場合のみ」という意味です。これがプラグインのagentを特定の操作に限定する仕組みです。コードレビュープラグインがファイルの書き込みや任意のコマンド実行をすべきではありません。

ralph-loopコマンドでは、さらに2つのfrontmatterフィールドが登場します:

plugins/ralph-wiggum/commands/ralph-loop.md#L1-L5

---
description: "Start Ralph Wiggum loop in current session"
argument-hint: "PROMPT [--max-iterations N] [--completion-promise TEXT]"
allowed-tools: ["Bash(${CLAUDE_PLUGIN_ROOT}/scripts/setup-ralph-loop.sh:*)"]
hide-from-slash-command-tool: "true"
---

hide-from-slash-command-tool を設定すると、Claudeがこのコマンドを自律的に呼び出せなくなります。必ずユーザーが手動で起動する必要があります。また allowed-tools${CLAUDE_PLUGIN_ROOT} を使うことで、Bashの実行をプラグイン内の特定スクリプトに限定していることにも注目してください。

ヒント: コマンド本文中の $ARGUMENTS 変数は、スラッシュコマンドの後にユーザーが入力した文字列に置き換えられます。複雑な引数パースを実装しなくても、コマンドが入力を受け取れる仕組みはここにあります。

Agents:特化型AIワーカー

Agentsはサブエージェントの定義です。Commandsが指揮する特化型AIワーカーと言えます。Commandsと同様にYAML frontmatterを持つMarkdownファイルですが、frontmatterはユーザー向けのメタデータではなく、サブエージェントのモデルケーパビリティを設定するために使われます。

feature-devのcode-explorerエージェントを見てみましょう:

plugins/feature-dev/agents/code-explorer.md#L1-L7

---
name: code-explorer
description: Deeply analyzes existing codebase features by tracing execution paths...
tools: Glob, Grep, LS, Read, NotebookRead, WebFetch, TodoWrite, WebSearch, KillShell, BashOutput
model: sonnet
color: yellow
---

各frontmatterフィールドの役割は次のとおりです:

フィールド 役割
name ログ/UIの表示名 code-explorer
description このagentを使うべきタイミング 詳細なケーパビリティの説明
tools 許可ツールのホワイトリスト Glob, Grep, LS, Read, ...
model モデルティアの選択 sonnet, haiku, opus
color ログでの視覚的識別 yellow, green, red

feature-devの3つのagentを比較すると、モデル選択とツール制限によってどのように役割が分担されているかがよくわかります:

Agent Model Tools 役割
code-explorer sonnet 読み取り中心(Glob, Grep, Read...) 高速なコードベース分析
code-architect sonnet 同じ読み取り中心のセット アーキテクチャ設計
code-reviewer sonnet 同じ読み取り中心のセット 信頼スコア付きの品質レビュー

plugins/feature-dev/agents/code-reviewer.md#L25-L33 のcode-reviewerエージェントは、0〜100スケールの信頼スコアシステムを導入しており、スコア80以上の問題のみを報告します。このフィルタリングはagentのプロンプト指示だけで実装されており、特別なランタイムサポートは不要です。プロンプト自体がプログラムなのです。

flowchart LR
    CMD["/feature-dev command"] --> EXPLORE["code-explorer<br/>model: sonnet<br/>color: yellow"]
    CMD --> ARCH["code-architect<br/>model: sonnet<br/>color: green"]
    CMD --> REVIEW["code-reviewer<br/>model: sonnet<br/>color: red"]

    EXPLORE --> |"Read-only tools"| ANALYSIS["Codebase<br/>Analysis"]
    ARCH --> |"Read-only tools"| DESIGN["Architecture<br/>Design"]
    REVIEW --> |"Read-only tools"| QUALITY["Quality<br/>Review"]

    style EXPLORE fill:#FDD835
    style ARCH fill:#4CAF50,color:#fff
    style REVIEW fill:#E53935,color:#fff

Skills:コンテキストで自動起動するナレッジ

Skillsは最もパッシブなコンポーネントタイプです。コンテキストマッチングに基づいてClaude Codeが自動的に有効化する知識を提供するもので、明示的な呼び出しは一切不要です。各skillはサブディレクトリに SKILL.md ファイルを持つ形で管理されます。

frontend-designスキルのfrontmatterを見てみましょう:

plugins/frontend-design/skills/frontend-design/SKILL.md#L1-L5

---
name: frontend-design
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications.
license: Complete terms in LICENSE.txt
---

description フィールドは二重の役割を果たします。skillの内容を文書化するとともに、Claude Codeにいつそのskillを起動すべきかを伝えます。ユーザーがWebコンポーネントの作成について質問すると、Claude Codeはそのコンテキストをskillのdescriptionと照合し、合致するskillのコンテンツを注入します。

plugins/plugin-dev/skills/plugin-structure/SKILL.md#L1-L5 のplugin-structureスキルは、より明示的なdescriptionを持っています:

description: This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure"...

descriptionを長くするほど、起動される場面が広がります。skill作者が特定性をコントロールできます。曖昧な説明は幅広く起動され、精確な説明は狭い範囲でのみ起動されます。

Skillはサブディレクトリ(references/examples/scripts/)にサポート資料を持てます。plugin-devプラグインには7つのskillがあり、それぞれ独自のリファレンス資料を持っています。ここがCommandsとの根本的な違いです。Commandは単発の指示ですが、Skillはセッション全体を通じて参照されるナレッジベースです。

Hooks:イベント駆動のインターセプター

Hooksは最もパワフルなコンポーネントタイプであり、最も複雑でもあります。9種類のライフサイクルイベントに応じて実行され、操作のブロック、コンテキストの注入、ポリシーの適用といった形でClaude Codeの動作を変更できます。

9つのhookイベントは plugins/plugin-dev/skills/hook-development/SKILL.md#L634-L644 に記述されています:

イベント タイミング 主な用途
PreToolUse ツール実行前 バリデーション、ブロック
PostToolUse ツール完了後 フィードバック、ログ
Stop エージェントが停止を検討 完了チェック
SubagentStop サブエージェントが停止を検討 タスクバリデーション
SessionStart セッション開始時 コンテキスト読み込み
SessionEnd セッション終了時 クリーンアップ
UserPromptSubmit ユーザーがプロンプトを送信 入力バリデーション
PreCompact コンテキスト圧縮前 重要情報の保持
Notification 通知送信時 リアクション、ログ

Hooksにはcommandフック(確定的なチェック向けのシェルスクリプト)とpromptフック(コンテキスト認識の判断向けのLLM駆動)の2種類があります。終了コードのプロトコルが重要です:

  • 終了コード 0 — 操作を許可(stdoutはトランスクリプトに表示)
  • 終了コード 2 — 操作をブロック(stderrがClaudeにフィードバックされる)
  • その他 — ノンブロッキングエラー

PreToolUseフックがファイル書き込みをインターセプトする流れを示すシーケンス図です:

sequenceDiagram
    participant C as Claude Code
    participant H as PreToolUse Hook
    participant T as Write Tool

    C->>H: JSON via stdin (tool_name, tool_input)
    H->>H: Check patterns/rules
    alt Pattern matches (new warning)
        H-->>C: stderr: warning message
        H->>C: exit 2 (BLOCK)
        Note over C: Tool call blocked
    else No match or already warned
        H->>C: exit 0 (ALLOW)
        C->>T: Execute Write tool
        T->>C: Tool result
    end

matcherを使うと、特定のツールのみがhookをトリガーするよう絞り込めます。security-guidanceプラグインは "matcher": "Edit|Write|MultiEdit" を使い、ファイル変更ツールのみに反応します:

plugins/security-guidance/hooks/hooks.json#L1-L16

matcherは完全一致("Write")、パイプ区切りのOR("Edit|Write")、ワイルドカード("*")、正規表現パターン("mcp__.*__delete.*")に対応しています。

hookの二重フォーマットという落とし穴

これはhook開発で最も頻繁に起きる落とし穴です。hookの配置場所によってJSONフォーマットが2種類あり、誤ったほうを使っても何のエラーも出ずに静かに無視されます。

プラグイン形式(プラグイン内の hooks/hooks.json)では、イベントを hooks キーで囲みます:

{
  "description": "Optional description",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/validate.sh"
          }
        ]
      }
    ]
  }
}

settings形式.claude/settings.json またはユーザー設定)では、イベントをトップレベルに直接記述します:

{
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [
        {
          "type": "command",
          "command": "python3 /path/to/validator.py"
        }
      ]
    }
  ]
}

プラグイン形式の実例はhookifyの登録処理 plugins/hookify/hooks/hooks.json#L1-L49 で確認できます。外側の "hooks" ラッパーに注目してください。bash_command_validatorの例 examples/hooks/bash_command_validator_example.py#L13-L27 のdocstringにもプラグイン形式のドキュメントがあります。

ヒント: hookが動かない場合は、まずフォーマットを確認しましょう。プラグインの hooks.json には {"hooks": {...}} のラッパーが必要です。ユーザー設定には不要です。plugins/plugin-dev/skills/hook-development/SKILL.md のhook開発スキルには、両方のフォーマットが並べて説明されています。

コンポーネントのライフサイクル:ディスカバリーから実行まで

4種類のコンポーネントタイプの理解が揃ったところで、それらが統合されたライフサイクルの中でどう連携するかを整理します:

flowchart TD
    INSTALL["Plugin Installed"] --> READ["Read plugin.json manifest"]
    READ --> SCAN["Scan Convention Directories"]

    SCAN --> CMD_SCAN["commands/*.md"]
    SCAN --> AGT_SCAN["agents/*.md"]
    SCAN --> SKL_SCAN["skills/*/SKILL.md"]
    SCAN --> HK_SCAN["hooks/hooks.json"]
    SCAN --> MCP_SCAN[".mcp.json"]

    CMD_SCAN --> CMD_REG["Register as<br/>slash commands"]
    AGT_SCAN --> AGT_REG["Register as<br/>available agents"]
    SKL_SCAN --> SKL_REG["Register for<br/>context matching"]
    HK_SCAN --> HK_REG["Register on<br/>event bus"]
    MCP_SCAN --> MCP_REG["Start MCP<br/>servers"]

    CMD_REG --> USER["User types /command"]
    AGT_REG --> ORCH["Command orchestrates agents"]
    SKL_REG --> AUTO["Auto-activated by context"]
    HK_REG --> EVENT["Fired by lifecycle events"]
    MCP_REG --> TOOL["Available as tools"]

    USER --> EXEC["Execution"]
    ORCH --> EXEC
    AUTO --> EXEC
    EVENT --> EXEC
    TOOL --> EXEC

    style INSTALL fill:#FF5722,color:#fff
    style EXEC fill:#4CAF50,color:#fff

重要なポイントをまとめると、CommandsはUserが起動し、AgentsはCommandが指揮し、Skillsはコンテキストによって自動起動され、Hooksはイベントによって駆動されます。この4つの起動モデルが、明示的なユーザー操作から完全自動の動作まで、あらゆる場面をカバーしています。

plugin.json のカスタムパス指定は、デフォルトディレクトリを置き換えるのではなく、補完する形で機能します。"commands": "./custom-commands" を指定した場合、Claude Codeは commands/custom-commands/ の両方をスキャンします。この加算型の動作により、既存の規約を壊さずに拡張できます。

設定の変更は次のClaude Codeセッション起動時に反映されます。プラグインの設定はホットリロードされません。hooks.json を編集したら、Claude Codeを再起動して新しいhookを読み込みましょう。

次回予告

コンポーネントモデルの全体像が理解できたところで、次はそれが大規模に組み合わさった様子を見ていきます。第3回では、2つの高度なマルチエージェントパターンを取り上げます。feature-devの7フェーズからなるhuman-in-the-loopワークフロー(並列エージェント起動あり)と、code-reviewのマルチパスバリデーションパイプライン(各findingを新たなサブエージェントが個別に検証する仕組み)です。さらに、ralph-wiggumプラグインのユニークな自己参照ループパターンも解剖します。Stopフックがトランスクリプトを読み取り、元のプロンプトを再注入することでagentの反復実行を実現するという、創造的な設計です。