0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code のプラグイン(plugin.json・marketplace.json)を自作してチームに配る実装手順 — commands を .claude-plugin/ に入れて認識されない・相対パスで hook が動かない・編集が反映されない、3つのハマりどころ【2026】

0
Posted at

はじめに / 対象と前提

チームで 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 する
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?