料理ブログ等のプロジェクトでClaude Codeを使い始めて、Bashコマンドの許可リストを整理したい人向け
料理ブログ等のプロジェクトを毎日 Claude Code で触っていて、`git status` や `hugo --quiet` のような無害な定型コマンドの確認画面が毎回割り込んできて作業が止まる時、または `git push` のような後戻りしづらい操作だけは Claude に勝手に叩かせたくない時に、`/permissions` を叩いてパネルを開き、安全な定型は allow に・破壊的なものは deny に振り分けて確認画面の数を「効くところだけ」に絞り込む。
そもそも何で確認画面が毎回出るのか
Claude Code は初期状態だと、ファイルを書き換える系のコマンドや Bash 経由の実行を1回ずつ確認してくる。git status のような無害な情報取得コマンドでも、初回は「Yes / Yes, don't ask again / No」のパネルが出る。
これは安全装置で、本来は良いこと。だけど料理ブログを毎日触っていると、「git status」「hugo --quiet」みたいな10回20回叩くコマンドの確認が積み重なってきて作業が止まる。
そこに /permissions が出てくる。確認画面の代わりに「このコマンドはもう聞かなくていい」を一覧で管理する画面。
噛み砕くと、家族で使うキッチンの「これは触っていい/これはダメ」リスト
例え話で書く。新しく入った家事代行に台所を任せると、最初は1つ1つ確認してくる。「包丁、出していいですか?」「炊飯器、開けていいですか?」「ガス、つけていいですか?」全部聞かれる。安全だけど作業が進まない。
そこで「包丁・まな板・炊飯器は毎回聞かなくていい」「ガスの元栓は触らない」「冷凍庫の奥は確認してから」と紙に書いて貼っておく。これが許可ルール。/permissions はその紙を画面で開いて編集する道具。
家事代行は「allow リスト=勝手にやっていい」「ask リスト=毎回確認してね」「deny リスト=絶対触らない」を見ながら動く。Claude Code もまったく同じ仕組み。
/permissions を叩くと画面に何が出るのか
Claude Code を起動した状態で、入力欄に /permissions と打って Enter。すると下のようなパネルが画面に出てくる。
┌─ Permissions ──────────────────────────────────────┐
│ Mode: default │
│ │
│ Allow: │
│ Bash(git status) (project) │
│ Bash(npm run *) (local) │
│ Read(./content/**) (project) │
│ │
│ Ask: │
│ Bash(git push *) (default) │
│ │
│ Deny: │
│ (none) │
│ │
│ [a] Add rule [e] Edit [d] Delete [q] Quit │
└────────────────────────────────────────────────────┘
ポイントは右側の「(project)」「(local)」表示。同じルールでも、保存されている場所が3種類ある。これが scope。プロジェクト全体で共有するか、私の手元だけに留めるか、私のパソコン全体で使い回すかをここで切り替える。
料理ブログで「git status / hugo --quiet を allow、git push を deny」を入れる4ステップ
具体題材で動かす。料理ブログ cooking-blog/ をHugoで書いていて、毎日 git status と hugo --quiet を10回ずつ叩く状態。git push は手動でやりたい(本番反映を機械任せにしたくない)。
ステップ1: /permissions パネルを開く
料理ブログのフォルダで Claude Code を起動。入力欄に /permissions と打つ。
$ cd ~/projects/cooking-blog
$ claude
> /permissions
パネルが開く。最初はほぼ空っぽ(インストール直後ならルール0件か数件)。
ステップ2: Bash(git status) Bash(git add *) Bash(git commit *) を allow に追加
パネルで a(Add rule)を押すと、ルールの追加画面に切り替わる。「どのモードに入れるか」と「ルール本体」を聞かれる。
Mode? [allow]
Rule: Bash(git status)
Scope? [local]
「local」を選ぶと cooking-blog/.claude/settings.local.json に保存される。手元だけの設定で、誰かと共有はしない。これを 3 回繰り返して、Bash(git status) Bash(git add *) Bash(git commit *) を入れる。
ルール本体の * はワイルドカード。Bash(git add *) と書くと git add . も git add content/recipes/curry.md も両方マッチする。
ステップ3: Bash(hugo --quiet) を allow に追加
同じ手順で Hugo のビルドコマンドも入れる。
Mode? [allow]
Rule: Bash(hugo --quiet)
Scope? [local]
これで Claude が裏で hugo --quiet を叩いてビルド確認する時、確認画面が割り込まなくなる。地味だけど効く。
ステップ4: Bash(git push *) を deny に追加
最後に本番反映系。git push は Claude に勝手に叩かせたくない。私の場合、push は GitHub Actions のビルドが走って本番サイトに反映されるので、私の目で確認してから手動で打ちたい。
Mode? [deny]
Rule: Bash(git push *)
Scope? [project]
scope は project にする。cooking-blog/.claude/settings.json に保存されて、Git でコミットできる。同じ料理ブログを別マシンで触ってもこのルールが効く。
これで4ステップ終了。次のセッションから「git status いい?」「hugo いい?」の確認は出なくなり、もし Claude が git push origin main を打とうとしたら deny で即ブロックされる。
allow / deny / ask の3モードの役割分担
パネルにあった3つの箱の使い分けを整理する。
- allow - 確認画面なしで通す。「これはもう毎回聞かないでいい」という安全な定型コマンド用。
Bash(git status)Bash(npm run test)など - ask - 毎回確認画面を出す。デフォルトの動作と同じだが、明示的に「これは確認したい」と固定したい時に使う。allow が広すぎる時のブレーキ
- deny - 問答無用でブロック。確認画面も出さずに弾く。
Bash(git push *)Bash(rm -rf *)Read(~/.ssh/**)みたいな破壊・情報漏洩系
ルールは deny → ask → allow の順番でチェックされる。同じコマンドが allow と deny の両方にマッチした場合は deny の勝ち。これ大事。
例: Bash(git *) を allow に入れて、Bash(git push *) を deny に入れる。git status は allow に当たって素通り、git push origin main は deny に当たってブロック。広く許可しつつ危険な部分だけ穴を塞ぐパターン。
scope 3種(user / project / local)の使い分け
同じルールでも、保存先が違うと「誰に効くか」が変わる。
| scope | 保存先 | 効く範囲 | 共有 |
|---|---|---|---|
| user | ~/.claude/settings.json |
個人マシンの全プロジェクト | 個人専用 |
| project | <プロジェクト>/.claude/settings.json |
このプロジェクトだけ・チーム全員 | Git で共有 |
| local | <プロジェクト>/.claude/settings.local.json |
このプロジェクトだけ・手元のみ | 非共有(gitignore対象) |
料理ブログ用の使い分け:
- user:
Bash(git status)Bash(ls *)など、料理ブログに限らず全プロジェクトで毎回叩く定番 - project:
Bash(hugo --quiet)Bash(git push *) denyなど、料理ブログ固有の方針。チームメイトにも配りたいやつ - local: 試行錯誤中の一時的な許可。
Bash(npm run experimental-build)みたいに、まだ Git に入れたくないやつ
判断は単純。「全プロジェクトで効かせたい?」→ user。「このプロジェクトでチーム全員に効かせたい?」→ project。「いまだけ手元で試したい?」→ local。
ルール書式の早見表(料理ブログ題材で具体例)
ルール本体は ツール名(対象パターン) の形。料理ブログでよく出てくる書き方をまとめる。
| 書式 | 意味 | 料理ブログでの用途 |
|---|---|---|
Bash(git status) |
完全一致。git status だけマッチ |
状態確認だけ素通しに |
Bash(git add *) |
git add + 何か。git add . も git add content/recipes/ もマッチ |
記事のステージング |
Bash(npm run *) |
npm run 系全部 |
npm run build npm run dev |
Bash(hugo --quiet) |
完全一致 | 静かにビルド |
Bash(git push *) |
git push 系全部 |
deny に入れて手動運用 |
Edit(content/**) |
content/ 配下の全ファイル編集 |
記事フォルダの編集を許可 |
Read(~/.ssh/**) |
ホーム下の .ssh/ の全ファイル |
deny に入れて秘密鍵を守る |
WebFetch(domain:github.com) |
github.com への取得だけ | 外部ドキュメント取得を限定 |
Read(カッコなし) |
Read ツール全部 | broad な許可(注意) |
ファイル系(Read Edit)のパターンは gitignore と同じ書式。* は1階層、** は再帰的に全部。content/** なら content/recipes/curry.md も content/recipes/japanese/sushi.md もマッチする。
料理ブログでの使いどころ3シナリオ
シナリオ1: 毎日30分の更新作業から確認画面を消す
料理ブログを毎朝30分触る生活を続けていると、git status git diff hugo --quiet git add git commit が日に20回ずつ走る。1回1秒の確認でも積み重なると地味に作業が止まる。
/permissions で Bash(git status) Bash(git diff *) Bash(hugo --quiet) Bash(git add *) Bash(git commit *) を user scope に入れる。これ全プロジェクトで効くから、ブログを増やしても再設定不要。
シナリオ2: 本番反映系を deny で止めて手動運用に残す
料理ブログの本番反映は git push origin main をトリガーにしている。私は push する前に必ずローカルでプレビュー確認したい派。
/permissions で Bash(git push *) を project scope の deny に入れる。これで Claude が「コミットして push しときますね」みたいな流れになっても、push の手前でブロックがかかる。コミットは進んで、push だけ私の手で打つ運用が固まる。
シナリオ3: 秘密フォルダを deny で読み取り禁止にする
料理ブログのフォルダの隣に ~/secrets/ を置いて、API キーや本番DB接続情報を入れている。Claude が間違って cat ~/secrets/api-key.txt しないように、読み取り自体を禁止したい。
/permissions で Read(~/secrets/**) を user scope の deny に入れる。Claude の Read ツールは止まる。ただし注意点が1つあって、Bash 経由の cat ~/secrets/api-key.txt は別ルートなので、合わせて Bash(cat ~/secrets/*) も deny にしておく。完全に止めたい場合は OS 側のサンドボックス機能と組み合わせる。
初心者が踏みやすい落とし穴
- local scope の
.claude/settings.local.jsonを Git にコミットしないこと。.gitignoreに入れ忘れると、手元だけのつもりだった許可ルールがチーム全員に配られる。意図しない allow が広がる事故になる - 複合コマンドは1個ずつ判定される。
git status && npm testを「Yes, don't ask again」で許可すると、保存されるのはBash(npm test)だけ。&&;|||はそれぞれの subコマンドが個別チェックされる Bash(devbox run *)系の許可は危険。devbox runnpxdocker execのような「中で別コマンドを叩くやつ」は、ワイルドカードで広く許可するとdevbox run rm -rf .も通ってしまう。中身まで含めてBash(devbox run npm test)のように具体に書くBash(watch *)Bash(find * -delete)は事前許可できない。これらは公式が「常にプロンプト出す」と決め打ちしているので、ルール書いても毎回確認画面が出る。仕様- deny → ask → allow の順を忘れる。
Bash(git *)を user の allow に入れた状態でBash(git push *)を project の deny に入れた場合、push は deny の勝ち。allow を広く取ったから「もう全部通る」と思い込むと事故る - Read deny は Bash 経由には効かない。
Read(~/.ssh/**)を deny にしても、cat ~/.ssh/id_rsaは Bash ルート。Bash 側にもBash(cat ~/.ssh/*)等を deny で入れるか、OS のサンドボックス機能を使う --dangerously-skip-permissionsで全素通しにしない。claude --dangerously-skip-permissionsという指定付きで起動すると確認画面が全部消える。コンテナや使い捨て VM なら使い道があるが、ホストPCで使うとrm -rf ~/もすり抜ける。「便利」と思って常用しない- パターンに頼って URL や指定の中身を絞ろうとしない。
Bash(curl http://github.com/ *)みたいな書き方はcurl -X GET http://github.com/...やcurl https://...でズレてマッチしない。URL を絞りたいなら、curl/wget 系を deny して、Claude 標準の WebFetch +WebFetch(domain:...)で許可する形にする - パネルでの追加と直接編集を混ぜると見失う。
.claude/settings.local.jsonをエディタで手書きしながら /permissions パネルでも追加していると、どこにどのルールが入ってるか分からなくなる。基本はパネル経由に統一する。手書きするなら scope を意識して保存先を1つに決める
関連するコマンド・ツールへの動線
- Bash(バッシュ) - 許可ルールの主役。
Bash(git status)Bash(npm run *)の対象になるツール - Edit(エディット) -
Edit(content/**)のようにフォルダ単位で許可可能なファイル編集ツール - Read(リード) -
Read(~/secrets/**)で読み取り禁止フォルダを設定する対象 - Write(ライト) - ファイル新規作成。Edit と同じくパス単位で許可制御
- Glob(グロブ) -
Read寄りの扱いでパターン検索する - Grep(グレップ) - 同じく
Read系として許可される - Hooks(フックス) - PreToolUse hook で許可判定をオーバーライドできる仕組み。/permissions だけで足りない時の追加ガード
- /init(イニット) - プロジェクトの初期化と CLAUDE.md 雛形生成
- /memory(メモリ) - CLAUDE.md の編集パネル
- CLAUDE.md - 許可ルールの方針をメモしておくとチーム運用が安定する
- /agents(エージェンツ) - エージェント別に許可ルールを変えられる仕組み
- /clear(クリア) - 会話のリセット
- /compact(コンパクト) - 会話の要約圧縮
- Skills(スキルズ) - スキル別動作の管理
- MCP(エムシーピー) -
mcp__server-name形式で許可ルールに書ける外部ツール接続
参考リンク
- Configure permissions(公式 docs)
- Permission modes(公式 docs)
- CLI reference(公式 docs)
- Settings(公式 docs)
- Sandboxing(公式 docs)
書き方
/permissions
やってみるとこうなる
入力
/permissions
出力例
Permissions パネルが画面に開く。Mode(default / plan / bypassPermissions など)と、Allow/Ask/Deny の3区分のルール一覧が表示される。各ルールの右側には保存先 scope(user / project / local)が表示される。`a`で追加、`e`で編集、`d`で削除、`q`で閉じる。追加したルールは scope に応じて `~/.claude/settings.json` か `<project>/.claude/settings.json` か `<project>/.claude/settings.local.json` に保存される。
このページに出てきた言葉
- allow
- 「確認画面なしで通す」許可ルールの箱。`Bash(git status)` のような無害な定型コマンドを入れる
- deny
- 「問答無用でブロック」する拒否ルールの箱。`Bash(git push *)` `Read(~/.ssh/**)` のような破壊・情報漏洩系を入れる。確認画面も出さずに止める
- ask
- 「毎回確認画面を出す」ルールの箱。allow が広すぎる時のブレーキとして使う
- scope(user / project / local)
- ルールの保存先と適用範囲。user は個人マシン全体(`~/.claude/settings.json`)、project はプロジェクト共有(`<project>/.claude/settings.json`、Git コミット可)、local は手元のみ(`<project>/.claude/settings.local.json`、gitignore で除外)
- ワイルドカード
- `*` 記号で「何文字でもマッチ」を表す書き方。`Bash(npm *)` で `npm install` も `npm run dev` も全部対象になる
- 複合コマンド
- `&&` `;` `|` `||` のような区切り記号で連結したコマンド。Claude Code は1個ずつ独立にルール判定する。`git status && npm test` の許可で保存されるのは `Bash(npm test)` 等の subコマンド単位
- additionalDirectories
- プロジェクトの外のフォルダにも作業範囲を広げる設定。`--add-dir` 起動指定や `/add-dir` コマンドでも追加できる
- --dangerously-skip-permissions
- Claude Code 起動時に付ける指定で、確認画面を全部素通しにする。コンテナや使い捨て VM 用。ホストPCでの常用は `rm -rf ~/` もすり抜けるので非推奨
- PreToolUse hook
- Claude がツールを叩く直前に走る、自前のシェルスクリプトの仕組み。許可判定を上書きできる。/permissions だけで足りない条件分岐の追加ガード用
- Hugo
- マークダウンで書いた記事をHTMLサイトに変換する静的サイトジェネレータ。料理ブログ・技術ブログで広く使われる