Claude Code Mods 入門:最初の Mod の作り方・テスト・導入手順と、コミュニティ実例 15 選
更新日

Claude Code の Mod は、Claude Code の内部で動く JavaScript または TypeScript の関数でできたプラグインです。ペインやプロンプト上部の行を描画したり、即座に実行されるスラッシュコマンドを追加したり、ツール呼び出しを実行前に止めたり書き換えたりできます。Mods は 2026年10月1日リリースの Claude Code 2.1.287 で導入され、デフォルトで有効になっています。
目的別の最短ルートは次のとおりです。
| やりたいこと | 方法 |
|---|---|
| コードを書かずに Mod を手に入れたい | セッションで作りたい Mod を説明します。たとえば「各ターンにかかった時間を表示する Mod を作って」と頼むと、Claude がコードを書き、ホットリロードを有効にするか一度だけ確認してきます |
| 他の人が作った Mod を導入したい | ターミナルのセッションで /plugin install <name>@<marketplace>、またはシェルで claude plugin install <name>@<marketplace> を実行します |
| 開発中のフォルダを読み込みたい | claude --plugin-dir ./my-mod |
| 組み込みのサイドエージェントを試したい | /plugin enable cc-plugin-you-should-know@builtin |
まずはバージョンを確認しましょう。claude --version が 2.1.287 以降を表示すれば使えます。Desktop アプリは独自の Claude Code を同梱していて、こちらは 2.1.286 から Mods が動きます。Code タブで /status を入力すると、そこで動いているバージョンを確認できます。
筆者が試したこと:2026年10月7日、macOS の Desktop アプリの Code タブで、Claude Code 2.1.293 を使って 3 つの Mod を作りました。コマンドガード、プロンプト上部のターンメーター、Python 作業用の
/pyenvコマンドです。3 つともclaude plugin validateを通過し、claude plugin testによる計 8 件の自動テストにもパスしています。ガードは、ホットリロードを有効にしたセッションでも実際に動かしました。コミュニティに関する節は、Zenn・Qiita・note に 10月1〜7日に公開された日本語記事約 50 本、公式の Mods ドキュメント (opens in a new tab)、10月6日時点の awesome-claude-code-mods (opens in a new tab) カタログのスキャンデータをもとにしています。
- Claude Code Mods 入門:最初の Mod の作り方・テスト・導入手順と、コミュニティ実例 15 選
- Laya の使い方:pandas でテキスト分類(Jev のオープンソース代替を4言語で実測)
- Claude Code が AGENTS.md を読むように:設定方法、4つの読み込みモード、Codex・OpenCode・Cursor との共用
- GPT Image 2.5の使い方:FlareとSunburstの違い・API料金
- DeepSeek Harness の使い方:インストール、初期設定、最初のエージェント実行まで
- Runcell Science:Claude Scienceのオープンソース代替となるAI研究ワークスペース
- Macをスリープさせない方法:Codex・Claude Codeを止めずに動かす
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: 2026年に選ぶべきAIエージェントスタックは?
- Claude CodeでJupyterノートブックを分析する方法|Data Science向けの実践ポイントと限界
- Claude Code Routinesとは?AIエージェントの定期実行と自動化を理解する
- Claude Code DesktopでBypass permissionsを有効にする方法
- GoogleのA2Aプロトコルで2つのPythonエージェントを構築する方法 - ステップバイステップチュートリアル
- 2025年のPythonで人気のあるトップ10のデータ可視化ライブラリ
Mod とは何か、ほかの拡張方法との使い分け
Mods が登場するまで、Claude Code は外側から拡張するものでした。手段は settings hook(settings.json に書く従来のフック)、スキル、ステータスラインのスクリプト、MCP サーバーなどです。違いはコードが動く場所にあります。settings hook は、Claude Code が外から起動するスクリプトです。一方、Mod の関数は Claude Code 自身のプロセスの中で動きます。そのため、インターフェースに描画できるのは Mod だけです。
公式の概要ページでは、おおよそ次のように比較されています。
| Mod | Settings hook | スキル | MCP サーバー | |
|---|---|---|---|---|
| 実体 | プラグイン内の JS / TS 関数 | settings.json に書くシェルコマンド、HTTP 呼び出し、プロンプト | 指示を書いた SKILL.md ファイル | Claude にツールを提供する外部プロセス |
| UI への描画 | できる | できない | できない | できない |
| 変更できる対象 | ツール呼び出し、プロンプト、コマンド、ターン、UI | 呼び出しを通すかどうか、その引数と結果、追加のコンテキスト | Claude の知識と行動 | Claude が使えるツール |
| 向いている場面 | ペイン、バンド、即時実行のコマンドが欲しいとき、イベントを書き換えたいとき | ブロックやログ記録をするスクリプトがすでにあるとき | 同じ指示を何度も貼り付けているとき | Claude を外部システムにつなぐ必要があるとき |
名前の紛らわしさに注意してください。Mods のドキュメントで「hook」と書かれていたら、それは Mod の関数のことです。従来の仕組みは「settings hook」と呼ばれています。この記事でも「フック」は Mod の関数を指します。settings hook は今も動作し、非推奨にもなっていません。1 つのプラグインに Mod、スキル、MCP サーバーをまとめて入れることもできます。
Mods が動く場所
フックはほぼどこでも動きますが、描画されるのはターミナルと Desktop アプリだけです。
| Claude Code の実行環境 | フック | Mod の UI |
|---|---|---|
ターミナルの claude(エディタ内のターミナル、JetBrains を含む) | 動く | 表示される |
| Desktop アプリの Code タブ | 動く | 表示される(ターミナル専用の要素を除く) |
| Desktop アプリの WSL セッション | 動かない | 表示されない |
| VS Code 拡張のチャットパネル | 動く | 表示されない |
claude -p と Agent SDK | 動く | 表示されない |
| クラウドセッション | プラグインがセッションに届いていれば動く | 表示されない |
この表は公式の概要ページにもとづいています。つまり、ガード系の Mod は VS Code や claude -p でも守ってくれますが、メーター系の Mod は描画する場所がありません。
Claude Code が 2 つ入っている環境にも注意が必要です。日本語の記事では、複数の著者が紛らわしい validate エラーに遭遇しています。原因は、Homebrew で入れた古いターミナル版 CLI(報告ではバージョン 2.1.226 と 2.1.234)が、Desktop アプリ同梱の 2.1.286 と共存していたことでした。使う場所ごとにバージョンを確認してください。
Mod のファイル構成
小さな Mod なら、ファイルは 3 つで済みます。
safe-shell/
├── .claude-plugin/
│ └── plugin.json name, version, description
└── hooks/
├── hooks.json { "modules": ["./register.ts"] }
└── register.ts your coderegister.ts は register(on) という関数を 1 つ export します。on(event, matcher, hook) を呼ぶたびにフックが 1 つ追加され、どのフックも同じ 3 つの引数を受け取ります。
$はエンジンです。自分のコードの外にあるものは、すべて$を経由して使います。$.ui.toast、$.process.run、$.state、$.model.completeなどです。eはイベントです。たとえば、Claude がこれから実行しようとしている Bash コマンドがこれにあたります。next(e)は、イベントをほかの Mod に渡し、最後に Claude Code に渡します。呼ばずに return すれば、そのフック自身が応答したことになります。next({ ...e, command })のように呼べば、実際に起きる処理を変えられます。
モジュールからは Node も DOM も使えません。この制約があるからこそ、Claude Code は Mod が呼び出すものを実行前にすべて列挙できます。手元の Mod フォルダで試してみてください。
claude plugin validate ./safe-shellMod 1:破壊的なコマンドをブロックするガード
auto モードや Bypass permissions で Claude を動かしていると、git reset --hard の前に Claude を止めるものは何もありません。この Mod は 3 種類のシェルコマンドを拒否し、.env ファイルを会話に持ち込ませません。
import type { Register } from 'claude-code'
// Shell commands an agent should never run without a human typing them.
const BLOCKED: { pattern: RegExp; reason: string }[] = [
{
pattern: /\brm\s+-[a-zA-Z]*[rR][a-zA-Z]*\s+(\/|~|\$HOME)\/?\*?(\s|$)/,
reason: 'recursive delete of / or the home folder',
},
{
pattern: /\bgit\s+push\b.*(--force\b|--force-with-lease\b|\s-f\b).*\b(main|master)\b/,
reason: 'force push to main or master',
},
{
pattern: /\bgit\s+reset\s+--hard\b/,
reason: 'git reset --hard throws away uncommitted work',
},
]
// .env, .env.local, config/.env.production ... but not .env.example.
const isSecretEnvFile = (path: string) =>
/(^|\/)\.env(\.[^/]+)?$/.test(path) && !/\.(example|sample|template)$/.test(path)
export const register: Register = on => {
on('tool.call', { tool: 'Bash' }, ($, e, next) => {
const hit = BLOCKED.find(rule => rule.pattern.test(e.command))
if (hit === undefined) {
return next(e)
}
$.ui.toast(`safe-shell blocked: ${hit.reason}`)
return { deny: `safe-shell: blocked (${hit.reason}). Ask the user to run it themselves.` }
}).catch(($, e, next) =>
// Fail closed: if the guard itself breaks, refuse instead of letting the command through.
next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the command was not run.' },
)
for (const tool of ['Read', 'Edit', 'Write'] as const) {
on('tool.call', { tool }, ($, e, next) =>
isSecretEnvFile(e.file_path)
? { deny: `safe-shell: ${e.file_path} holds secrets and stays out of the conversation.` }
: next(e),
).catch(($, e, next) =>
next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the file was not touched.' },
)
}
}正規表現そのものより大事なポイントが 2 つあります。
ガードは next を呼ぶ前に判定する。next が動いた時点で、コマンドはもう実行されています。そのあとで deny を返しても、何も取り消せません。
.catch で fail closed にする。例外を投げたフックや、10 秒の持ち時間を超えたフックはスキップされます。そしてスキップされたガードは、コマンドをそのまま通してしまいます。next.called ? next(e) : deny のハンドラーは、その場合でも通さずに拒否します。validate は判定を行うフック(gating hook)をすべて列挙し、それぞれに .catch があるかどうかも表示します。他人が作ったガードでは、最初にここを確認してください。
❯ ./register.ts hooks: tool.call{tool=Bash}, tool.call{tool=Read|Edit|Write}
❯ ./register.ts gating hook with .catch: tool.call{tool=Bash}
❯ ./register.ts gating hook with .catch: tool.call{tool=Read|Edit|Write}
❯ ./register.ts calls: $.ui.toast
✔ Validation passedセッションなしでテストする
claude plugin test は、Mod の *.test.ts ファイルをエンジン上で実行します。セッションもサインインもネットワークも不要です。ただし、テストキットでは Mod の下に何もありません。そのため各テストで、Mod が次に渡す処理を受け止める代役のフック(スタブ)を登録します。
import { expect, test } from 'claude-code/testing'
const ran = { stdout: 'ran', stderr: '', interrupted: false }
test('blocks rm -rf on the home folder', async ($, on) => {
on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ~' })
expect(answer.deny).toContain('recursive delete')
})
test('lets ordinary commands through', async ($, on) => {
on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ./build && python -m pytest -q' })
expect(answer.deny).toBeUndefined()
})ファイル全体では 4 件のテストがあります。
(pass) blocks rm -rf on the home folder [16.23ms]
(pass) blocks a force push to main [7.73ms]
(pass) lets ordinary commands through [7.22ms]
(pass) keeps .env out of Read but allows .env.example [9.40ms]
4 pass
0 fail筆者の最初の実行は、on("tool.call") after the test first called $ というエラーで失敗しました。代役のフックは、各テストの冒頭、最初に $ を呼ぶ前に登録してください。
実際のセッションでの挙動
ホットリロードを有効にした状態で、Claude に echo "the words git reset --hard inside an echo" を実行させてみました。ガードは「blocked (git reset --hard throws away uncommitted work)」として拒否し、トーストも表示されました。しかし、この echo は無害です。パターンマッチでは、コマンドと、コマンドに言及しているだけのテキストを区別できません。変数、スクリプト、エイリアスに隠れたコマンドも見逃します。rafi-guard、delete-guard、board-guard など、似たガードを公開した国内の開発者も、この 2 つの問題を報告しています。
ガード系の Mod は、2 枚目のセーフティネットとして扱いましょう。絶対に起きてはいけない操作は、パーミッションの deny ルールにも入れておきます。逆方向のリスクにも注意してください。公式ドキュメントによると、managed settings(組織が配布する管理設定)のない個人のマシンでは、deny ルールが拒否する呼び出しを Mod が承認できてしまいます。Mod はサンドボックス化されておらず、ユーザー自身の権限で動きます。
Mod 2:プロンプト上部のメーター
Mod の描画先として多いのは、プロンプト上部のバンドとサイドペインです。10月6日のカタログのスキャンでは、41% の Mod がバンドに描画し、40% がペインを開いていました。ここで作る Mod は、直前のターンの所要時間、ツール呼び出し数、トークン数を表示します。Hide ボタンで隠すこともできます。
描画で読む値は $.state に置き、それぞれを小さな型定義ファイルで宣言します。
// types/index.d.ts, named in plugin.json as "types": "./types/index.d.ts"
export type TurnStats = {
seconds: number
tools: number
inputTokens: number
outputTokens: number
model: string | null
}
declare module 'claude-code' {
interface PluginState {
'turn-meter': { last: TurnStats | null; isHidden: boolean }
}
}フックでツール呼び出しを数え、turn.complete から durationMs と usage を読み取って、バンドを描画します。
import { atom, read, update } from 'claude-code'
import type { Register } from 'claude-code'
import type { TurnStats } from '../types'
const last = atom({ plugin: 'turn-meter', key: 'last' } as const, null)
const isHidden = atom({ plugin: 'turn-meter', key: 'isHidden' } as const, false)
const formatTokens = (n: number) => (n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n))
export const register: Register = on => {
let tools = 0
on('prompt.submit', ($, e, next) => {
tools = 0
return next(e)
})
on('tool.call', ($, e, next) => {
// Count the main conversation's calls; subagents carry an agentId.
if (e.agentId === undefined) tools += 1
return next(e)
})
on('turn.complete', async ($, e, next) => {
if (e.agentId !== undefined) return next(e)
const usage = e.usage
const stats: TurnStats = {
seconds: Math.round(e.durationMs / 1000),
tools,
inputTokens: usage
? usage.input_tokens + usage.cache_read_input_tokens + usage.cache_creation_input_tokens
: 0,
outputTokens: usage?.output_tokens ?? 0,
model: usage?.model ?? null,
}
await update($, last, () => stats)
if (stats.seconds > 120) $.ui.toast(`That turn took ${stats.seconds}s`)
return next(e)
})
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
const stats = await read($, last)
if (e.props.hasSurvey || stats === null || (await read($, isHidden))) return next(e)
const { Box, Button, Text } = $.ui.resolve(e)
const model = stats.model === null ? '' : ` · ${stats.model}`
// The band is shared by every mod: keep what the mods beneath drew, then add a row.
const below = await next(e)
return (
<Box flexDirection="column">
{below}
<Box>
<Text dimColor>
{`Last turn: ${stats.seconds}s · ${stats.tools} tool calls · ${formatTokens(stats.inputTokens)} in / ${formatTokens(stats.outputTokens)} out${model} `}
</Text>
<Button key="hide" label="Hide" onPress={() => update($, isHidden, () => true)} />
</Box>
</Box>
)
})
}テストでは、ターミナルと Desktop のどちらのサーフェスでも、バンドは次のように表示されました。
Last turn: 42s · 0 tool calls · 18.2k in / 800 out · claude-opus-5-5 [ Hide ]作ってみてわかったことが 3 つあります。
- 描画する値は、モジュール変数ではなく
$.stateに置きます。ホットリロードではregisterが再実行されて変数がリセットされますが、$.stateは残ります。/clearすると最初からになるので、それより長く残したい値はsession.endで$.storeに書き込みます。 - バンドは全 Mod で共有されます。
next(e)を呼び、その結果を自分のBoxの中に入れてください。そうしないと、ほかの Mod の行がすべて隠れてしまいます。ある note の著者は、この仕組みに気づくまで、自作のバンドの 1 つを別の Mod に隠されていました。 Text要素はkeyを保持しません。テストではui.find({ type: 'Text', text: /Last turn/ })のように、表示している文字列で探します。
Mod 3:Claude が別の Python を使ってしまうときの /pyenv
データサイエンス向けの Mod を探したところ、空白地帯が見つかりました。10月6日のスキャンに含まれる 2,690 個の Mod のうち、名前や説明で Jupyter、pandas、DataFrame、Polars、venv、conda に触れているものは 1 つもありません。
この Mod が扱う問題は、データ分析ではよくあるものです。Claude の Bash ツールは PATH 上で最初に見つかった python3 を実行しますが、それがプロジェクトの環境とは限りません。筆者のマシンで環境チェック用のスクリプト(以下、プローブ)を実行すると、次のように出力されました。
python: /Users/<you>/.local/bin/python3 (3.14.2)
env: none (system or tool-managed Python)
pandas: 3.0.1
numpy: 2.4.2
polars: not installed
matplotlib: 3.11.0
pygwalker: not installed仮想環境が有効になっていなかったため、もし Claude が pip install を実行していたら、グローバルのインタープリターにインストールされていたはずです。
/pyenv コマンドはこのプローブを実行し、2 つの部分で応答します。text は画面に表示される行です。context はモデルだけが読むメモです。これにより Claude の次の Bash 呼び出しは、ユーザーが改めて指示しなくても、どのインタープリターが使われているかを把握できます。
import type { Register } from 'claude-code'
// Reads package versions from metadata instead of importing them, so it stays fast.
const PROBE = `
import os, sys
from importlib.metadata import PackageNotFoundError, version
env = os.environ.get("VIRTUAL_ENV") or os.environ.get("CONDA_PREFIX") or "none (system or tool-managed Python)"
print(f"python: {sys.executable} ({sys.version.split()[0]})")
print(f"env: {env}")
for name in ("pandas", "numpy", "polars", "matplotlib", "pygwalker"):
try:
print(f"{name}: {version(name)}")
except PackageNotFoundError:
print(f"{name}: not installed")
`
export const register: Register = on => {
on('session.start', async ($, e, next) => {
await $.command.register({
name: 'pyenv',
description: "Show which Python, environment and data packages this session's shell uses",
})
return next(e)
})
on('command.run', { command: 'pyenv' }, async $ => {
try {
const probe = await $.process.run(['python3', '-c', PROBE], { timeoutMs: 15_000 })
if (probe.exitCode !== 0) {
return { text: `pyenv: python3 exited with ${probe.exitCode}: ${probe.stderr.trim().slice(0, 300)}` }
}
const report = probe.stdout.trim()
// `text` is the row you see; `context` is a note only the model reads.
return {
text: report,
context: [`Python environment of this session's shell, from /pyenv:\n${report}`],
}
} catch (error) {
return { text: `pyenv: could not run python3 (${String(error).slice(0, 200)})` }
}
})
}Mod のスラッシュコマンドは、モデルのターンを挟まずに関数をすぐ実行します。Claude が作業中でも動きます。$.process.run はシェルを通さず引数のリストを受け取り、timeoutMs を指定しなければ 30 秒でタイムアウトします。
$.process.run は Claude の Bash ツールと同じ PATH を見ているのでしょうか。Mod から起動したプロセスで nvm の node が見つからなかったという報告があったので、一時的な調査用 Mod で確かめました。筆者の Desktop セッションでは、そのままの $.process.run は Bash ツールとまったく同じ PATH を受け取り、python3 も同じものを指していました。逆に、ログインシェル zsh -lc 経由で同じ調査を走らせると、python.org の 3.10.9 という別のインタープリタを返しました。非対話のログインシェルは ~/.zshrc を読まず、PATH の追加設定の多くはそこにあるためです。呼び出しはシェルを挟まないまま使いましょう。結果がおかしいと感じたら、Claude Code のプロンプトで !which python3 を実行して見比べてください。
テストでは、もう 1 つ落とし穴が見つかりました。$.process.run や $.command.register のような $ の呼び出しにも代役が必要で、$ 呼び出しの代役は { value: ... } の形で応答します。結果をそのまま返すと、テストキットに拒否されます。
分析の大半をスクリプトではなくノートブックで行っているなら、この方法には限界があります。Claude Code は .ipynb ファイルを JSON として編集するだけで、実行中のカーネルを見ることはないからです。RunCell (opens in a new tab) はセルを実行し、その出力を直接読むノートブック向けのエージェントなので、こうした作業にはこちらのほうが向いています。
Mod を Claude に書かせる
ここまでのコードは、手で書く必要はありません。セッションで「5 時間枠の使用量をプロンプトの上に表示する Mod を作って」のように頼むだけです。Claude は組み込みの plugin-authoring スキルを読み込み、~/.claude/dev-mods/<session-id>/ にファイルを書き出します。最初のファイルを書くときに、「Enable hot reloading for this session?」という確認が一度だけ出ます。同意すると、以降は Claude のターンが終わるたびに編集内容がリロードされます。上の 3 つの Mod も、この方法で作って読み込みました。
ドキュメントとコミュニティからの補足です。
- フォルダは恒久的な場所にコピーしておきましょう。Qiita や Zenn の著者によると、dev-mods フォルダは約 30 日たつと古いセッションと一緒に削除されます。
- 開発中は
claude --plugin-dir ./my-modで起動します。インストールした Mod はキャッシュされたコピーで動くため、元のフォルダを編集しても、プラグインを更新するまで何も変わりません。 - Desktop アプリには起動フラグを渡せません。代わりに
~/.claude/settings.jsonのenvブロックでCLAUDE_CODE_PLUGIN_DIRSを設定します。プロジェクトの設定ファイルに書いても、この設定は無視されます。 /pluginを実行して、1 mod active · safe-shellのような薄い色の行が出れば、Mod は読み込まれています。- 開発中は
claude --debugで起動しましょう。デバッグログには、スキップされたフックと、エンジンが拒否した描画がすべて記録されます。
参考になるコミュニティ製 Mod 15 選
スター数 316 の awesome-claude-code-mods (opens in a new tab) カタログは、リリースから 5 日後の 10月6日に、1,265 のリポジトリにある 2,690 個の公開 Mod をスキャンしました。そのデータから、どんな Mod が作られているかが見えてきます。
- 68% がスラッシュコマンドを追加
- 53% がツール呼び出しをフック
- 41% がプロンプト上部に描画、40% がペインを開く
- 40% がプロセスを起動、12% がモデルを呼び出し、11% がネットワークを使用
幅の広さがわかる 15 個を紹介します。スター数は 2026年10月7日時点のものです。
| Mod | 内容 | スター | 注目ポイント |
|---|---|---|---|
| terminal-browser (opens in a new tab) | 会話の横に Web ブラウザを表示し、Web サイト、ローカル HTML のプレビュー、プルリクエストを閲覧できる | 3,695 | 現時点で最も野心的なペイン |
| claude-image-view (opens in a new tab) | 貼り付けた画像を、[Image #1] の代わりにサムネイルでプロンプト上部に表示 | 160 | ターミナルでの画像描画 |
| hamzafer/claude-code-mods (opens in a new tab) | コンテキストバー、blast-radius ガード、Markdown プレビュー、サブエージェントのダッシュボードをまとめたセット | 138 | 1 つのリポジトリに複数タイプの Mod |
| claude-auto-handoff (opens in a new tab) | 長くなったセッションを、構造化した引き継ぎメモ付きで新しいセッションに渡す | 60 | コンテキスト管理 |
| prismantis (opens in a new tab) | 返信をテーマで装飾。表、コード、チャートをボックスアートで描き、右から左に書くテキストにも対応 | 49 | Claude 自身のメッセージの見た目を変える手法 |
| cc-arcade (opens in a new tab) | プロンプト上部で遊べる 9 つのゲーム。Claude の処理が終わると一時停止 | 41 | フレームクロックを使ったアニメーション |
| jev-permission-gate (opens in a new tab) | auto モードのツール呼び出しを Jev の判定モデルが審査 | 28 | 丁寧なプライバシーの説明。直近 3 件のメッセージを各 1,500 文字まで TypeSafe の API に送ると明記 |
| prompt-rail (opens in a new tab) | 過去のプロンプトをレール状に並べ、ホバーで内容を表示、クリックでその位置にジャンプ | 22 | Zenn で最もいいねを集めた日本語の Mods レビュー記事の主役 |
| claude-paste-view (opens in a new tab) | 貼り付けた画像や長いテキストをプレビュー | 18 | 小さく読みやすいコード |
| claude-gfm-render (opens in a new tab) | 返信内の GitHub アラート、タスクリスト、Mermaid を、ボックスアートまたは SVG で表示 | 14 | サーフェスごとに描画を切り替える方法 |
| claude_qamods (opens in a new tab) | qa-guide が、Claude からの質問と選択肢をサイドペインで解説 | 10 | 組み込みダイアログの改善 |
| CC-Usage-Band (opens in a new tab) | 5 時間枠と 7 日間の利用上限、コンテキスト、キャッシュヒット率をプロンプト上部に表示 | 10 | 最も多いタイプであるメーター系の例 |
| harness-scope (opens in a new tab) | リポジトリごとのプロファイルで、グローバルなスキル、エージェント、ルールを非表示にする | 1 | 作者の計測では、スキル一覧が 98 件から 49 件に減少 |
| touch-map (opens in a new tab) | Claude がどのファイルを一覧、読み取り、編集、作成したかを表示 | 0 | 作者は、あるリファクタリングの調査中に Claude が 304 ファイル中 125 ファイルに触れていたことを確認 |
| claude-mods-router (opens in a new tab) | $.model.classify でプロンプトごとに effort レベルを振り分ける | 0 | Qiita の解説記事(26 いいね)が、モデルを切り替えるとプロンプトキャッシュが効かなくなると指摘 |
Anthropic も claude-code-playground (opens in a new tab) で、token-weather、blast-radius、replay-theater の 3 つのサンプルを公開しています。/diff を含む組み込み Mod のソースは、claude-code リポジトリ (opens in a new tab) にあります。
コミュニティで定着したベストプラクティス
リリース後の 1 週間で、日本語の記事だけでも約 50 本が公開され、動く Mod、計測結果、失敗の報告が共有されました。そこで何度も挙がった習慣をまとめます。
- 導入する前に Mod を読む。リポジトリを clone して
claude plugin validateを実行し、hooks:とcalls:の行を確認します。$.process、$.http、$.fs.write、$.env.get、$.modelが出てくる箇所はソースを読みましょう。更新のたびに validate し直してください。validate を通過しても、エンジンがコードを読み込めるというだけで、コードが安全だという意味ではありません。 - ガードは
nextの前に判定し、fail closed にする。監視するだけの Mod は、逆に.catch(($, e, next) => next(e))で fail open にします。こうすれば、メーターのバグで作業が止まることはありません。 - 待つなら
$の呼び出しの中で待つ。フックが自分の処理に使える時間は 10 秒です。実行中の$.process.runや$.ui.askの待ち時間はこれに数えられませんが、自分で作った Promise の待ち時間は数えられます。 $を保存したり分割代入したりしない。$は、ファイルのトップレベルで宣言した関数にだけ渡します。複数の著者が、これを直すまで Mod がエラーも出さずに読み込まれなかったと報告しています。- プロンプトキャッシュに気を配る。セッションの途中でモデルを切り替えたり、リクエストごとにシステムプロンプトを変えたりすると、キャッシュが捨てられます。
e.surfaceで分岐する。Svgは Desktop アプリでしか描画されず、RasterとImageはターミナルでしか描画されません。- チームで使うならバージョンを固定する。API はアーリーアクセス段階で、リリースごとに変わります。公開後に出た 6 つのリリース(2.1.288〜2.1.293)のうち 5 つで、Mod の挙動が変更または修正されました。
シークレットのマスキングは、教訓になる事例です。ある note の著者は、ツールの出力に含まれる API キーを、Claude が見る前に置き換える Mod を作りました。それでも Claude は、失敗した編集を od -c でデバッグする途中で生の値を表示しました。さらに、ファイル全体を書き直す Write で、本物のキーがプレースホルダーに上書きされました。最後まで守れたのは、そのファイルに対するパーミッションの deny ルールだけでした。画面の表示を変える Mod は、モデルからは何も隠せません。
よくあるトラブルと対処法
| 症状 | 考えられる原因 | 対処法 |
|---|---|---|
/plugin に Mod が表示されない | 信頼されていないフォルダ、--safe-mode、--bare、disableAllHooks のいずれか | フォルダを信頼し、フラグを外して再起動する |
hooks modules are turned off in this process と出る | Anthropic がインストール済みの Mod をリモートで無効にした | ローカルで直す箇所はない。2.1.289 と 2.1.290 で Mod が無効のままになる 2 つのケースが修正されたので、アップデートする |
validate が「expected record, received undefined」で失敗する | PATH 上で古い CLI が先に見つかっている | claude --version を実行して確認し、アップデートする |
| フックがエラー表示なしにスキップされる | 例外が出ている。たとえば $.plugin.name() を呼び出したが、これは関数ではなくプロパティ | claude --debug で起動し、スキップの行を読む |
| ペインが開かない | 自動で開くペインは、幅が 144 カラム以上になるまで開かない。トランスクリプトの横にドッキングするのはフルスクリーンレイアウトのときだけで、/diff に覆われることもある | ウィンドウを広げる、フルスクリーンレイアウトを試す、/diff を閉じる |
| ターミナルでは動くのに Desktop では動かない | Desktop は独自のバージョンを同梱しており、ターミナル専用の要素もある | Code タブで /status を確認し、e.surface で分岐する |
VS Code や claude -p で Mod の UI が出ない | これらのサーフェスは描画を行わない | トランスクリプトに出す行や、コマンドが返すテキストで代用する |
| テストが「nothing beneath the plugins answers」で失敗する | テストキットにはエンジンがない | 代役のフックを追加し、$ の呼び出しには { value } で応答する |
Mod を公開する
.claude-plugin/ の中の、plugin.json の隣に marketplace.json を置きます。
{
"name": "my-mods",
"owner": { "name": "you" },
"plugins": [{ "name": "safe-shell", "source": "./" }]
}フォルダを GitHub に push すれば、誰でもターミナルのセッションから導入できます。
/plugin install safe-shell --marketplace you/safe-shellDesktop アプリでは、ローカルセッションと SSH セッションで + → Plugins → Add plugin の順に進みます。リポジトリに claude-code-mod トピックを付けておくと、次に push してから数時間以内に、たいていコミュニティのカタログに載ります。
FAQ
Related Guides
- Claude Code DesktopでBypass permissionsを有効にする方法
- Claude CodeのAGENTS.md設定と移行: 4つの読み込みモードとCLAUDE.mdとの違い
- Claude Code Routinesとは?AIエージェントの定期実行と自動化を理解する
- Claude Agent SDK(TypeScript)でClaude Code風AIエージェントを自作する
- OpenCodeの使い方ガイド: 始め方、実践Tips、Oh My OpenCodeとの使い分け