Claude Media
Claude Codeプラグイン化の移行手順 — hooks/skills/agentsを移す

Claude Codeプラグイン化の移行手順 — hooks/skills/agentsを移す

既存の.claude/配下のcommands・agents・skills・hooksをプラグイン構造へ移す具体的な手順と、CLAUDE.mdが移行対象に含まれない理由をまとめます。

移す前に決めること: そもそもプラグインにするか

.claude/直下に置いたcommands・agents・skills・hooksは、そのプロジェクトの中だけで使う設定としては十分です。別のプロジェクトやチームへ配ろうとした途端、フォルダを手でコピーするしか方法がなくなります。コピーが古くなっても、それを知らせる仕組みはありません。

プラグインにすると、マーケットプレイス経由の/plugin installで配れます。更新の検知はversionで決まります。plugin.jsonにversionを書くと、その文字列を書き換えるまで、利用側は何コミット進んでも同じコピーのままです。versionを書かなければ、gitでホストされたマーケットプレイス経由なら、コミットのSHAが版の代わりになります。

同じリポジトリの中だけで使うなら、移さずに済む道もあります。<project>/.claude/skills/<名前>/の下に.claude-plugin/plugin.jsonを置くと、Claude Codeはそのフォルダをプラグインとして読みます。その場合はskills-dirプラグインの記事の手順で足ります。この記事は、複数のプロジェクトやチームへ配る前提で、.claude/の中身を別ディレクトリへ移す手順を扱います。

CLAUDE.mdだけは移せない

移せるのは、.claude/commands/・.claude/agents/・.claude/skills/と、設定ファイルのhooksキーの4つです。実際に持っているものだけを移せば足ります。

例外がCLAUDE.mdです。プラグインのルートに置いても、プロジェクトのコンテキストとしては読み込まれません。実際にコピーしてclaude plugin validateにかけると、次の警告が出ます(v2.1.289で実行)。

cp CLAUDE.md my-plugin/
claude plugin validate ./my-plugin
Validating plugin: .../my-plugin/CLAUDE.md
 
⚠ Found 1 warning:
 
  ❯ root: CLAUDE.md at the plugin root is not loaded as project context. To ship context with your plugin, use a skill (skills/<name>/SKILL.md) instead.

常時読ませたい指示があるなら、スキルとして書き直します。CLAUDE.mdそのものをプラグインにする手順は存在しません。

5つの手順で.claude/をプラグインに移す

次のコマンドは、.claude/があるプロジェクトルートで実行します。cpのパスがルートからの相対になっているためです。

手順

移行の5手順

  1. 1

    雛形を作る

    .claude/と同じ階層にプラグインのディレクトリを作ります。マニフェストはmy-plugin/.claude-plugin/plugin.jsonです。必須なのはnameだけで、descriptionとversionは書いておくと配布後に役立ちます。

    mkdir -p my-plugin/.claude-plugin
    {
      "name": "my-plugin",
      "description": "Migrated from standalone configuration",
      "version": "1.0.0"
    }
  2. 2

    commands・agents・skillsをコピーする

    持っているディレクトリだけをコピーします。存在しないものは飛ばします。

    cp -r .claude/commands my-plugin/
    cp -r .claude/agents my-plugin/
    cp -r .claude/skills my-plugin/

    ls -a my-pluginで、コピーしたディレクトリが.claude-pluginと並んでいれば完了です。

  3. 3

    hooksをhooks.jsonへ移す

    settings.jsonかsettings.local.jsonのhooksオブジェクトを、my-plugin/hooks/hooks.jsonへそのまま貼ります。形式は同じです。

    mkdir -p my-plugin/hooks
    {
      "hooks": {
        "PostToolUse": [
          {
            "matcher": "Write|Edit",
            "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npm run lint:fix" }]
          }
        ]
      }
    }
  4. 4

    --plugin-dirで読み込んで試す

    プラグインを1セッションだけ読み込みます。設定ファイルには何も書き込まれません。

    claude --plugin-dir ./my-plugin
  5. 5

    配る前にvalidateする

    マニフェストと、各コンポーネントのフロントマター・hooksを検査します。

    claude plugin validate ./my-plugin --strict

hooksのイベント名や設定パターンは、Claude Code Hooks完全ガイドがそのまま流用できます。

移行後の呼び出し名はどう変わるか

プラグイン内のスキル・コマンド・エージェントには、プラグイン名の接頭辞が付きます。公式の例では、/deployだったスキルは/my-plugin:deploy、reviewerだったエージェントはmy-plugin:reviewerとして呼び出します。commands/のフラットな.mdも同じで、commands/about.mdは/my-plugin:aboutになります。

commands/はskills/より古い形式です。新しく書くものはskills/<名前>/SKILL.mdにし、すでにあるファイルを移すときだけcommands/をそのまま使う、という使い分けが公式の案内です。

--plugin-dirで読み込んだ状態は、claude plugin listでも確かめられます。次はフラグを先に付けて実行した出力です(v2.1.289)。

claude --plugin-dir ./my-plugin plugin list
Session-only plugins (--plugin-dir / --plugin-url):
 
  ❯ my-plugin@inline
    Version: 1.0.0
    Path: .../my-plugin
    Status: ✔ loaded

読み込みに失敗したときは、セッション内の/pluginのErrorsタブに原因が出ます。claude plugin list --jsonならerrorsフィールドで読めます。ファイルを直したあとは/reload-pluginsで反映します。反映の詳細は/reload-pluginsの記事にあります。

元の.claude/を消し忘れるとどうなるか

移行が終わっても、元のファイルが.claude/に残っていれば、そちらも読み込まれ続けます。ここで押さえたいのは、コンポーネントごとに結果が違う点です。

くらべる

消し忘れの結果

両方が別名で並ぶ

skills・agents・commands

接頭辞が付くので衝突しません。/deployと/my-plugin:deployがどちらも動き、Claudeはreviewerとmy-plugin:reviewerを別々のサブエージェントとして見ます。壊れはしませんが、どちらが最新かをチームで取り違えやすくなります。

二重に実行される

hooks

hooksには接頭辞がありません。設定ファイルとhooks/hooks.jsonの両方に同じhookが残ると、イベントのたびに2回走ります。

プラグインの動作を確かめ終えたら、.claude/側の元ファイルを削除し、設定ファイルのhooksオブジェクトも消します。

agentの定義は、そのまま移せないフィールドがある

.claude/agents/のMarkdownをコピーしても、フロントマターの一部はプラグイン同梱のagentでは働きません。

扱い

プラグイン同梱agentのフロントマター

  • そのまま使える

    name / description / model / effort / maxTurns / tools / disallowedTools / skills / memory / background / omitClaudeMd / isolation(値は"worktree"のみ)/ color

  • 無視される

    permissionMode・hooks・mcpServers・initialPrompt。agentのファイルだけでhooksやMCPサーバーは足せません。プラグインのhooks/hooks.jsonと.mcp.jsonに移します。

  • パースできない

    フロントマターが壊れていても、プラグイン同梱のagentは読み込まれます。名前はファイル名から付き、説明は「Agent from my-plugin plugin」になり、残りのフィールドはすべて捨てられます。

3番目の挙動は、元の.claude/agents/と違います。壊れたフロントマターのファイルを2種類のディレクトリで検査すると、次のようになります(v2.1.289)。

元の.claude/側を検査した出力です。

Validating agent: .../proj/.claude/agents/broken.md
 
✘ Found 1 error:
 
  ❯ frontmatter: YAML frontmatter failed to parse: YAML Parse error: Unexpected token. At runtime this agent does not load at all — with no frontmatter name it is treated as a co-located reference document and skipped.

コピー先のプラグイン側を検査した出力です。

Validating agent: .../proj/my-plugin/agents/broken.md
 
✘ Found 1 error:
 
  ❯ frontmatter: YAML frontmatter failed to parse: YAML Parse error: Unexpected token. At runtime this agent loads with its name taken from the filename and every other frontmatter field silently dropped.

放置していた壊れたagentが、移行後は設定の抜けたまま有効になります。コピーしたら、使い始める前にclaude plugin validateを通しておく価値があります。なお、検査用のreviewer.mdに書いたpermissionMode: planには、検査の警告は出ませんでした。無視されることは警告では分からず、公式のフィールド表で確かめるしかありません。

validateと--strictは何を落とすのか

--strictは、警告をエラー扱いにします。実際に動かすと、境目がはっきり見えます。次の2つを同じプラグインで実行します(v2.1.289)。

claude plugin validate ./my-plugin
claude plugin validate ./my-plugin --strict

最初のコマンドは、authorが無いという警告を出したうえで✔ Validation passed with warningsで終わります。2つ目は同じ警告が理由で✘ Validation failed (--strict treats warnings as errors)となり、終了コードが1になります。plugin.jsonにauthorを足すと、どちらも✔ Validation passedです。

警告で済む間違いは、ほかにもあります。hooks.jsonのイベント名をpostToolUseと書いた例では、次の警告が出ました。

⚠ Found 1 warning:
 
  ❯ hooks: hooks.postToolUse: unknown hook event; entry ignored at runtime

イベント名は大文字小文字を区別します。警告のまま動き続けるので、--strictなしだと見逃します。移行元のsettings.jsonから貼っただけの状態でも、キー名の取り違えは起こりえます。配る前に--strictを一度通すと、この種のミスが拾えます。

移行後にhooksが動かないときの確認順

hookが発火しないときは、次の順に確認します。

  1. イベント名の大文字小文字: PostToolUseであってpostToolUseではない
  2. matcherが対象のツール名に合っているか: ファイル操作なら"Write|Edit"
  3. typeがcommand / http / mcp_tool / prompt / agentのどれかか
  4. スクリプトを単体で実行して、エラーなく終わるか
  5. 元の設定ファイルにも同じhookが残っていないか(二重実行の原因になります)

hookのコマンドの中でスクリプトを呼んでいるなら、パスの扱いも見直します。プラグインに同梱したスクリプトは${CLAUDE_PLUGIN_ROOT}/scripts/format.shのように書き、プロジェクト側のファイルを指すときは${CLAUDE_PROJECT_DIR}を使います。.claude/hooks/のスクリプトをプラグインのscripts/へ移したなら、hookのコマンドもその位置に書き換えが要ります。

hooksが発火したかどうかは、デバッグログで確かめます。PostToolUseのhookは0で終了するとトランスクリプトに何も出さないので、ログか、スクリプト自身が変えるものを見ます。

移行後に配る方法

ここまでは、--plugin-dirでローカルに読み込んだだけです。チームや社外へ配るには、marketplace.jsonをgitでホストして/plugin marketplace addしてもらうか、公式のディレクトリへ提出します。配布方法の使い分けはClaude Codeプラグイン(Plugins)完全ガイドにあります。

エージェント定義を見直すならClaude Code Sub-agents完全ガイド、スキルを作り直すならClaude Code Skills完全ガイドが土台になります。

まとめ

.claude/の中身は、コピーとマニフェストの追加でプラグインになります。CLAUDE.mdだけは移せないので、常時読ませたい指示はスキルに書き直します。

移行後に残る事故は、元ファイルの消し忘れによるhookの二重実行と、壊れたagentが静かに有効になることの2つです。二重実行はvalidateでは検出されないので、動作確認のあとに元ファイルを消す作業を忘れないようにします。agentの壊れたフロントマターと、イベント名の綴りミスは、配る前にclaude plugin validate ./my-plugin --strictで拾えます。

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