Claude Media
Agent SDKプラグインをロードする方法

Agent SDKプラグインをロードする方法

Agent SDKのpluginsオプションでローカルプラグインを読み込む手順。パス指定のルール・複数ソースの組み合わせ・initメッセージでの確認・よくあるトラブルまでまとめました。

Agent SDKがプラグインを読み込む仕組み

プラグインは、Skills・Agents・Hooks・MCPサーバーをひとまとめにして配布できる単位です。4種類の中身は次の通りです。

  • Skills: 関連するときに自律的に呼ぶ能力
  • Agents: 特定タスク向けの専門サブエージェント
  • Hooks: ツール実行などのイベントに反応する処理
  • MCPサーバー: Model Context Protocol経由の外部ツール連携

1つのプラグインディレクトリに、この4種類を好きなだけ組み合わせて入れられます。Agent SDKでは、これをコードから直接読み込めます。CLIの/plugin installのようなマーケットプレイス経由のインストール操作はSDK側には無く、query()pluginsオプションにローカルのディレクトリパスを渡すだけです。マーケットプレイスやリモートリポジトリで配布されているプラグインを使いたい場合も、先に手元へダウンロードしてからそのローカルパスを渡します。

CLIでのプラグイン作成・マーケットプレイスの使い方はClaude Codeプラグイン完全ガイドが扱っています。Agent SDK自体の基本はClaude Agent SDK入門で押さえられます。

動作にはAgent SDK本体が必要です。TypeScriptなら@anthropic-ai/claude-agent-sdk、Pythonならclaude-agent-sdkをインストール済みのプロジェクトで、以下のコード例をそのまま試せます。

npm install @anthropic-ai/claude-agent-sdk
# または
pip install claude-agent-sdk

プラグインと単体設定(.claude/)のどちらを使うか

プラグインを作る前に、そもそもプラグイン化が必要かを考える価値があります。Claude Codeには、SkillsやHooksを追加する方法がもう1つあります。プロジェクトの.claude/ディレクトリに直接ファイルを置く単体設定です。

方法コマンド名の形向いている場面
単体設定(.claude/ディレクトリ)コマンド名の形/hello向いている場面個人の作業用、プロジェクト固有のカスタマイズ、その場限りの実験
プラグイン(skills/ / agents/ / hooks/をまとめたディレクトリ)コマンド名の形/plugin-name:hello向いている場面チームでの共有、コミュニティへの配布、バージョン管理された配布、複数プロジェクトでの再利用

自分1人のプロジェクトでしか使わないSkillなら、.claude/skills/に直接置くだけで十分です。複数のプロジェクトやチームで同じSkillsやHooksを配りたくなった時点で、プラグイン化してpluginsオプションから読み込む形に移行する、という判断基準になります。

pluginsオプションでローカルパスを渡す

typeフィールドは"local"固定で、SDKが受け付ける唯一の値です。1つのquery()呼び出しで複数のプラグインを別々のパスから読み込めます。

for await (const message of query({
  prompt: "Hello",
  options: {
    plugins: [
      { type: "local", path: "./my-plugin" },
      { type: "local", path: "/absolute/path/to/another-plugin" }
    ]
  }
})) {
  // プラグインのコマンド・エージェント等が使えるようになる
}
options = ClaudeAgentOptions(
    plugins=[
        {"type": "local", "path": "./my-plugin"},
        {"type": "local", "path": "/absolute/path/to/another-plugin"},
    ]
)

パスはプラグインのルートディレクトリ、つまりskills/ / agents/ / hooks/ / commands/ / .claude-plugin/の親ディレクトリを指します。サブディレクトリを指定すると読み込みに失敗します。

パス指定で気をつける3点

書き方挙動
相対パス("./plugins/my-plugin")挙動実行時のカレントディレクトリを基準に解決
絶対パス("/home/user/plugins/my-plugin")挙動そのまま解決
チルダ("~/plugins/my-plugin")挙動展開されない。ホームディレクトリを使うならos.homedir()(Node.js)やPath.home()(Python)で自分で絶対パスに組み立てる

存在しないパスを渡した場合、SDKはそのプラグインをエラーを出さずに読み飛ばしてセッションを続行します。エラーにはならないため、読み込めたかどうかは次に説明するinitメッセージで確認します。

initメッセージでロード結果を確認する

セッション開始直後のsystem初期化メッセージ(subtype: "init")には、読み込まれたプラグインの一覧がpluginsフィールドとして入ります。名前とパスの組で構成され、パスが存在しなかったプラグインはここに出てきません。

if (message.type === "system" && message.subtype === "init") {
  console.log("Plugins:", message.plugins);
  // 例: [{ name: "my-plugin", path: "/absolute/path/to/my-plugin" }]
 
  console.log("Skills:", message.skills);
  // 例: ["my-plugin:greet"]
 
  console.log("Commands:", message.slash_commands);
  // 例: ["compact", "context", "my-plugin:custom-command", "my-plugin:greet"]
}

プラグインが提供するSkillsは、プラグイン名をプレフィックスにした名前空間付きでskillsslash_commandsの両方に並びます。読み込んだつもりのプラグインが動かないときは、まずこの3つのフィールドを見比べます。

プラグインのSkillsを名前空間付きで呼び出す

プラグインのSkillは自動的にplugin-name:skill-nameという名前で衝突を避けます。呼び出すときはプロンプトにその名前空間ごと書きます。

for await (const message of query({
  prompt: "/my-plugin:greet",
  options: {
    plugins: [{ type: "local", path: "./my-plugin" }]
  }
})) {
  if (message.type === "assistant") {
    console.log(message.message.content);
  }
}

CLIの/plugin install my-plugin@marketplaceで既にインストール済みのプラグインも、そのインストール先パスをpluginsオプションへ渡せばSDKから使えます。CLIでインストールしたプラグインの実体は~/.claude/plugins/以下にあります。

複数のプラグインソースを組み合わせる

プロジェクト固有のローカルプラグインと、チームで共有しているプラグインを同時に読み込むこともできます。

import * as os from "node:os";
import * as path from "node:path";
 
plugins: [
  { type: "local", path: "./local-plugin" },
  {
    type: "local",
    path: path.join(os.homedir(), ".claude", "custom-plugins", "shared-plugin")
  }
];

プラグインのSkillはプラグイン名で名前空間化されるため、別のプラグインが同名のSkillを持っていても/plugin-name:skill-nameで呼び分けられます。プロジェクト固有のプラグインと組織共通のプラグインを分けて管理しておくと、どちらかを更新したときの影響範囲を追いやすくなります。

プラグインのディレクトリ構成

.claude-plugin/plugin.jsonのマニフェストは任意です。無くてもClaude Codeがディレクトリ構成から中身を自動判定します。

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # 省略可。無ければ自動判定
├── skills/
│   └── my-skill/
│       └── SKILL.md
├── commands/
│   └── custom-cmd.md
├── agents/
│   └── specialist.md
├── hooks/
│   └── hooks.json
└── .mcp.json

commands/skills/より前からある形式で、フラットな.mdファイルとしてSkillを置きます。新しく作るプラグインではskills/を使い、commands/は既存プラグインとの互換のために残っている形と考えます。

hooks/hooks.jsonに書けるフックはプラグイン専用の形式ではなく、Claude Code本体のイベントハンドラーと同じ書式です。ツール実行の前後やセッション開始時など、対応するイベントの種類と設定の書き方はClaude Code Hooks完全ガイドにまとまっています。プラグインとして配布すれば、チームの全員が同じフックを同じ設定ファイルなしで受け取れます。

一通りの流れを1つのコード例で見る

maxTurnsを短く区切ると、プラグインが正しく読み込まれているかどうかだけを確認する検証用クエリとして使い回せます。読み込み確認だけが目的なら、本来のタスク用のプロンプトを流す前に、この形の軽いクエリを1回はさんでおくと安全です。

import { query } from "@anthropic-ai/claude-agent-sdk";
 
for await (const message of query({
  prompt: "What custom commands do you have available?",
  options: {
    plugins: [{ type: "local", path: "./plugins/my-plugin" }],
    maxTurns: 3
  }
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log("Loaded plugins:", message.plugins);
    console.log("Available skills:", message.skills);
    console.log("Available commands:", message.slash_commands);
  }
  if (message.type === "assistant") {
    console.log("Assistant:", message.message.content);
  }
}

実行すると、最初に届くinitメッセージでロード済みプラグインの一覧が確認できます。続くassistantメッセージには、Claudeがプラグインの存在を認識した上での応答が入ります。

よくあるつまずき

initメッセージのpluginsに出てこない: パスがプラグインのルート(skills/等の親ディレクトリ)を指しているか確認します。サブディレクトリを指していないか、plugin.jsonを含めているならJSON構文が壊れていないかも見ます。ディレクトリの読み取り権限が無い場合も同様に読み込まれません。相対パスを渡しているなら、実行時のカレントディレクトリが想定とずれていないかも合わせて確認します。プログラムを別のディレクトリから起動しただけで、正しかったはずの相対パスが解決できなくなるケースがあります。

プラグインのSkillsが動かない: /plugin-name:skill-nameの名前空間付きで呼び出しているか確認します。initメッセージのskills配列に正しい名前空間で並んでいるかも合わせて見ます。skills/my-skill/SKILL.mdのようにSkillごとにサブディレクトリを切っているかも確認点です。

チルダパスが展開されない: SDKは~/pluginsのようなパスを展開しません。os.homedir()path.join(PythonならPath.home())で絶対パスに組み立ててから渡します。シェルのタブ補完で入力したパスをそのまま貼り付けたときに紛れ込みやすいミスです。

Agent SDKのプラグインとCLIのプラグインの関係

同じプラグイン形式を、CLIは/pluginコマンドとマーケットプレイス経由でインストールして使い、Agent SDKはpluginsオプションでローカルパスから直接読み込んで使います。配布・共有の仕組みが違うだけで、プラグインが提供するSkills・Agents・Hooks・MCPサーバーの中身は共通です。チームで配布用のプラグインをすでに持っているなら、CLI用に作ったものをそのままAgent SDKからも使えます。常駐アプリとしてSDKを組み込む実装例はAgent SDKでSlack常駐botを作るで扱っています。

よくある質問

pluginsオプションとskillsオプションは併用できますか

できます。skillsオプションはプラグイン由来のSkillsにも適用され、名前空間付きの名前(plugin-name:skill-name)で許可リストに指定します。

プラグインのHooksはプログラム側のhooksコールバックと同時に動きますか

動きます。プラグインが持つhooks/hooks.jsonのようなfilesystem hooksと、query()に渡すプログラム側のhooksコールバックは同じフックのライフサイクルで両方実行されます。

マーケットプレイスのURLをそのままpluginsオプションに渡せますか

渡せません。type"local"しか受け付けないため、マーケットプレイスやリモートリポジトリのプラグインは先にローカルへダウンロードしてから、そのディレクトリパスを渡します。

.claude-plugin/plugin.jsonを書かないとどうなりますか

省略しても動きます。マニフェストが無い場合、Claude Codeはskills/ / agents/ / hooks/ / commands/ / .mcp.jsonといったディレクトリ構成そのものから中身を自動的に判定します。

プラグインのagents/ディレクトリはquery()agentsパラメータと同じものですか

別の経路です。プラグインのagents/はMarkdownファイルとしてディスクに置くサブエージェント定義で、query()に直接渡すagentsパラメータはコードで定義するプログラム的なサブエージェントです。どちらも特定タスクを任せる専門サブエージェントを増やす点は共通していますが、定義する場所が違います。

まとめ

Agent SDKでプラグインを使うには、ローカルのプラグインルートディレクトリをpluginsオプションに{ type: "local", path: "..." }の形で渡し、initメッセージのplugins / skills / slash_commandsで読み込み結果を確認します。チルダパスは展開されない点と、存在しないパスがエラーを出さずに読み飛ばされる点の2つだけ覚えておけば、読み込みまわりのトラブルのほとんどは避けられます。

この記事を共有:XはてブLinkedIn