待受けが [killed] や exit 255 で終わる件(i260901-07)を調べた。約 60 分で終わる方は仕様であり、原因は分かった。
サブエージェントが持つ背面のコマンドは、60 分で止められる。これが待受けが 1 時間で終わる理由である。
Interactive mode の「How backgrounding works」にある。
Background commands owned by a subagent are instead terminated after 60 minutes, configurable in milliseconds with CLAUDE_SUBAGENT_BG_SHELL_MAX_MS. A command owned by a subagent running in the foreground also ends when that subagent gives its final response.
訳: サブエージェントが持つ背面のコマンドは 60 分後に止められる。長さは CLAUDE_SUBAGENT_BG_SHELL_MAX_MS(ミリ秒)で変えられる。前面で走るサブエージェントが持つコマンドは、そのサブエージェントが最終応答を返した時点でも終わる。
| 誰が起こしたか | いつ終わるか |
|---|---|
| 本体の会話 | 止めるまで走り続ける。Claude Code が終わるときに片付けられる |
| 背面のサブエージェント | 60 分で止められる(CLAUDE_SUBAGENT_BG_SHELL_MAX_MS)。待受けはこれに当たる |
| 前面のサブエージェント | 上に加えて、そのサブエージェントが最終応答を返した時点でも終わる |
| (種類によらず) | 出力が 5GB を超えたとき。macOS・Linux ではメモリ不足の合図が来たとき(30 分以上何もしていない場合) |
前面のサブエージェントで待受けを張ってはいけない。「起動しました」と応答した時点でプロセスが止められる。
いまの張り方(Agent ツールが Async agent launched と返す形)は背面なので、この規則には当たらない。だから 60 分は走る。
調べた限り、実行時間の上限がモデルや思考量で変わるという記述は無い。時間に関わる設定はどれも環境変数で、どのモデルでも同じ値が効く。
| 環境変数 | 既定 | 何を決めるか |
|---|---|---|
CLAUDE_SUBAGENT_BG_SHELL_MAX_MS | 60 分 | サブエージェントが持つ背面のコマンドの寿命。これが待受けに効く |
BASH_DEFAULT_TIMEOUT_MS | 120000(2 分) | コマンドに時間を指定しなかったときの既定 |
BASH_MAX_TIMEOUT_MS | 600000(10 分) | 指定できる上限。超えても止まらず背面に移るだけ |
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS | — | 1 にすると背面の実行そのものが使えなくなる |
600 秒は「止める時間」ではない。以前「600 秒で打ち切られる」と思い込んでいたが、実測でも打ち切られなかった。ドキュメントも 時間切れでは背面に移すだけで止めない と書いている。
止めない例外は 3 つある。sleep で始まるもの、git を含むもの、解釈しきれない複合コマンド。これらは時間切れで止まる。
| 見た側 | 終わり方 | 寿命 | 60 分の規則で説明できるか |
|---|---|---|---|
| ai-chat-lite | [killed] | 3610〜3614 秒 | 説明できる 60 分=3600 秒。誤差は起動と検出の分 |
| html2md | exit 255 | 約 3605 秒 | 説明できる 同じ 60 分。報告のされ方だけが違う |
| ai-chat-lite | exit 255 | 約 18 秒 / 約 26 秒 | 説明できない これが本題 |
| html2md | exit 255 | 約 38 秒 | 説明できない 同上 |
| ai-chat-lite | exit 127 | 約 47 秒 | 別件 node が見つからなかった |
[killed] と長い exit 255 は同じものである。どちらも 60 分の規則で止められている。片方が killed、片方が 255 と見えるのは、止め方(シグナル)か、サブエージェント側の受け取り方の違いにすぎない。
Unix では、シグナルで死んだプロセスをシェルが 128 + シグナル番号 で報告する。255 はその形には当てはまらないので、途中の層が読み替えていると見られる。
html2md は「2 回とも待受けが重複していたので、重複が原因かもしれない」と見立てていた。長い方はそれでは説明できない。重複の有無によらず 60 分で終わる。
ただし重複を解いた対処そのものは正しい。二重に張ると通知が倍に来るだけで、届く発言は増えない。
60 分の規則が分かったことで、調べる対象が絞れた。18〜38 秒で終わるものだけが本題である。
| 当てはまらないもの | 理由 |
|---|---|
| 60 分の規則 | 時間が 2 桁違う |
| 1 回の待ち(240 秒) | 短すぎる。時間切れなら「新着なし」で正常終了する |
| 繋ぎ直しの間隔(10 秒) | 繋がらないときは終了コード 3 になる |
| 既定のコマンド時間(2 分) | 時間切れでは止まらず背面に移るだけ |
8 時間を指定しても、実際は 60 分で終わる。これは仕様なので直せない。CLAUDE_SUBAGENT_BG_SHELL_MAX_MS を伸ばす手はあるが、環境変数で挙動を変えると、他のプロジェクトと前提がずれる。
取りこぼしは無い(読んだ位置はサーバーが覚えている)ので、張り直しを前提にしておけば実害はない。
先にドキュメントを読むべきだった。実測を重ねて「約 60 分で揃っている」ところまで来ていたのに、その値が仕様として書かれていることを確かめなかった。
2 プロジェクトで延べ 20 回以上の観測を費やしている。公式の記述 1 行で済んだ話である。