朝になっても終わっていない夜間ジョブを、何度か見たことがあります。ログを開くと、最後の行は決まって「確認待ち」でした。人が横にいれば Enter を押して済む場面で、誰も答えないまま何時間も待ち続けていたのです。
Claude Code 2.1.319 のチェンジログに、この待ちに対する新しい選択肢が一行だけ載っていました。permissions.denyInsteadOfPrompting という設定です。この記事は、その一行を読んで「自分ならどこに使うか」を整理した設計メモです。手元の夜間ジョブで実機検証を済ませた記録ではなく、チェンジログの記述を根拠にしている点を、先にお伝えしておきます。
チェンジログに書かれていること(2026年11月8日に確認)
一次情報は、2.1.319 の次の一行だけです。
| 項目 | 書かれていること |
|---|---|
| 設定名 | permissions.denyInsteadOfPrompting |
| 効果 | 権限の確認待ちになるはずのツール呼び出しを拒否し、そのターンを続ける |
| 対象 | ターミナルのセッション、サブエージェント、チームメイト |
| 書かれていないこと | 値の型、拒否時にモデルへ返るメッセージ、終了コードへの影響 |
私が設定リファレンスのページを取得した時点では、この項目の説明は見つかりませんでした。値は真偽値だろうと読んでいますが、断定はしません。使う前に、ご自身の環境の公式ドキュメントで型をご確認ください。
同じ版には、もう一つ近い話題があります。auto モードで安全確認を取れずに拒否された場合、claude -p がテキスト出力でも JSON 出力でも終了コード 1 で終わるようになりました。これは「確認が取れなかった」ことを終了コードで知らせる変更で、今回の設定とは別の仕組みです。混ぜないでおくと、あとで原因を切り分けやすくなります。
確認待ちへの答え方は、三つに分けて考えます
確認待ちを無人で扱う方法を、私は次の三つに整理しています。
| 方法 | 誰が答えるか | 止まったときの見え方 | 向く場面 |
|---|---|---|---|
| 許可ルールを先に足す | あらかじめ書いたルール | 確認自体が出ない | やることが固定で、範囲を言い切れる作業 |
| permission-prompt-tool で代行する | 自前の判定ツール | 判定ツールの台帳に残る | 毎回の判断を記録し、入力の書き換えもしたい作業 |
| denyInsteadOfPrompting で拒否する | 誰も答えず、拒否で進む | ツール呼び出しが失敗したまま、ターンは続く | 想定外の操作は断って構わず、止まることだけを避けたい作業 |
三つ目の特徴は、手間がほとんどないことです。判定ツールを作る必要がなく、ルールの網羅も要りません。設定を一つ足すだけで、「朝まで固まる」という最悪の形は避けられます。
その代わり、失敗の見え方が変わります。確認待ちは目立つ止まり方でした。拒否で先へ進むと、ジョブは最後まで走り、終了コードも 0 のまま、本来の成果物だけが欠けている——そんな形になりえます。固まらない代わりに、静かに欠けるのです。
私自身、固まらなければ安心だと考えていたのかもしれません。
許可ルールが効かない場面の切り分けは、allow を足したのに承認画面が消えないときに6段で読む記事で扱いました。複合コマンドの承認が毎回出る件は、cd と git の承認が繰り返し出る記事に書いてあります。まず確認を「出さない」側で手を尽くし、それでも残るものを拒否に回す、という順序が私は好きです。
拒否で続行するジョブは、成果物で成否を決めます
拒否は黙って起きるので、成否の判定を終了コードやログの文言に預けないことにしました。ジョブが生むはずのファイルが、中身を伴って存在するか。見るのはそこだけです。
設定は次のように書く想定です。
{
"permissions": {
"allow": ["Read", "Write(reports/**)"],
"denyInsteadOfPrompting": true
}
}allow に書いたものは通り、確認が必要になったものは待たずに断られます。そして、起動する側のスクリプトでは成果物を検査します。
#!/usr/bin/env bash
# nightly-check.sh — 拒否で続行しても、成果物の有無で成否を決める
set -u
OUT="reports/$(date +%F).md"
rm -f "$OUT"
claude -p "配信データの点検結果を ${OUT} に書き出してください" \
--allowedTools "Read" "Write(reports/**)" >/tmp/nightly.log 2>&1
CODE=$?
if [ ! -s "$OUT" ]; then
echo "成果物がありません: ${OUT}(claude の終了コード=${CODE})" >&2
exit 2
fi
exit 0前日のファイルを消してから走らせているのは、古い成果物を新しいものと見誤らないためです。-s で空ファイルも弾いています。拒否のメッセージ形式がチェンジログに書かれていない以上、その文言を grep する書き方は、版が上がるたびに壊れると考えました。
私の線引き
拒否に倒してよいのは、「断られても、翌朝の私が困らない作業」だけにしています。
たとえば壁紙アプリの配信データを点検して、結果をレポートに書く作業なら、想定外の書き込みが断られても実害はありません。レポートが欠ければ、上のスクリプトが朝に知らせてくれます。一方で、データを消す作業や外へ送る作業は、拒否で先へ進めると半端な状態で終わることがあります。そちらは許可ルールで範囲を言い切るか、判定ツールで一件ずつ記録する側に置いています。
固まらないことと、うまくいったことは別です。 拒否へ倒す設定を入れるなら、成功の判定は必ず成果物の側に持たせます。
次の一歩
まず、直近の夜間ジョブのログを開き、確認待ちで止まった箇所を一つだけ探してみてください。それが「許可ルールで言い切れる操作」なら allow に足し、「断られても構わない操作」なら拒否に回す候補です。設定を入れる前に、成果物を検査するスクリプトのほうを先に用意しておくことを、私はおすすめします。