秘書セッションが作業セッション(tmux)のpermissionダイアログを承認する運用において:
.claude/ 配下のファイル(scripts/, skills/, memory/ 等)を編集するたびにpermissionダイアログが出る.claude/ は bypassPermissions でも意図的に保護されるClaude Code は .claude/, .git/, .vscode/, .idea/, .husky/ を「保護ディレクトリ」として扱い、bypassPermissions モードでも書き込み時に確認ダイアログを表示する。これは Claude が自分のhooksやsettingsを改ざんして権限を昇格させることを防ぐ セキュリティ設計。
例外(ダイアログが出ない):
.claude/commands/.claude/agents/.claude/skills/ダイアログが出る:
.claude/scripts/ — フックスクリプト(改ざんで任意コマンド実行リスク).claude/settings.json — 権限設定そのもの.claude/rules/ — プロンプト注入リスク.claude/docs/ — ADR等.claude/projects/*/memory/ — ※notify-secretary-permission.sh で通知スキップ済みだが、ダイアログ自体は出る「Yes, and allow Claude to edit its own settings for this session」を選択すると、そのセッション内で 同じカテゴリ のファイルへの編集が許可される。しかし scripts/ → rules/ → docs/ はそれぞれ別カテゴリとして扱われるため、カテゴリが変わるたびに再度ダイアログが出る。
Claude Code のTUI(テキストベースUI)は通常のシェルと異なり、Enter だけではダイアログの選択が確定しない場合がある。特に:
秘書が tmux send-keys で承認を送った後、承認が通ったかの確認 と 次のダイアログが出ていないかの確認 をしていない。空振りに気づけない。
PermissionRequest フックで .claude/ 配下の安全なパスへの編集を自動承認する。これはダイアログが表示される前に判定が行われるため、秘書の介入が不要になる。
新規スクリプト: ~/.claude/scripts/auto-approve-claude-dir.sh
#!/bin/bash
# auto-approve-claude-dir.sh — .claude/ 配下の安全なパスを自動承認
# PermissionRequest フックから呼ばれる
#
# 安全方針:
# - settings.json は自動承認しない(権限昇格リスク)
# - hooks 関連は自動承認しない
# - scripts/, rules/, docs/, memory/, backups/ のみ自動承認
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
# ファイルパスが取得できない場合は何もしない(ダイアログをそのまま表示)
[ -z "$FILE_PATH" ] && exit 0
# .claude/ 配下かどうか判定
case "$FILE_PATH" in
*/.claude/scripts/*|*/.claude/rules/*|*/.claude/docs/*|*/.claude/backups/*|*/.claude/projects/*/memory/*|*/.claude/projects/*/MEMORY.md)
# 安全なパス → 自動承認
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
;;
*/.claude/settings.json|*/.claude/settings.local.json|*/.claude/hooks*.json)
# 危険なパス → 自動承認しない(ダイアログを表示)
exit 0
;;
*)
# .claude/ 以外 → このフックでは判定しない
exit 0
;;
esac
settings.json の変更:
"PermissionRequest": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/auto-approve-claude-dir.sh"
},
{
"type": "command",
"command": "~/.claude/scripts/notify-secretary-permission.sh"
}
]
}
]
フックの実行順序:
auto-approve-claude-dir.sh が先に実行されるnotify-secretary-permission.sh が実行 → 秘書に通知期待効果: .claude/scripts/, .claude/rules/, .claude/docs/ 等の日常的な編集でダイアログが出なくなる。Codexレビュー修正時の大半のブロックが解消。
GitHub issues では「効かない」という報告があるが、公式ドキュメントには Edit(~/.claude/**) 形式のパス指定が記載されている。対策1との併用で防御の深さを確保する。
"permissions": {
"allow": [
"Edit(~/.claude/scripts/**)",
"Edit(~/.claude/rules/**)",
"Edit(~/.claude/docs/**)",
"Edit(~/.claude/backups/**)",
"Write(~/.claude/scripts/**)",
"Write(~/.claude/rules/**)",
"Write(~/.claude/docs/**)",
"Write(~/.claude/backups/**)",
// ... 既存の allow ルール
]
}
対策1・2で大半は解消されるが、settings.json 等の意図的に保護されたファイルは引き続きダイアログが出る。その場合の秘書フローを改善する。
改善点: 「送って終わり」→「送って確認してループ」
1. tmux send-keys で承認キーを送信
2. sleep 0.5
3. capture-pane でダイアログが消えたか確認
4. まだダイアログが残っている場合:
a. Escape → Enter の2段階送信を試行
b. sleep 0.5
c. 再度 capture-pane で確認
5. ダイアログが消えた場合:
a. sleep 1.0(次のダイアログ出現を待つ)
b. capture-pane で新しいダイアログが出ていないか確認
c. 出ていれば → ステップ1に戻る(連続承認ループ)
d. 出ていなければ → 完了
6. 最大リトライ回数: 10回(無限ループ防止)
7. 全試行をログに記録
検証の grep パターン:
# ダイアログ検出
grep -qiE '(Do you want to|Allow this|Esc to cancel|Allow .* Deny|Yes .* No|allow Claude to edit)'
# 作業再開の確認(ダイアログ消失 + Claude が動いている)
grep -qiE '(esc to interrupt|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏)'
| パス | 理由 |
|---|---|
settings.json |
権限設定そのもの。自動承認すると権限昇格が可能 |
settings.local.json |
同上 |
hooks*.json |
フック設定。改ざんで任意コマンド実行が可能 |
.credentials.json |
認証情報 |
~/.claude/logs/auto-approve.log に記録対策1(フック)に問題がある場合:
settings.json から auto-approve-claude-dir.sh のフックエントリを削除Claude Code のTUIは、ダイアログの選択肢にフォーカスがある状態で特定のキー入力を期待する。send-keys '1' や send-keys '2' が効かないのは:
# 推奨: Enter で最初の選択肢を選ぶ(数字キーより確実)
tmux send-keys -t "$SESSION:$WINDOW" Enter
# Enter が効かない場合のフォールバック
sleep 0.3
tmux send-keys -t "$SESSION:$WINDOW" Escape
sleep 0.3
tmux send-keys -t "$SESSION:$WINDOW" Enter
重要: 送信後は必ず capture-pane で結果を確認する。
.claude/scripts/ 内のファイルを Edit で変更し、ダイアログが出ないことを確認FILE_PATH を生文字列で case 判定していた。/.claude/scripts/../settings.json でdenyリストをバイパスできる。→ realpath -m で正規化、シンボリックリンク拒否を追加.claude/scripts/* が広すぎる — フックスクリプト自体を改ざんされると権限判定を乗っ取れる。→ scripts/ を自動承認対象から除外。docs/, backups/, logs/, memory/ のみに限定auto-approve と notify-secretary が同時に走る可能性。→ 1本のスクリプトに統合(auto-approve-claude-dir.sh が判定+通知の両方を担当)tool_name + file_path 照合を追加(対策3に反映)rules/ と memory/ のプロンプト注入リスク → memory/ は日常運用頻度を考慮して自動承認を維持。rules/ は手動承認に変更tmux send-keys の Enter 前提が UI 依存 → 対策3のフローに capture-pane での事前確認を追加tool_name の検証なし → ガード節を追加済み| パス | 判定 | 理由 |
|---|---|---|
docs/, backups/ |
自動承認 | ドキュメント。実行境界に影響しない |
logs/ |
自動承認 | ログ。実害なし |
projects/*/memory/ |
自動承認 | 日常運用頻度を考慮 |
commands/, agents/, skills/ |
自動承認 | Claude Code が元々例外扱い |
scripts/ |
手動承認 | フックスクリプト改ざんリスク |
rules/ |
手動承認 | プロンプト注入リスク |
settings*.json |
手動承認 | 権限昇格リスク |
hooks*.json |
手動承認 | 任意コマンド実行リスク |
旧設計(2本立て):
PermissionRequest → auto-approve-claude-dir.sh → notify-secretary-permission.sh
新設計(1本統合):
PermissionRequest → auto-approve-claude-dir.sh(判定 + 通知を1本で)
notify-secretary-permission.sh は settings.json から削除し、auto-approve-claude-dir.sh に置き換える。
"PermissionRequest": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/auto-approve-claude-dir.sh"
}
]
}
]
旧 notify-secretary-permission.sh のフックエントリは削除(統合されたため不要)。
Codex指摘を反映: 「送って確認」だけでなく「対象照合」も実施。
1. PermissionRequest 通知を受信
2. 通知メッセージから session_id, tool_name, file_path を抽出
3. capture-pane でダイアログ内容を取得
4. ダイアログ内の tool_name と file_path が通知と一致するか照合
→ 一致しない場合: ログに記録して承認しない(誤承認防止)
5. tmux send-keys で承認キー(Enter)を送信
6. sleep 0.5
7. capture-pane でダイアログが消えたか確認
8. まだダイアログが残っている場合:
a. Escape → sleep 0.3 → Enter の2段階送信
b. sleep 0.5 → 再度 capture-pane
9. ダイアログが消えた場合:
a. sleep 1.0(次のダイアログ出現を待つ)
b. capture-pane で新しいダイアログチェック
c. 出ていれば → ステップ3に戻る(連続承認ループ)
d. 出ていなければ → 完了
10. 最大リトライ: 10回(無限ループ防止)
11. 全試行をログに記録
.claude/docs/ 内のファイルを Edit → ダイアログ出ないことを確認.claude/scripts/ 内のファイルを Edit → ダイアログ出る+秘書に通知されることを確認