CLAUDE.md の書き方で押さえたいのは、CLAUDE.md が Claude Code に毎回読み込ませる「お願い」のメモだという点です。命名規則や Sass の構成は、ここに具体的に書けば守られやすくなります。一方で、本番サーバーへの接続や SQL の直接実行のように絶対に止めたいことは、settings.json の permissions と hooks で「仕組み」として止めるのが確実です。
この記事では、CLAUDE.md・.claude/rules・スキル・サブエージェント・permissions と hooks の 5 つの仕組みを、Web 制作チームでの役割分担とあわせて紹介します。どの設定例も、そのままファイルにして試せる形にしています。
設定例はすべて、Vite + Sass + PHP で WordPress テーマを作る架空のチームを想定したものです。仕様は 2026 年 11 月 10 日時点の公式ドキュメントで確認しましたが、Claude Code は更新が速いため、導入するときは公式ドキュメントもあわせて確認してください。
Claude Code にルールを守らせる 5 つの仕組みと役割分担

「CLAUDE.md に書いたのに守ってくれない」という悩みの多くは、書く場所の選び方で解決できます。まずは全体像を押さえましょう。
CLAUDE.md・rules・スキル・サブエージェント・hooks・permissions の違い
公式ドキュメントの「Claude Code を拡張する」の比較をもとに、Web 制作の例を当てはめて整理すると次のようになります。
| 仕組み | 読み込み・実行のタイミング | 強制力 | 向いている内容 | Web 制作での例 |
|---|---|---|---|---|
| CLAUDE.md | 毎セッションの開始時 | なし(お願い) | 常に守ってほしい規約、ビルドコマンド | 「npm run dev で起動」「クラス名は FLOCSS + BEM」 |
| .claude/rules | 毎セッション、または該当ファイルを扱うとき | なし(お願い) | 分野別の細かい規約 | Sass 用・PHP 用のルール |
| スキル | 呼び出したとき(または Claude が必要と判断したとき) | なし(お願い) | 定型の手順 | テーマ雛形の作成 |
| サブエージェント | 起動したとき(独立したコンテキストで動く) | 指示はお願い、使えるツールの制限は強制 | レビューや調査 | 書き換え不可のレビュー担当 |
| permissions | 常時 | Claude Code 本体が強制 | 危険な操作の拒否・確認 | ssh や .env の読み込みを拒否 |
| hooks | イベントの発生時 | 決まった処理を必ず実行 | 整形の自動化、操作のブロック | 編集後の stylelint、mysql のブロック |
CLAUDE.md・rules・スキルは「Claude に読ませて判断してもらう」仕組みで、permissions と hooks は「Claude の判断に関係なく Claude Code が処理する」仕組みです。サブエージェントはその中間で、指示の中身はお願いですが、使えるツールの制限は仕組みとして効きます。
「お願い」と「強制」を分けて考える
公式ドキュメントは、CLAUDE.md を「強制される設定ではなく、コンテキスト」と位置づけ、権限ルールは「モデルではなく Claude Code が強制する」と説明しています。「.env を編集しない」と CLAUDE.md に書くのはお願いで、PreToolUse フックでブロックするのが強制、という例も挙げられています。
そこでこの記事では、次のように使い分けます。
- お願い(CLAUDE.md・rules・スキル): 命名規則、Sass の書き方、作業の手順など、守られると品質が上がること
- 中間(サブエージェント): 役割の指示はお願い、使わせないツールは強制で外す
- 強制(permissions・hooks): 本番接続、SQL の直接実行、WordPress 本体の編集など、一度でも起きると困ること
禁止事項は「お願い」にも書き、「強制」でも止めるのがポイントです。理由を書いておけば Claude は最初から別の方法を選び、それでも実行しようとしたときは仕組みで止まります。
この記事で使う架空プロジェクトの構成
ここからの設定例は、すべて次の架空プロジェクト「sample-project」を前提にしています。Vite + Sass + BrowserSync で開発し、PHP の WordPress テーマとして納品する案件を想定しました。
sample-project/
├── CLAUDE.md # チーム共有の指示(git 管理)
├── CLAUDE.local.md # 個人用の指示(git 管理外)
├── .claude/
│ ├── settings.json # チーム共有の権限と hooks(git 管理)
│ ├── settings.local.json # 個人用の設定(git 管理外)
│ ├── rules/
│ │ ├── naming.md
│ │ ├── sass.md
│ │ ├── php.md
│ │ └── security.md
│ ├── skills/
│ │ └── scaffold/
│ │ ├── SKILL.md
│ │ ├── reference.md
│ │ └── templates/
│ ├── agents/
│ │ ├── code-reviewer.md
│ │ └── writer.md
│ └── hooks/
│ ├── block-remote-and-sql.sh
│ └── lint-after-edit.sh
├── docs/
│ ├── coding-guide.md
│ └── drafts/
├── src/
│ ├── scss/
│ │ ├── global/ # 変数・mixin・関数
│ │ ├── foundation/
│ │ ├── layout/
│ │ ├── object/
│ │ │ ├── component/
│ │ │ ├── project/
│ │ │ └── utility/
│ │ └── style.scss
│ └── js/
│ └── main.js
├── themes/
│ └── sample-theme/ # 編集してよいテーマ
│ ├── CLAUDE.md # テーマ固有の指示
│ ├── assets/ # ビルドの出力先
│ ├── functions.php
│ └── template-parts/
├── wp/ # WordPress 本体(編集禁止)
├── package.json
├── vite.config.js
└── README.md
ポイントは、Claude Code 用の設定がプロジェクト直下の CLAUDE.md と .claude/ フォルダにまとまっていることです。
CLAUDE.md の置き場所と読み込まれる範囲
CLAUDE.md は、置く場所によって効く範囲が変わります。
4 つのスコープ(管理ポリシー / ユーザー / プロジェクト / ローカル)
公式ドキュメント「Claude があなたのプロジェクトを記憶する方法」では、CLAUDE.md の置き場所として次の 4 つが挙げられています。
| スコープ | 置き場所 | 効く範囲 | 主な用途 |
|---|---|---|---|
| 管理ポリシー | macOS は /Library/Application Support/ClaudeCode/CLAUDE.md、Linux / WSL は /etc/claude-code/CLAUDE.md など | その端末のすべてのユーザー | 会社全体の規約やセキュリティ方針 |
| ユーザー | ~/.claude/CLAUDE.md | 自分のすべてのプロジェクト | 個人の共通ルール |
| プロジェクト | ./CLAUDE.md または ./.claude/CLAUDE.md | git で共有したチーム全員 | 案件の規約、ビルドコマンド |
| ローカル | ./CLAUDE.local.md | 自分だけ(そのプロジェクト) | 個人用の検証 URL など。.gitignore に追加する |
大事なのは、これらが上書きではなく連結されて読み込まれることです。起動したディレクトリに近いものほど後に読まれ、同じディレクトリでは CLAUDE.local.md が CLAUDE.md の後に続きます。
上の階層は起動時、サブディレクトリは必要になったときに読み込まれる
Claude Code を起動したディレクトリと、その上の階層にある CLAUDE.md は起動時に読み込まれます。一方、サブディレクトリにある CLAUDE.md は、Claude がそのディレクトリのファイルを読んだり編集したりしたときに初めて読み込まれます。
たとえば sample-project のルートで起動した場合、themes/sample-theme/CLAUDE.md は、Claude がテーマ内のファイルを開くまで読み込まれないため、テーマ固有の決まりを置く場所に向いています。
/compact で会話を圧縮したあとも、ルートの CLAUDE.md は読み直されます。
/init で雛形を作り、/memory で開いて育てる
CLAUDE.md を一から書くのが大変なら、/init から始めるのが近道です。コードベースを解析して CLAUDE.md を生成し、すでにある場合は上書きせずに改善案を出してくれます。
環境変数 CLAUDE_CODE_NEW_INIT=1 を設定してから実行すると、CLAUDE.md・スキル・hooks のどれを用意するかを選べる対話式のフローになります。
作ったファイルは /memory で開いて編集でき、読み込まれているかどうかは /context all の「Memory files」で確認できます。
なお、人が書く CLAUDE.md とは別に、Claude が訂正や好みをもとに自分で書く「自動メモリ」もあり、オン・オフは /memory から切り替えられます。
AGENTS.md がある場合
ほかの AI ツールと共有する AGENTS.md を使っている場合、最新版の Claude Code は、作業ディレクトリとその上の階層に CLAUDE.md(.claude/CLAUDE.md や CLAUDE.local.md を含む)が無ければ、AGENTS.md を読み込みます。
これらがある場合は、既定では CLAUDE.md 側だけが読み込まれます。両方を使いたいときは、CLAUDE.md に @AGENTS.md と書いて取り込むのが手軽です。
Web 制作チーム向け CLAUDE.md の書き方と記述例

ユーザー用(全プロジェクト共通)とプロジェクト用の 2 つの例で、何をどう書くかを見ていきます。
書くこと・書かないこと
公式ドキュメントが示している CLAUDE.md の書き方の指針は、次の 4 点にまとめられます。
- 短く保つ: 1 ファイル 200 行以下が目安。長いほど守られにくくなる
- 具体的に書く: 「コードを適切に整形する」ではなく「インデントは 2 スペース」のように確認できる書き方にする
- 構造化する: 見出しと箇条書きでまとめる
- 矛盾させない: 2 つの指示が食い違うと、Claude はどちらかを任意に選ぶことがある。ユーザー用とプロジェクト用、CLAUDE.md と rules など、ファイルをまたいだ食い違いにも注意する
書き足すタイミングについても、公式は「同じ間違いが 2 回起きたとき」「コードレビューで、Claude が知っておくべきだったことを指摘されたとき」「前回のセッションと同じ訂正をチャットで打ったとき」などを挙げています。
逆に、書かないほうがよいものもあります。コードを読めばわかるディレクトリの一覧や依存パッケージの羅列は、コンテキストを消費するだけです。何段階もある長い手順は、後で紹介するスキルに回しましょう。
グローバル ~/.claude/CLAUDE.md の例(全プロジェクト共通の禁止事項)
まずは、自分のすべてのプロジェクトに効かせたい共通ルールです。~/.claude/CLAUDE.md に置きます。
# 個人の共通ルール(すべての案件に適用)
## 返答の言語
- 返答・作業計画・説明はすべて日本語にする。コマンドの出力が英語のときも、要点は日本語でまとめる
## どの案件でも禁止
- データベースに対して SQL を直接流さない(mysql、wp db query など)
- 理由: 検証や本番のデータを壊しかねないため
- 代わりに: 変更したい内容と手順を文章にまとめ、担当者に依頼する
- 外部のサーバーには入らない。ssh・rsync・scp のコマンドも実行しない
- 理由: サーバーへの反映は担当者が決まった手順で行うため
- 代わりに: 動作の確認は手元の開発環境で行う
## 補足
- テーマごとの細かい決まりは ~/.claude/rules/ にファイルを分けて置いている
全案件で共通の禁止事項はユーザー用に集約しておくと、プロジェクトごとに書き忘れる心配がありません。ただし、ここに書いただけでは「お願い」のままなので、後の章で permissions と hooks でも止めます。
WordPress テーマ案件のプロジェクト CLAUDE.md の例(命名規則・Sass 構成)
次に、sample-project のルートに置くプロジェクト用の CLAUDE.md です。
# sample-project(WordPress テーマ制作)
<!-- メンテナー向けメモ: 命名規則はチームのコーディングガイドと同じ内容にそろえる。この行は Claude のコンテキストには入らない -->
## コマンド
- 開発サーバー(Vite + BrowserSync): `npm run dev`
- 本番ビルド: `npm run build`(出力先は `themes/sample-theme/assets/`)
- Lint: `npm run lint`(stylelint と prettier --check)
## 編集してよい範囲
- 編集してよいのは `src/` と `themes/sample-theme/` だけ
- `wp/` は WordPress 本体。編集しない(理由: コアの更新で上書きされるため)
- `themes/sample-theme/assets/` はビルドの出力先。直接編集せず、`src/` を直して `npm run build` する
## クラスの命名規則
- FLOCSS + BEM で書く。接頭辞は `l-`(レイアウト)、`c-`(コンポーネント)、`p-`(プロジェクト)、`u-`(ユーティリティ)
- Element は `__`、Modifier は `--` でつなぐ(例: `p-news__item--new`)
- 状態クラスは `is-` で始める(例: `is-open`)
- JavaScript から参照するクラスは `js-` で始め、スタイルを当てない
## Sass の構成
- 読み込みは `@use` と `@forward` を使う。`@import` は使わない
- 変数・mixin・関数は `src/scss/global/` に置き、`global/_index.scss` から `@forward` する
- 各パーシャルでは相対パスで global を読み込む(例: `@use "../../global" as *;`)
- 色・余白・フォントサイズは変数を使い、値を直接書かない
- インデントは 2 スペース
## 禁止事項(理由と代わりにやること)
- 本番サーバーへは接続しない(ssh / scp / rsync を使わない)
- 理由: 反映は担当者がデプロイ手順で行うため
- 代わりに: 表示の確認はローカルの `npm run dev`(BrowserSync)で行う
- SQL を直接実行しない
- 理由: データを元に戻せなくなるため
- 代わりに: 必要な変更は手順を書き出して担当者に渡す
- WordPress の記事やページは公開しない
- 理由: 公開の判断は担当者が行うため
- 代わりに: 保存するときは「下書き保存」だけにする
- ブラウザ操作はメインセッションだけが行う。サブエージェントには操作させない
- 理由: 操作の衝突を防ぎ、人が画面を見ていられるようにするため
## 作業の終わりに
- `npm run lint` と `npm run build` が通ることを確認してから、完了と報告する
ブロックエディタ対応まで扱う案件なら、ブロックのマークアップ規約も足しておくと安心です。詳しくは当ブログの「Gutenbergブロックエディタ用のコーディング」で詳しく紹介しています。
禁止事項は「理由」と「代わりにやること」をセットで書く
禁止事項は、ただ「するな」と書くだけでは不十分です。理由がわからないと、Claude は似たような別の方法で同じことをしようとする場合があります。
| 書き方 | 例 |
|---|---|
| NG | 本番に触るな |
| OK | 本番サーバーへは接続しない(理由: 反映は担当者がデプロイ手順で行うため)。表示の確認はローカルの BrowserSync で行う |
「理由」と「代わりにやること」をセットにすると、Claude は最初から許された方法を選びやすくなります。
人間向けのメモは HTML コメントで残す
上の例の 3 行目にある <!-- --> は HTML コメントです。CLAUDE.md の中のブロックレベルの HTML コメントはコンテキストに入る前に取り除かれるため、メンテナー向けのメモをコンテキストを消費せずに残せます(コードブロック内のコメントは残ります)。
@インポートと .claude/rules で CLAUDE.md を分割する
CLAUDE.md が 200 行を超えてきたら、@ によるインポートと .claude/rules/ で分割しましょう。
@path インポートの書き方と注意点
CLAUDE.md の中に @パス と書くと、そのファイルの内容が一緒に読み込まれます。たとえば、プロジェクトの CLAUDE.md の冒頭に次のように追記します。
# sample-project
プロジェクトの概要は @README.md 、npm スクリプトは @package.json を参照する。
## コーディングガイド
- 詳しいガイドは @docs/coding-guide.md にある
## 個人の追加メモ(各自のホームディレクトリから読み込む)
- @~/.claude/sample-project-notes.md
インポートには、次のような決まりがあります。
- 相対パスは、作業ディレクトリではなくインポートを書いたファイルの場所が基準になる
- 取り込んだファイルからさらに取り込むこともでき、深さは最大 4 ホップまで
- 作業ディレクトリの外を指すインポート(上の例の最後の行)は、初回に承認ダイアログが表示される
- コードスパンやコードブロックの中の
@は取り込まれない。前の章の CLAUDE.md で Sass の@useや@forwardをバッククォートで囲んでいるのは、意図しないインポートを避けるためでもある
注意したいのは、インポートは整理には役立つものの、コンテキストの消費は減らないという点です。量を減らしたいなら、次の paths つきの rules を使いましょう。
.claude/rules/ にトピック別のルールを置く
.claude/rules/ に Markdown ファイルを置くと、ルールを分野ごとに管理できます。sample-project では naming.md(命名規則)、sass.md、php.md、security.md の 4 つに分けました。
.md ファイルはサブディレクトリも含めて再帰的に読み込まれます。paths の指定が無いルールは、起動時に .claude/CLAUDE.md と同じ優先度で読み込まれます。
paths で「Sass を触るときだけ」読み込ませる
ルールファイルの先頭に YAML の frontmatter で paths を書くと、該当するファイルを扱うときだけ読み込まれるようになります。Sass のルールと PHP のルールを、それぞれ必要なときだけ効かせる例です。
---
paths:
- "src/scss/**/*.scss"
---
# Sass のルール
- パーシャルのファイル名は先頭に `_` を付け、`style.scss` から `@use` する
- `@import` は使わない。`@use` と `@forward` で読み込む
- ネストは 3 階層まで。BEM は `&__element` と `&--modifier` で書く
- メディアクエリは `global/_mixins.scss` の `mq()` mixin を使う
- `!important` は `u-` で始まるユーティリティ以外では使わない
---
paths:
- "themes/**/*.php"
---
# PHP(WordPress テーマ)のルール
- 出力は必ずエスケープする(`esc_html()`、`esc_attr()`、`esc_url()`、`wp_kses_post()`)
- 関数名とフック名には接頭辞 `sample_theme_` を付ける
- 共通部品は `template-parts/` に置き、`get_template_part()` で読み込む
- 編集したら `php -l` で構文を確認する
上が .claude/rules/sass.md、下が .claude/rules/php.md です。Claude が Sass や PHP のファイルを読んだり編集したりしたときに、それぞれのルールが読み込まれます。
補足として、rules の frontmatter で読み取られるのは paths だけです。ほかのフィールドを書いてもエラーにはならず、無視されます。
~/.claude/rules/ で個人ルールを全プロジェクトに効かせる
~/.claude/rules/ に置いたルールは、自分のすべてのプロジェクトに効きます。ユーザー用 CLAUDE.md には要点だけを書き、詳しい運用ルールはここに分けて置けます。
ユーザーのルールはプロジェクトのルールより先に読み込まれますが、どちらも相手を上書きしません。個人ルールとチームのルールは、内容をそろえておきましょう。
Claude Code スキルの作り方:.claude/skills で定型作業をコマンド化する

「毎回同じ指示を打つのが面倒」という悩みには、スキルが向いています。よく使う手順を 1 つのファイルにまとめておけば、/スキル名 だけで呼び出せます。
スキルとは何か・置き場所
スキルは SKILL.md というファイルを中心にしたフォルダで、置き場所は主に 2 つです。
- 個人用:
~/.claude/skills/<スキル名>/SKILL.md(自分のすべてのプロジェクトで使える) - プロジェクト用:
.claude/skills/<スキル名>/SKILL.md(コミットすればチームで共有できる)
スキルは /スキル名 で呼び出せるほか、description の内容が作業に合っていれば Claude が自動で読み込むこともあります。従来の .claude/commands/ はスキルに統合され、既存のファイルもそのまま動きます。
SKILL.md を編集すると、再起動しなくても現在のセッションに反映されます。
SKILL.md の frontmatter で設定できる主な項目
frontmatter で設定できる主な項目を、公式ドキュメント「Claude をスキルで拡張する」から抜き出しました。
| 項目 | 内容 |
|---|---|
name | / メニューに表示されるコマンド名。省略するとフォルダ名になる |
description | 何をするスキルか、いつ使うか。Claude が自動で使うかどうかの判断材料になる |
argument-hint | 入力補完のときに表示する引数のヒント(例: [theme-slug]) |
disable-model-invocation | true にすると Claude が自動で読み込まなくなり、/名前 で呼んだときだけ動く |
user-invocable | false にすると / メニューに出なくなり、Claude だけが使う |
allowed-tools | スキルを呼び出したターンの間、確認なしで使えるツール。次のメッセージを送ると解除される |
context と agent | context: fork にすると、agent で指定したサブエージェントの独立したコンテキストで動く |
paths | 指定したパターンのファイルを扱うときだけ自動で読み込む |
hooks | スキルを呼び出したときに登録する hooks |
description は、when_to_use と合わせて 1,536 文字を超えると一覧で切り詰められます。用途は description の先頭に書くのがコツです。また、SKILL.md 本体は 500 行以下が目安で、詳しい資料は別ファイルに分けて、必要なときに読ませるようにします。
例: Vite + Sass + BrowserSync + PHP の雛形を作る /scaffold スキル
Web 制作で定番の作業といえば、新しい案件のテーマ雛形づくりです。/scaffold sample-theme のようにテーマのスラッグを渡すと、雛形を配置してビルドまで確認するスキルを作ってみます。
---
name: scaffold
description: Vite + Sass + BrowserSync + PHP の WordPress テーマ雛形を作る。新しい案件でテーマを用意するときに使う
argument-hint: "[theme-slug]"
disable-model-invocation: true
allowed-tools: Read Write Edit Glob Bash(mkdir *) Bash(cp *) Bash(npm install *) Bash(npm run build)
---
# WordPress テーマの雛形を作る
作成するテーマのスラッグ: $ARGUMENTS
## 手順
1. スラッグが空、または英小文字・数字・ハイフン以外を含む場合は、作業せずにスラッグを質問する
2. `themes/$ARGUMENTS/`、`vite.config.js`、`src/scss/` のどれかがすでにある場合は、上書きせずに作業を止めて報告する
3. `${CLAUDE_SKILL_DIR}/templates/` から、次のとおりファイルを配置する
- `${CLAUDE_SKILL_DIR}/templates/vite.config.js` を `vite.config.js` に置き、`THEME_SLUG` を `$ARGUMENTS` に置き換える
- `${CLAUDE_SKILL_DIR}/templates/stylelint.config.js` を `stylelint.config.js` に置く
- `${CLAUDE_SKILL_DIR}/templates/scss/` を `src/scss/` に置く
- `${CLAUDE_SKILL_DIR}/templates/theme/` を `themes/$ARGUMENTS/` に置き、`style.css` の Theme Name と Text Domain を置き換える
4. `npm install -D vite sass vite-plugin-browser-sync stylelint stylelint-config-standard-scss prettier` を実行する
5. `npm run build` を実行し、`themes/$ARGUMENTS/assets/` に CSS と JS が出力されたことを確認する
6. 作成したファイルの一覧と、人が確認すべき点を報告する
設定値の意味や変更してよい箇所は [reference.md](reference.md) を参照する。
## 完了条件
- `npm run build` がエラーなく終わっている
- `src/scss/` で `@import` を使っていない
- `wp/` 配下のファイルを変更していない
$ARGUMENTS は呼び出し時に渡した文字列(例: sample-theme)に置き換わります。${CLAUDE_SKILL_DIR} は SKILL.md があるフォルダのパスになるので、作業ディレクトリに関係なくテンプレートを指せます。
allowed-tools で許可しても、settings.json の deny ルールのほうが先に評価されるため、deny で止めている操作は実行されません。
スキルのフォルダには、SKILL.md のほかに補助ファイルを置けます。今回の構成は次のとおりです。
.claude/skills/scaffold/
├── SKILL.md # 概要と手順(必須)
├── reference.md # 設定値の説明(必要なときだけ読む)
└── templates/
├── vite.config.js
├── stylelint.config.js
├── scss/ # style.scss、global/、foundation/ など
└── theme/ # style.css、functions.php、template-parts/ など
テンプレートの中身はチームの標準構成に合わせて用意してください。Vite の基本構成は、当ブログの「WebコーダーがViteを初めて使ってベースコーディングしてみた【導入から実践まで】」も参考になります。
副作用のあるスキルは「人が呼んだときだけ」動かす
/scaffold はファイルを作り、パッケージをインストールします。こうした副作用のあるスキルは disable-model-invocation: true にして、Claude が勝手に実行しないようにしましょう。
公式ドキュメントによると、この設定にしたスキルは description もコンテキストに読み込まれません。人が呼ぶまでコンテキストを消費しないので、スキルが増えてきたときの節約にもなります。
逆に、「Sass 規約の参照資料」のような知識系のスキルは user-invocable: false にして、Claude だけが必要に応じて読み込む使い方もできます。
Claude Code のサブエージェントで「書く人」と「見る人」を分ける
書いた本人にレビューさせると、思い込みがレビューにも残りがちです。サブエージェントなら、役割ごとに独立した担当者を用意できます。仕様は公式ドキュメント「カスタムサブエージェントの作成」にまとまっています。
サブエージェントの仕組み
サブエージェントは、メインの会話とは別の独立したコンテキストで動き、作業の要約だけをメインに返します。メインの会話履歴は引き継ぎません。
CLAUDE.md は、組み込みの Explore と Plan を除き、サブエージェントでも読み込まれます。命名規則や禁止事項はレビュー担当にも伝わります。
置き場所は、プロジェクト用が .claude/agents/、個人用が ~/.claude/agents/ です。同名の場合はプロジェクト用が優先されます。
レビュー担当サブエージェントの例
まずは、ファイルを読むだけで書き換えはしないレビュー担当です。.claude/agents/code-reviewer.md に置きます。
---
name: code-reviewer
description: Sass・JavaScript・PHP の変更をレビューする。コードを書き終えたあと、完了と報告する前に使う
tools: Read, Grep, Glob
model: sonnet
---
あなたは Web 制作チームのコードレビュー担当です。ファイルは読むだけで、書き換えはしません。
レビューの対象ファイルは、呼び出し元から受け取ります。
## チェックする観点
1. 命名規則: FLOCSS + BEM の接頭辞(l- / c- / p- / u-)と `__` / `--` の使い方
2. Sass: `@import` を使っていないか、`global/` を `@use` しているか、色や余白の値を直接書いていないか
3. アクセシビリティ: 画像の alt、見出しの階層、フォーム要素のラベル、フォーカスの見え方
4. PHP: 出力のエスケープ漏れ(esc_html / esc_attr / esc_url)、接頭辞 `sample_theme_` の付け忘れ
## 報告の形式
- 「必ず直す」「直したほうがよい」「確認だけ」の 3 段階に分け、ファイル名と行番号を付けて箇条書きにする
- 問題が無ければ「指摘なし」と書く
tools に Read, Grep, Glob だけを指定しているのがポイントです。編集のツールを持たないため、コードを書き換えることはありません。
ツールの制限は「お願い」ではなく、仕組みとして効きます。
model には sonnet・opus・haiku・inherit(メインと同じ)などを指定できます。
執筆・コーディング担当との分担と、ブラウザ操作をメインに限定する考え方
次は、ページの原稿を書く担当の例です。ブラウザを操作する MCP サーバー(ここでは架空の browser という名前)のツールを使わせないようにしています。
---
name: writer
description: ページの原稿やブログ記事の下書きを Markdown で書く。原稿づくりを頼まれたときに使う
disallowedTools: mcp__browser__*, Bash
model: inherit
---
あなたは Web 制作チームの原稿担当です。
- 原稿は `docs/drafts/` に Markdown で保存する
- ブラウザ操作はしない。画面の確認や WordPress への保存が必要なときは、必要な手順をまとめて呼び出し元に返す
- 医療機関のページでは、効果や効能を断定する表現を使わない
disallowedTools に mcp__browser__* を書くと、その MCP サーバーのツールがすべて外れます。シェルコマンドも不要なので、Bash も外しました。
ブラウザ操作をメインセッションだけに任せておけば、操作が衝突せず、WordPress の管理画面のような誤操作の影響が大きい画面も人が見ながら確認できます。
なお、項目名の表記には注意が必要です。スキルの frontmatter では disallowed-tools(ハイフン区切り)、サブエージェントでは disallowedTools(キャメルケース)と、書き方が異なります。
項目名が一致しないと、エラーも出ずに無視されます。
呼び出し方
サブエージェントの呼び出し方は、主に 3 つです。
- 自動委任: description の内容に合う作業になると、Claude が自動で任せる
- 自然言語で指名: 「code-reviewer サブエージェントで、さっきの変更を見て」のように頼む
- @ メンション:
@を入力して候補から選ぶ。@"code-reviewer (agent)"のような形で入力される
/agents コマンドの画面はバージョンで変わることがあるため、この記事のように Markdown ファイルを直接作る方法がいちばん確実です。
settings.json の permissions(allow / deny)で禁止事項を仕組みで止める
ここからが「強制」の仕組みです。permissions は Claude Code 本体がツールの実行前に判定するルールで、拒否したものは実行されません。書き方の詳細は公式ドキュメント「権限を設定する」で確認できます。
設定ファイルの種類と優先順位
公式ドキュメント「設定ファイルと優先順位」によると、設定ファイルは主に次の 4 種類です。
| スコープ | ファイル | 効く範囲 | 用途 |
|---|---|---|---|
| ユーザー | ~/.claude/settings.json | 自分のすべてのプロジェクト | 個人の好みや権限 |
| 共有プロジェクト | .claude/settings.json | git で共有したチーム全員 | チームの権限、hooks |
| ローカル | .claude/settings.local.json | 自分だけ(そのプロジェクト) | 個人の上書き、共有前の試験 |
| 管理設定 | managed-settings.json など | 組織が配布した端末すべて | セキュリティポリシー |
同じキーが複数のファイルにある場合の優先順位は、「管理設定 > コマンドライン(--settings)> ローカル > 共有プロジェクト > ユーザー」です。ただし permissions.allow のような配列は、すべてのファイルの内容がマージされます。
allow / ask / deny の評価順
permissions には、allow(確認なしで許可)、ask(毎回確認)、deny(拒否)の 3 種類のルールを書けます。評価は deny → ask → allow の順で、最初に一致したものが採用されます。
そのため、allow で deny に例外を作ることはできません。deny に Bash(ssh *) を書いたら、別のファイルの allow に Bash(ssh localhost) を書いても拒否されます。
Bash のルールでは * がワイルドカードで、その前のスペースにも意味があります。
Bash(ls *):lsやls -laに一致し、lsofには一致しないBash(ls*):lsofにも一致する
Web 制作チームの settings.json 例
sample-project の .claude/settings.json に、permissions を書いた例です。deny の対象は、次の章で作るフックが止めるコマンドとそろえています。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run dev)",
"Bash(npm run build)",
"Bash(npm run lint *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Bash(ssh *)",
"Bash(scp *)",
"Bash(sftp *)",
"Bash(rsync *)",
"Bash(mysql *)",
"Bash(mysqldump *)",
"Bash(mariadb *)",
"Bash(wp db query *)",
"Bash(wp db import *)",
"Bash(wp db cli *)",
"Bash(wp db reset *)",
"Bash(wp db drop *)",
"Read(./.env)",
"Read(./.env.*)",
"Edit(/wp/**)"
]
}
}
内容を整理すると、次のとおりです。
- allow: 開発サーバー、ビルド、Lint は確認なしで実行してよい
- ask:
git pushは、実行のたびに人が確認する - deny: 本番接続、SQL の実行、
.envの読み込み、WordPress 本体(wp/)の編集は拒否する
$schema を書くとエディタで入力補完と検証が効きます。settings.json は厳密な JSON なので、// のコメントや末尾のカンマはエラーになります。
もう 1 つの注意点が、書き込みの制限は Write(...) ではなく Edit(...) で書くことです。公式ドキュメントには、Write(パス) のルールはファイル操作に一致しないと明記されています。
Edit(/wp/**) の先頭の / は、ファイルシステムのルートではなく設定ファイルの基準となるディレクトリを指します。プロジェクトの設定ファイルなら、Claude Code を起動した作業ディレクトリ直下の wp/ という意味になります。
Bash ルールの限界を知っておく
公式ドキュメントによると、Bash(rm *) というルールは rm -rf build/ には一致しますが、/bin/rm -rf build/ や bash -c 'rm -rf build/' には一致しません。
公式はこれを、Bash の deny や ask のルールは「Claude が普段書く形」を止めるものであり、セキュリティ境界ではないと説明しています。上の例の Bash(ssh *) も、/usr/bin/ssh のように書かれると deny には一致しません。
その場合はほかのルールや権限モード次第になり、モードによっては確認なしで通る可能性もあります。確実に止めたいときは、次の章の hooks やサンドボックス機能と組み合わせてください。
一方、&& や ;、パイプでつないだ複合コマンドは分解して判定され、どれか 1 つが deny に一致すれば止まります。そのため、cd dist && rsync -av ./ user@example.com:/var/www/ のような書き方は、Bash(rsync *) で止まります。
チームで共有するときの注意
.claude/settings.json をチームで共有するときは、次の点を知っておきましょう。
.claude/settings.json(permissions と hooks)は、Claude Code を起動した作業ディレクトリの.claude/からだけ読み込まれ、親のディレクトリはさかのぼらない- allow のルールは、各自がそのフォルダを信頼する(ワークスペーストラストのダイアログで承認する)まで有効にならない。deny と ask はすぐに効く
- リポジトリにあるスキルの
allowed-toolsは、ワークスペーストラストに関係なく適用される。共有されたスキルは、allowed-toolsをレビューしてから使う /permissionsを実行すると、すべてのルールと、それぞれがどの設定ファイルから来ているかを確認できるdefaultModeのautoとbypassPermissionsは、プロジェクトやローカルの設定ファイルからは効かない
1 つ目は特に見落としがちです。themes/sample-theme/ のようなサブディレクトリで起動すると、ルートの .claude/settings.json に書いた deny も hooks も読み込まれません。Claude Code は必ずリポジトリのルートで起動することを、チームの決まりにしておきましょう。
さらに、ssh や SQL の禁止のように全案件で共通の決まりは、各自の ~/.claude/settings.json の permissions.deny にも同じルールを入れておくと安心です。ユーザー設定はどのディレクトリで起動しても読み込まれ、deny はどのスコープのものでも allow より優先されます。
なお bypassPermissions は権限の確認をほぼすべて飛ばすモードで、公式もコンテナなどの隔離環境でのみ使うよう警告しています。
Claude Code hooks で整形の自動化と危険操作のブロックを行う

hooks は、Claude Code の決まったタイミングで、指定したシェルコマンドを Claude の判断に関係なく必ず実行する仕組みです。
hooks の基本構造と主なイベント
hooks は settings.json の hooks キーに書きます。構造は「イベント名 → matcher(どのツールに反応するか)→ 実行するコマンドの一覧」の 3 段です。
この記事で使うイベントは、次の 3 つです。全イベントの一覧は、公式ドキュメント「hooks でアクションを自動化する」で確認できます。
| イベント | 発生するタイミング | 使い道の例 |
|---|---|---|
| PreToolUse | ツールの実行前(ブロックできる) | 危険なコマンドを止める |
| PostToolUse | ツールの実行が成功した後 | 編集後に整形・Lint を実行する |
| Notification | Claude Code が通知を出すとき | 入力待ちをデスクトップに通知する |
スクリプトには標準入力から JSON が渡されます。Bash なら tool_input.command にコマンドが、Edit や Write なら tool_input.file_path にファイルパスが入ります。
PreToolUse で本番接続・SQL 実行をブロックする
前の章の deny ルールでは一致しない /usr/bin/ssh や bash -c "ssh ..." も含めて止めるため、PreToolUse のフックを用意します。.claude/hooks/block-remote-and-sql.sh として保存してください。
#!/bin/bash
# .claude/hooks/block-remote-and-sql.sh
# PreToolUse(matcher: Bash)から呼ばれ、本番サーバーへの接続と SQL の直接実行を止める
# jq が無いと判定できないため、安全側に倒して止める
command -v jq >/dev/null 2>&1 || { echo "Blocked: jq が見つからないため判定できません" >&2; exit 2; }
INPUT=$(cat)
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty')
# コマンドが取り出せないときは何もせず、通常の権限判定に任せる
if [ -z "$COMMAND" ]; then
exit 0
fi
# 直前が英数字・_・.・- 以外(行頭、空白、; & | ( / 引用符など)で、
# 直後が空白か行末のときだけ「コマンド名」とみなす
BEFORE='(^|[^[:alnum:]_.-])'
AFTER='([[:space:]]|$)'
REMOTE="${BEFORE}(ssh|scp|sftp|rsync)${AFTER}"
SQL="${BEFORE}(mysql|mysqldump|mariadb)${AFTER}"
WPDB="${BEFORE}wp[[:space:]]+db[[:space:]]+(query|import|cli|reset|drop)${AFTER}"
if printf '%s\n' "$COMMAND" | grep -Eq "$REMOTE"; then
echo "Blocked: リモートサーバーへの接続(ssh / scp / sftp / rsync)は禁止です。本番への反映は担当者がデプロイ手順で行います。表示の確認はローカルの npm run dev で行ってください。" >&2
exit 2
fi
if printf '%s\n' "$COMMAND" | grep -Eq "${SQL}|${WPDB}"; then
echo "Blocked: SQL の直接実行(mysql / wp db query など)は禁止です。データの変更が必要なときは、手順を書き出して担当者に依頼してください。" >&2
exit 2
fi
exit 0
標準入力の JSON から jq で tool_input.command を取り出し、禁止コマンドが含まれていれば理由を標準エラー出力に書いて exit 2 で終わります。理由は Claude に伝わるので、Claude は別の方法に切り替えられます。
判定には jq が必要です(macOS なら brew install jq で入ります)。jq が見つからない環境では判定ができないため、冒頭のチェックで exit 2 を返し、安全側に倒して止めるようにしています。
保存したら、実行権限を付けてから、手元で動作を確かめておきましょう。
chmod +x .claude/hooks/block-remote-and-sql.sh
echo '{"tool_name":"Bash","tool_input":{"command":"ssh deploy@example.com"}}' | .claude/hooks/block-remote-and-sql.sh
echo $?
「Blocked:」のメッセージが出て 2 が返れば成功です。settings.json への登録は、次の PostToolUse とあわせて完成形で示します。
終了コードの意味は、次のように決まっています。
- exit 2: ツールの実行をブロックする。標準エラー出力の内容が Claude に伝わる
- exit 0: 「異議なし」。許可したことにはならず、通常の権限判定(permissions のルール)に進む
- それ以外(exit 1 など): 多くのイベントでは、エラーとして記録されるだけで実行は止まらない
ブロックしたいときは必ず exit 2 を使います。また、PreToolUse のフックは権限モードの判定より前に動くため、フックによるブロックは bypassPermissions モードでも有効とされています。
なお、変数やエイリアスを経由した実行までは見抜けず、逆に grep -r ssh src のようなコマンドも止めてしまいます。安全側に倒した判定として、チームの事情に合わせてパターンを調整してください。
PostToolUse で Sass / PHP の編集後にチェックを自動実行する
PostToolUse はツールの実行が成功した後に動きます。編集のたびに整形と構文チェックを走らせるスクリプトを、.claude/hooks/lint-after-edit.sh として保存します。
#!/bin/bash
# .claude/hooks/lint-after-edit.sh
# PostToolUse(matcher: Edit|Write)から呼ばれ、編集したファイルの種類に応じてチェックする
INPUT=$(cat)
FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty')
# 対象のファイルが無ければ何もしない
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
exit 0
fi
cd "$CLAUDE_PROJECT_DIR" || exit 0
case "$FILE_PATH" in
*.scss)
npx prettier --write "$FILE_PATH" > /dev/null 2>&1
if ! OUTPUT=$(npx stylelint --fix "$FILE_PATH" 2>&1); then
echo "stylelint のエラーがあります。内容を確認して修正してください。" >&2
echo "$OUTPUT" >&2
exit 2
fi
;;
*.js)
npx prettier --write "$FILE_PATH" > /dev/null 2>&1
;;
*.php)
if ! OUTPUT=$(php -l "$FILE_PATH" 2>&1); then
echo "PHP の構文エラーがあります。内容を確認して修正してください。" >&2
echo "$OUTPUT" >&2
exit 2
fi
;;
esac
exit 0
.scss は prettier と stylelint、.js は prettier、.php は php -l で確認します(stylelint と prettier は devDependencies に入っている前提です)。
PostToolUse で exit 2 を返すとエラー内容が Claude に伝わり、修正に取りかかれます。ただし実行後に動くため、編集そのものは取り消せません。止めたい操作は PreToolUse で扱います。
ここまでの permissions と 2 つのフックを 1 つにまとめた、.claude/settings.json の完成形は次のとおりです。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run dev)",
"Bash(npm run build)",
"Bash(npm run lint *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Bash(ssh *)",
"Bash(scp *)",
"Bash(sftp *)",
"Bash(rsync *)",
"Bash(mysql *)",
"Bash(mysqldump *)",
"Bash(mariadb *)",
"Bash(wp db query *)",
"Bash(wp db import *)",
"Bash(wp db cli *)",
"Bash(wp db reset *)",
"Bash(wp db drop *)",
"Read(./.env)",
"Read(./.env.*)",
"Edit(/wp/**)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-remote-and-sql.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint-after-edit.sh"
}
]
}
]
}
}
$CLAUDE_PROJECT_DIR は、セッションを開始したプロジェクトのルートを指す環境変数です。こう書いておけば、セッションの途中で Claude が cd してサブディレクトリに移ってもスクリプトが見つかります(起動そのものは前の章のとおりリポジトリのルートで行います)。
lint-after-edit.sh にも chmod +x で実行権限を付けておきましょう。
Notification で入力待ちをデスクトップ通知する
Notification のフックを使うと、入力待ちになったときにデスクトップへ通知できます。macOS の osascript を使う例が公式の「hooks でアクションを自動化する」にあるので、OS に依存する設定として各自の ~/.claude/settings.json に入れましょう。
hooks を使うときの注意
設定したフックは、/hooks で一覧を開くと、どのイベントに何が登録されているかを確認できます。複数の設定ファイルに書いたフックはマージされてすべて実行されますが、同じハンドラーを複数の設定ファイルに書いた場合は 1 回だけ実行されます。
フックは、自分のユーザー権限で任意のコマンドを実行できる強力な仕組みです。チームで共有するスクリプトも、ネットで見つけたスクリプトも、必ず中身をレビューしてから使ってください。
また、hooks はスキルやサブエージェントの frontmatter にも書けます。スキルに書いたフックは、スキルを呼び出した後、そのセッションの間ずっと有効です。サブエージェントに書いたフックは、そのサブエージェントが動いている間だけ有効になります。
運用のコツ:設定を育て、AI に任せきりにしない
ここまでの仕組みを、最初から全部そろえる必要はありません。
設定を足していく順番
公式ドキュメントでは、「きっかけ」ごとにどの仕組みを足すとよいかが整理されています。Web 制作の例を添えると、次のようになります。
| きっかけ | 足す仕組み | Web 制作での例 |
|---|---|---|
| 同じ間違いが 2 回起きた | CLAUDE.md | @import を使ってしまう → Sass の構成を書く |
| 同じプロンプトを繰り返し打っている | スキル | 雛形づくりの指示 → /scaffold にする |
| 調査やレビューの出力で会話が埋まる | サブエージェント | レビューを code-reviewer に任せる |
| 毎回、必ず実行してほしい | hooks | 編集後の stylelint、危険なコマンドのブロック |
守られないと困るものほど、hooks や permissions に移すべきサインです。
.claude/ も git で管理してレビュー対象にする
Claude Code の設定も、共有するものと個人用のものを分けてリポジトリで管理しましょう。
- チームで共有する(コミットする):
CLAUDE.md、.claude/settings.json、.claude/rules/、.claude/skills/、.claude/agents/、.claude/hooks/ - 個人用(コミットしない):
CLAUDE.local.md、.claude/settings.local.json
設定の変更もプルリクエストでレビューすれば、allow の広げすぎといった事故を防げます。矛盾や古い指示の点検には、最新版で使える /doctor prompt-audit も役立ちます。
生成されたコードは必ず人が確認する
納品物の最終責任は人にあります。生成されたコードや Claude に作らせた設定ファイルは、特に次の点を必ず人がレビューしてください。
- 表示崩れ: 実機やブラウザでの、レスポンシブを含めた表示
- アクセシビリティ: alt の内容、見出しの構造、キーボード操作
- セキュリティ: PHP のエスケープ漏れや、権限・hooks の設定の穴
- 表現: 医療機関のサイトなら、医療広告ガイドラインに沿っているか
そのうえで、「本番への反映と公開は人が行う」ことを、チームのルールとして明文化しておきましょう。AI と人の分担の事例として、当ブログの「画質を測りながらAVIFに変換するツールをAIに書いてもらった」もあわせてご覧ください。
まとめ
Claude Code にルールを守らせるには、「お願い」と「強制」を分けて設計することが大切です。
- CLAUDE.md は短く具体的に。禁止事項は理由と代わりにやることをセットで書く
- 分野別の規約は
.claude/rules/に分け、pathsで必要なときだけ読み込ませる - 繰り返す定型作業はスキルにして、副作用があれば
disable-model-invocation: trueにする - レビューや調査はサブエージェントに任せ、ツールを制限して役割を分ける
- 絶対に止めたいことは、同じ対象を permissions の deny と PreToolUse フックの二重で止める。全案件共通の禁止事項は
~/.claude/settings.jsonの deny にも入れる - Claude Code はリポジトリのルートで起動し、生成されたコードと設定は最後に必ず人がレビューする
設定はチームで使いながら育てるものです。まずは CLAUDE.md と settings.json の deny から始めてみてください。
Claude を使った制作の事例は、当ブログの「figma motionをClaudeで動かしてみる」や、セミナーの参加レポート「AI展示会にてClaude Codeのセミナーに参加してきました」でも紹介しています。
メディカルデザインは、病院・クリニックのホームページ制作・運用を手がけています。テーマ開発やブロックコーディングに AI を取り入れつつ、表示・アクセシビリティ・医療広告ガイドラインへの配慮は人の目で確かめています。詳しくは「病院ホームページ制作・運用」や「病院ホームページのCMS導入(WordPress)」のページをご覧ください。
サイトのリニューアルや、更新しやすい CMS の導入についてのご相談は、「サイト制作・運用のご相談フォーム」から承っております。
制作環境づくりに一緒に取り組むメンバーも募集しています。詳しくは「採用情報」をご覧ください。








