Claude Codeには特定のコマンドを自動承認するパーミッション機能がある。
こいつを使えばいちいち確認ダイアログを挟まずに作業できる、のだけども思わぬバグに突き当たった。
きっかけ : Zedをスキルから起動したい
Claude Codeには「スキル」という仕組みがあり、「このファイルをZedで開いて」と言えばエディタを起動するような自動化ができる。今回定義したスキルはこんなシンプルな実装だった。
---
name: open-in-zed
description: 指定されたファイルまたはディレクトリをZedエディタで開く。ユーザーが「〇〇をZedで開いて」「Zedで開いてください」「zedで見たい」などと依頼したとき、またはファイル/ディレクトリとともにZedへの言及があるときに積極的に使用する。
---
# open-in-zed
指定されたパスをZedで開く。
## 手順
1. ユーザーのメッセージからパス(ファイルまたはディレクトリ)を抽出する
2. PowerShellで以下を実行する:
```powershell
Start-Process -FilePath "C:\Users\chacha\AppData\Local\Programs\Zed\Zed.exe" -ArgumentList "<path>"
```
問題はこのスキルが起動するたびに「許可しますか?」とダイアログが出ること。
毎回手動で承認するのは面倒なので、settings.json にパーミッションルールを追加して承認をスキップしたかった。
Claude Codeのパーミッション設定
{
"permissions": {
"allow": [
"PowerShell(Command *)"
]
}
}
パターン部分にはワイルドカード * が使える。
たとえば PowerShell(Get-Date *) なら Get-Date で始まるすべてのPowerShellコマンドを自動承認する、という意味になる。
まず素直に書いてみた → 自動承認されない
Zed.exeのパスをそのまま書いてみた:
"PowerShell(Start-Process -FilePath \"C:\\Users\\<USER>\\AppData\\Local\\Programs\\Zed\\Zed.exe\" *)"
承認されない。
引用符なしも試した:
"PowerShell(Start-Process -FilePath C:\\Users\\<USER>\\AppData\\Local\\Programs\\Zed\\Zed.exe *)"
これもダメ。
スラッシュに変えてみた:
"PowerShell(Start-Process -FilePath C:/Users/<USER>/AppData/Local/Programs/Zed/Zed.exe *)"
やっぱり承認されない。
ヤケクソでこれを書いてみた:
"PowerShell(Start-Process *)"
自動承認された。
つまり、パスを含まなければ動く、パスを含むと動かないという状況だった。
本当に再現するか確認する
「自動承認された」「されなかった」だけでは根拠が薄い。
そこで思いつく限りのパターンを検証するスクリプトを書いた。
# settings.jsonをコピーしてsettings.json.bkにバックアップ
# settings.jsonにパターンを設定し、 claude -p (非インタラクティブモード)でテスト
for pattern in "${patterns[@]}"; do
jq --arg p "$pattern" '.permissions.allow = [$p]' "$BACKUP" > "$SETTINGS"
rm -f "$SENTINEL"
claude -p "$PROMPT" > /dev/null 2>&1
if [[ -f "$SENTINEL" ]]; then
echo "✓ APPROVED: $pattern"
else
echo "✗ BLOCKED: $pattern"
fi
done
# 検証が終わったらバックアップからsettings.jsonを復元
検証結果
パスなし → 動く
| パターン | 結果 |
|---|---|
PowerShell |
✓ |
PowerShell(Get-Date *) |
✓ |
PowerShell(* -Format *) |
✓ |
PowerShell(Start-Process *) |
✓ |
PowerShell(Start-Process -FilePath * -ArgumentList *) |
✓ |
パスあり → 全滅
| パターン | 結果 |
|---|---|
PowerShell(& "C:\...\where.exe" *) |
✗ |
PowerShell(& C:\...\where.exe *) |
✗ |
PowerShell(Start-Process -FilePath C:\...\where.exe *) |
✗ |
PowerShell(Start-Process -FilePath C:/Windows/System32/where.exe *) |
✗ |
PowerShell(Start-Process -FilePath "C:\...\where.exe" *) |
✗ |
引用符あり・なし、バックスラッシュ・フォワードスラッシュ、& 演算子・Start-Process、どの組み合わせでもパスを含むパターンは一切機能しなかった。
現状、Windowsのファイルパスをパターンに含めることができる書き方は存在しない。
落とし穴:非インタラクティブモードのサンドボックス
検証中に気づいた罠。claude -p(非インタラクティブモード)では、Start-Process による子プロセス起動がサンドボックスによってブロックされる。
つまり Start-Process * がテストで ✗ になっていても、それはパーミッションが拒否したのではなくサンドボックスが邪魔しているだけ、という状況が起きていた。インタラクティブモードでは PowerShell(Start-Process *) は自動承認される。
非インタラクティブモードと通常TUIでは実行環境が異なるため、パーミッションの検証は最終的にはTUIで手動確認する必要がある。めんどくせぇ。。
GitHubのissueを調べたら同じ問題が山積みだった
調べてみると、Claude Codeのパーミッションシステムには多数の未解決バグがあり、#30519 というissueにまとめられていた。
"The permission matching system doesn't work. It's been broken since mid-2025"
現時点での結論
| 設定 | 問題点 |
|---|---|
| 特定のexeだけ自動承認 | パスを含むパターンが機能しない |
| Start-Process系を全部自動承認 | セキュリティリスクあり |
| 手動承認 | 毎回承認を求められる |
テキストエディタ起動のような「特定のコマンドだけ許可」という使い方はバグが修正されるまで実現できない。
Claudeへの愛
今回の一連の検証では、検証スクリプトの作成、結果の記録と要約、それらをソースにしてこの記事を書くに至るまで、あらゆる所でClaudeちゃんが活躍してくれました。ほんと優秀。だーいすき♡
だから、ね