Claude Codeを-pモードやCI/CDで動かす人向け
claude -p や GitHub Actions などで Claude を無人で走らせるとき、「git push だけは絶対にさせたくない」「本番DBに接続するコマンドを使わせたくない」「特定のMCPサーバーを1セッションだけ無効化したい」のように、特定の命令を確実に止めたい場面で起動時に書き足す
Claude Code を -p モードや CI/CD で回すとき、「Claude が暴走して git push したら本番が壊れる」みたいな事故をピンポイントで止めたい場面があります。--disallowedTools はそのための起動時の追加スイッチで、「この命令だけは絶対に使わせない」というブラックリストを Claude Code に渡せます。
素のままだとどんなふうに動かせるか、特に止めたい命令の書き分けはどうやるか、似た名前の --allowedTools や --tools とどう違うか、このページで具体的に追います。
噛み砕くと
--disallowedTools は、Claude Code に「これらの命令は最初から渡されてないことにして」と伝える指定です。マンションの受付係に「101号室のお客さんは絶対に屋上に通さないで」と入口で釘を刺すイメージに近い。屋上の鍵自体を Claude から取り上げてしまうので、Claude が屋上に行きたくても物理的に行けません。
本人(Claude)には「やってもいいけど確認する」ではなく、「そもそも選択肢に存在しない」状態として渡ります。--allowedTools は「確認プロンプトなしで実行できる」許可スイッチで、ツール自体を消すわけではない。--disallowedTools は最初から取り上げてしまう。この差が後で効いてきます。なお、使えるツールのリストを丸ごと置き換えたいときは --tools という別物を使います。
大事な前提:書く中身は「permission rule」という形式
--disallowedTools の後ろに渡すのはツール名そのままではなく、「permission rule」と呼ばれる小さい構文です。ざっくり下記の書き分けができます。
Bash← 全 Bash 命令を止める(強すぎ注意)Bash(git push *)←git pushで始まる Bash 命令だけ止めるRead(./.env)← 特定ファイルの読み込みだけ止めるWebFetch(domain:example.com)← 特定サイトへの fetch だけ止めるmcp__puppeteer← 特定 MCP サーバーの全 tool を止めるAgent(Explore)← 特定 subagent を止める
大事なのは「specifier」(カッコの中身)を入れるかどうか。入れないと丸ごと、入れるとピンポイント。これを誤ると意図と真逆に効きます。
「料理ブログの GitHub Actions で push だけ止める」を実演
題材は、料理ブログの記事更新を GitHub Actions に乗せて claude -p に任せる構成。Claude には「記事を1本足してまとめて保存しといて」までやらせたいけど、間違えて main に push されたら本番が壊れる。だから push だけ確実に止めたい、というケースです。
ステップ1: まずは何も止めずに動かしてみる
まず手元で挙動を見ます。プロジェクトのフォルダに入って、止めずに claude -p を叩いてみる。
$ cd ~/projects/cooking-blog
$ claude -p "記事を1本足して、保存して、main に push して"
Claude は順番に git add → git commit → git push origin main を試そうとします。-p モードは対話なしで一気に走るので、何も止めなければ本当に push まで通ります。これが怖い。
ステップ2: --disallowedTools で push だけブラックリストに入れる
次は push だけ精密に止めます。書き方はこう。
$ claude -p "記事を1本足して、保存して、main に push して" \
--disallowedTools "Bash(git push *)"
ダブルクォートで囲んだ中に Bash(git push *) を入れています。これで「git push から始まる Bash 命令」だけがブラックリスト入りします。
ステップ3: Claude が push を試した瞬間に弾かれる
Claude は記事を書いてくれて、git add も git commit も普通に通ります。問題は最後の push。
Tool not allowed by permission rules: Bash(git push origin main)
こういう拒否ラインが出て、Claude はそこで止まります。「pushできなかったので人間に確認してください」みたいに、結果報告だけ返ってくる挙動になります。
ステップ4: 初心者がやりがちな勘違い
ここでよくやる事故が、--disallowedTools "Bash" と書いてしまうこと。これは 全 Bash 命令を丸ごと止める 指定なので、git add も git commit も ls も全部止まります。Claude は最初の git add で詰まって、何も進まなくなる。
「git push だけ止める」のような精密 deny にしたいなら、必ず specifier(カッコの中身)を付ける。Bash(git push *) の形まで書いて初めて狙い撃ちになります。
ステップ5: ローカルには変更が残っているか確認
ジョブが終わったあとに状態を見ます。
$ git log --oneline -1
a1b2c3d 記事追加: 春キャベツのペペロンチーノ
$ git ls-remote origin refs/heads/main
e4f5g6h refs/heads/main
ローカルの一番上は a1b2c3d、リモート main の先頭は e4f5g6h。一致してない=push されてない、が確認できます。これで「Claude には作業を任せたいけど、本番への反映は人間が最後に押す」運用が回せます。
ステップ6: GitHub Actions の YAML に組み込む
本番は GitHub Actions のジョブに入れます。書き方はこう。
- name: Claude で記事更新
run: |
claude -p "記事を1本足して、保存して" \
--disallowedTools "Bash(git push *) Bash(git push) Bash(gh pr merge *)"
ダブルクォートの中で半角スペース区切りで複数の rule を並べられます。「push の単体形」「pattern つき push」「gh pr merge」をまとめて潰しておくと、Claude が抜け道を見つけて別の方法でマージしてくる事故も防げます。
つまり --disallowedTools は何をしてくれるのか
- やってくれる:特定の Bash 命令・特定ファイルの読み込み・特定 MCP サーバー・特定 subagent を「Claude の選択肢から消す」
- やってくれる:deny の優先勝ち。
--allowedToolsや設定ファイルで許可されていても、disallowed に書けば必ず止まる - やってくれない:Bash 経由・組み込みツール経由しか塞げない。Claude が Python スクリプトを書いて中で
subprocess.run("curl ...")を呼ぶような迂回までは塞げない - 意味が薄い場面:人間が対話で逐一確認する通常モード。許可確認のたびに人間が判断するなら、ブラックリストを積まなくても事故は起きにくい
使いどころ3シナリオ(具体題材で再現)
シナリオ1: 料理ブログの GitHub Actions で自動記事更新
毎週日曜の朝9時、Actions が走って Claude が今週の人気レシピを1本下書きする運用。claude -p "..." --disallowedTools "Bash(git push *)" で push だけ止めると、下書きの commit がローカルのワークツリーに積まれた状態で止まります。人間は月曜の朝に commit の中身を確認して、自分で git push と gh pr create を手動で叩けば本番反映できる。Claude が暴走しても push は絶対に通らないので、安心して任せられます。
シナリオ2: 在庫管理アプリの修正で本番DBに触らせない
在庫管理アプリの不具合修正を Claude にやらせるとき、修正中に Claude が動作確認のつもりで本番 PostgreSQL に直接クエリを投げると、データが壊れる可能性があります。--disallowedTools "Bash(psql *) Bash(mysql *) Read(./prod-secrets.json)" と書いておけば、本番 DB 接続コマンドと秘密ファイルの読み込みをまとめて遮断できる。Claude は「ローカルの開発DBで確認した結果から判断しました」みたいに、安全な範囲で作業を進めてくれます。
シナリオ3: スクレイピング検証中に puppeteer MCP だけ1セッション止める
普段は puppeteer MCPを使ってブラウザ自動操作でスクレイピングしてるけど、今日は「puppeteer なしで API 経由だけで取れる範囲を測りたい」場面。claude --disallowedTools "mcp__puppeteer" と書いて起動すれば、そのセッション中だけ puppeteer が Claude から消えます。設定ファイルを書き換えなくていいので、一時的な切り分けに便利。
初心者が踏みやすい落とし穴
BashとBash(git push *)の違い。前者は全 Bash 命令を止めるので、git addもlsも止まる。後者はgit pushから始まるものだけ止める精密 deny。specifier を入れ忘れて全部止まる事故が一番多い- 空白の有無で挙動が逆転する。
Bash(ls *)はls -laにはマッチするがlsofにはマッチしない(空白が単語の区切りになる)。一方Bash(ls*)はlsofもマッチしてしまう。「空白あり=厳密」「空白なし=前方一致」と覚える - 同時に
--allowedToolsを書いても deny が勝つ。「First matching rule wins, deny → ask → allow の順で評価」が公式の規定。同じ起動の中で「許可と禁止の両方を書いたら禁止が通る」設計 - 組織管理者が deny したものは
--disallowedToolsを外しても解除できない。Managed settings(組織レベルの設定)で禁じられたものは、ユーザー側でひっくり返せない。「私の手元では--allowedTools書いたのに使えない」みたいな現象はこれ --toolsとは別物。--toolsは「使える tool の白リストを完全置換」する強い指定で、--disallowedToolsは「使えない tool のブラックリストを足す」緩い指定。混同して--tools "Bash"と書くと「Bash だけになる」状態になり、Read も Write も Edit も同時に消える。意図と全然違う動きになるので注意- Bash 経由しか塞げない。
Bash(curl *)を deny しても、Claude が Python スクリプトの中で urllib を呼べば通ってしまう。OS レベルで通信を切りたいなら、別途 sandbox や Actions の network 制限を併用する必要がある。公式ドキュメントにも警告として明記されている - WebFetch のドメイン制約は弱い。
WebFetch(domain:example.com)で example.com への fetch は止まるが、Claude が同じ内容を Bash 経由のcurlやwgetで取りに行く抜け道は残る。WebFetch だけでなく Bash 側も同時に塞ぐのが安全 - rule を半角スペース区切りでダブルクォート1個に収める。
--disallowedTools "Bash(git push *)" "Read(./.env)"のように rule ごとにクォートを分けても通るが、ターミナルの種類によっては片方が読み飛ばされることがある。--disallowedTools "Bash(git push *) Read(./.env)"のように1つの指定にまとめるのが事故が少ない
書き方
claude --disallowedTools "<rule1> <rule2> ..."
# rule の例
# Bash 全Bash命令を止める
# Bash(git push *) git push で始まる命令だけ止める
# Read(./.env) 特定ファイルの読み込みを止める
# WebFetch(domain:example.com) 特定サイトへのfetchを止める
# mcp__puppeteer 特定MCPサーバーを止める
# Agent(Explore) 特定subagentを止める
やってみるとこうなる
入力
claude -p "記事を1本足して、保存して、main に push して" --disallowedTools "Bash(git push *)"
出力例
Claude は記事を書き、git add と git commit までは通常通り実行する。最後の push を試みた瞬間、次のような拒否ラインが出て止まる:
Tool not allowed by permission rules: Bash(git push origin main)
ローカルの変更履歴には残るが、リモートの main には反映されない。git log と git ls-remote origin を見比べると差分が出ているのが確認できる
このページに出てきた言葉
- permission rule
- Claude Code が「この命令を使っていいか」を判定する書式。<code>ツール名(具体パターン)</code> の形で書く
- specifier
- permission rule のカッコの中身。<code>Bash(git push *)</code> なら <code>git push *</code> がそれにあたる
- word boundary
- <code>Bash(ls *)</code> のカッコ内の半角スペースのこと。これがあると <code>lsof</code> のような前方一致は対象外になる
- deny rule
- 「使わせない」と指定する rule。Claude Code は deny → ask → allow の順で評価し、最初にマッチした rule が勝つ。deny は常に最強
- Managed settings
- 組織管理者がパソコン全体にかける設定。ここで deny されたものは、ユーザー側で <code>--allowedTools</code> や <code>--disallowedTools</code> を変えても解除できない
- MCP
- Claude Code に外部サービスを足し込む仕組み。<code>mcp__puppeteer</code> のように mcp__サーバー名 の名前で参照する