はじめに / 対象と前提
チームで Claude Code を使っていると、「便利なスラッシュコマンドや hook を各自が .claude/ にコピペして、気づくと全員バージョンがバラバラ」という状態になりがちだ。自分もレビュー用コマンドと編集後の lint hook を 3 つのリポジトリに手で配っていて、直すたびに配り直すのがつらくなった。
これを解決するのが Claude Code のプラグイン機能 だ。コマンド・サブエージェント・Skills・hook・MCP サーバー設定を 1 つのディレクトリにまとめ、marketplace(配布元の目録) 経由で install / update できる。
- 想定読者:Claude Code を普段使いしていて、自作のコマンドや hook をチームに配りたい人
- 前提:
.claude/commands/やsettings.jsonの hooks を一度は書いたことがある - 確認環境:Claude Code 2.1.285 / macOS 15(Darwin 24)/ bash
TL;DR
- プラグインは
.claude-plugin/plugin.jsonを置いたディレクトリ。commands/hooks/などは プラグインのルート直下 に置く(.claude-plugin/の中ではない) - 配布は
.claude-plugin/marketplace.jsonを書いたリポジトリをclaude plugin marketplace addし、claude plugin install 名前@marketplace名で入れる - hook のスクリプトパスは
${CLAUDE_PLUGIN_ROOT}で書く。開発中はclaude --plugin-dirで読み込むと、インストール済みのコピーと取り違えずに済む
手順 / 動かし方
1. ディレクトリ構成
marketplace とプラグインを同じリポジトリに置く構成にした。
my-mkt/
├── .claude-plugin/
│ └── marketplace.json # 配布元の目録
└── plugins/
└── team-tools/
├── .claude-plugin/
│ └── plugin.json # ここにはマニフェストだけ
├── commands/
│ └── review.md # /team-tools:review になる
└── hooks/
├── hooks.json
└── after-edit.sh
2. plugin.json(マニフェスト)
{
"name": "team-tools",
"version": "0.1.0",
"description": "team shared commands and hooks",
"author": { "name": "your-team" }
}
name は kebab-case 必須。これがコマンドの名前空間になり、commands/review.md は /team-tools:review として呼べる。
3. コマンドと hook
commands/review.md は通常のカスタムスラッシュコマンドと同じ書き方でいい。
---
description: 変更差分をレビューする
---
git diff を確認し、バグと命名の問題だけを指摘してください。
hook は settings.json の hooks と同じ構造を hooks/hooks.json に書く。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/after-edit.sh\""
}
]
}
]
}
}
4. marketplace.json(配布元の目録)
{
"name": "my-team",
"description": "社内向け Claude Code プラグイン集",
"owner": { "name": "your-team" },
"plugins": [
{
"name": "team-tools",
"source": "./plugins/team-tools",
"description": "team shared"
}
]
}
source は marketplace.json があるリポジトリのルートからの相対パス。別リポジトリに置いたプラグインは {"source": "git-subdir", "url": "...", "path": "...", "ref": "v1.0.0"} のようなオブジェクト形式でも指定できる(公式 marketplace でもこの形式が多数派だった)。
5. 検証する
配る前に必ず validate を通す。
$ claude plugin validate ./my-mkt
Validating marketplace manifest: /path/to/my-mkt/.claude-plugin/marketplace.json
⚠ Found 2 warnings:
❯ description: No marketplace description provided. ...
❯ plugins[0] plugin.json → author: No author information provided. ...
✔ Validation passed with warnings
marketplace を指定すると、中のプラグインの plugin.json までまとめて見てくれる。name にスペースを入れると、ちゃんとエラーで止まる。
✘ Found 1 error:
❯ name: Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")
✘ Validation failed
6. 追加してインストール
# ローカルパスでも GitHub の owner/repo でも追加できる
claude plugin marketplace add ./my-mkt
claude plugin install team-tools@my-team
claude plugin list
セッションを開き直すと /team-tools:review が補完候補に出る。チームメンバーには「marketplace add して install」の 2 行を渡すだけでよくなった。
ハマりどころ
ハマり 1:commands/ を .claude-plugin/ の中に入れて認識されない
症状:インストールは成功するのにコマンドが 1 つも出てこない。
原因:.claude-plugin/ に置くのは plugin.json(と marketplace.json)だけ。commands/ agents/ skills/ hooks/ はプラグインのルート直下に置く必要がある。「プラグイン関連のものは全部 .claude-plugin/ へ」と思い込むとこうなる。
厄介なのは、この配置ミスは validate を通ってしまう こと。実際に commands/ を .claude-plugin/ に移して試したが、結果は「passed with warnings」で、警告はどれも description や author に関するものだった。
回避策:validate の結果だけで安心しない。claude plugin details team-tools でプラグインに含まれるコンポーネントの一覧が見られるので、コマンドや hook がちゃんと数えられているか確認する。
ハマり 2:相対パスで書いた hook が動かない
症状:自分の手元(プラグインのリポジトリ内)では hook が動くのに、別のプロジェクトにインストールすると No such file or directory で失敗する。
原因:hook の command はユーザーが作業しているプロジェクトのディレクトリで実行される。bash hooks/after-edit.sh のような相対パスは、プラグインのリポジトリ内で試しているときだけ偶然解決できていた。
回避策:プラグイン内のファイルは必ず ${CLAUDE_PLUGIN_ROOT} 起点で書く。パスにスペースが入る環境もあるので、ダブルクォートで囲む。
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/after-edit.sh\""
プラグインに .mcp.json を同梱して MCP サーバーを起動する場合も同じで、args のスクリプトパスは ${CLAUDE_PLUGIN_ROOT} で書く。公式 marketplace の hook 付きプラグインも、全部この書き方になっていた。
ハマり 3:プラグインのソースを編集しても反映されない
症状:commands/review.md を直して保存したのに、Claude Code 上のコマンドは古い内容のまま動く。
原因:インストールされたプラグインはキャッシュ領域にコピーされて、そこから読み込まれる。手元のソースを書き換えても、インストール済みのコピーは変わらない。
回避策:用途によって 2 通りある。
# 開発中:インストールせず、そのセッションだけディレクトリから直接読む
claude --plugin-dir ./my-mkt/plugins/team-tools
# 配布後:version を上げてから目録とプラグインを更新
claude plugin marketplace update my-team
claude plugin update team-tools@my-team
自分は「開発は --plugin-dir、配る前に validate、配ったら version を上げる」の 3 つをルールにしてから、反映されない問題では悩まなくなった。version を上げ忘れると、メンバーの環境で更新されているのか目視で判断できなくなるので、変更したら必ず上げる。
背景・補足
自分は 24 時間稼働の完全自律実装システムを運用していて、司令塔役と複数の実装エージェントが同じレビュー手順や危険コマンドのブロック hook を共有している。以前はプロジェクトごとに .claude/ をコピーしていて、ブロック対象を 1 つ足すたびに全部直す必要があった。プラグイン化してからは、修正 → version を上げる → update で全プロジェクトに行き渡るようになり、「どこかの環境だけ古い hook のまま」という事故がなくなった。
hook や MCP を含むプラグインは、ユーザーの権限でシェルコマンドを実行する。社外の marketplace を追加する前に、中の hooks.json と .mcp.json に目を通す習慣はつけておいたほうがいい。
まとめ
- プラグイン =
.claude-plugin/plugin.json+ ルート直下のcommands/hooks/など - 配布は
marketplace.jsonを書いてmarketplace add→install 名前@marketplace名 -
validateは配置ミスまでは見てくれないので、plugin detailsで中身を確認する - hook や MCP のパスは
${CLAUDE_PLUGIN_ROOT}起点で書く - 開発中は
--plugin-dir、配布後は version を上げてupdateする