You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This box's own hook session for #535/#546 (this repo's fix for a different
flavor of the same problem) got a live demonstration of it: a sibling
session ran sudo systemctl reboot at 16:40:39 while this session was
mid-task, waiting on CI and a CodeRabbit review for PR #546. The reboot
killed every tmux session with no epilogue, the supervisor silently
respawned this one via --resume (confirmed: AGENT_BOX_RESTART_NOTICE is
off, per #507/#512's default), and it then sat fully idle for 2.5 hours
— CI had failed and CodeRabbit had requested changes in the meantime, and
nothing happened until the user noticed and asked why.
This isn't quite the case #507/#512 reasoned about
PR #512's decision was specifically about the canned interruption text:
"--resume restores the transcript on its own, so a respawn ... hands the
agent no injected prompt at all rather than this notice." That's a good
call for the verbose "You were interrupted and automatically restarted..."
message being unnecessary noise when the agent can just read its own
transcript.
But "no injected prompt" doesn't mean "the agent reads its transcript and
decides what to do" — it means no new turn is triggered at all. A
resumed Claude Code process sits at the prompt exactly as claude --resume
outside agent-box would: correctly caught up, and doing nothing until
someone or something starts a turn. For an ordinary interactive session
that's fine — a human will type something eventually. For a session with
an outstanding external commitment (an open PR it authored, a claimed
webhook topic, anything hook-* by definition), there's nobody to type
anything, and it can sit there indefinitely with no signal to anyone that
it needs to.
Make the nudge conditional, not global: only inject a minimal
"you were interrupted, check whether your prior work is still needed"
prompt when the respawned session has something to check — e.g. a
non-stoppedboxSessionId/transcript that has real work AND (new,
via feat(sessions): durable lease for a hook session's accepted assignment #546) an unresolved lease (outcome: died:<status> or vanished) for that session name. That's a much narrower trigger than
"every respawn," and it reuses state feat(sessions): durable lease for a hook session's accepted assignment #546 already maintains — a lease_mark_outcome write on respawn is exactly the moment to also
decide whether to nudge.
No recommendation forced here between (1) and (2) — (2) is more surgical
and ties into #546's own lease state, but is more code; (1) is one config
flip whose cost is a message the agent can trivially answer "already
handled" and stop. Lio's call.
Also worth confirming from the incident itself
Independent of the reboot: CodeRabbit's review (16:21:29) and CI's failure
(16:27:16) both landed on PR #546before the reboot, while the session's
own webhook subscription should have still been live (subscribed ~16:15,
2h TTL) — and neither reached the session either. That gap is not explained
by this issue and wasn't root-caused (no access to the prior boot's
local-webhook receiver logs from here); flagging it here since it compounds
the same symptom, but it may be a distinct bug in the delivery path itself.
Incident
This box's own hook session for #535/#546 (this repo's fix for a different
flavor of the same problem) got a live demonstration of it: a sibling
session ran
sudo systemctl rebootat 16:40:39 while this session wasmid-task, waiting on CI and a CodeRabbit review for PR #546. The reboot
killed every tmux session with no epilogue, the supervisor silently
respawned this one via
--resume(confirmed:AGENT_BOX_RESTART_NOTICEisoff, per #507/#512's default), and it then sat fully idle for 2.5 hours
— CI had failed and CodeRabbit had requested changes in the meantime, and
nothing happened until the user noticed and asked why.
This isn't quite the case #507/#512 reasoned about
PR #512's decision was specifically about the canned interruption text:
"
--resumerestores the transcript on its own, so a respawn ... hands theagent no injected prompt at all rather than this notice." That's a good
call for the verbose "You were interrupted and automatically restarted..."
message being unnecessary noise when the agent can just read its own
transcript.
But "no injected prompt" doesn't mean "the agent reads its transcript and
decides what to do" — it means no new turn is triggered at all. A
resumed Claude Code process sits at the prompt exactly as
claude --resumeoutside agent-box would: correctly caught up, and doing nothing until
someone or something starts a turn. For an ordinary interactive session
that's fine — a human will type something eventually. For a session with
an outstanding external commitment (an open PR it authored, a claimed
webhook topic, anything hook-* by definition), there's nobody to type
anything, and it can sit there indefinitely with no signal to anyone that
it needs to.
Options
restartNoticeback on globally. Simple, but reintroduces thenoise feat(sessions): make the claude restart notice opt-in, off by default #512 was avoiding for the common case (an interactive session
whose work is already done or who doesn't need a nudge).
"you were interrupted, check whether your prior work is still needed"
prompt when the respawned session has something to check — e.g. a
non-
stoppedboxSessionId/transcript that has real work AND (new,via feat(sessions): durable lease for a hook session's accepted assignment #546) an unresolved lease (
outcome: died:<status>orvanished) for that session name. That's a much narrower trigger than"every respawn," and it reuses state feat(sessions): durable lease for a hook session's accepted assignment #546 already maintains — a
lease_mark_outcomewrite on respawn is exactly the moment to alsodecide whether to nudge.
follow-up on auto-requeue/notification for a stranded hook-*
assignment) — except Decide: auto-requeue and/or GitHub notification for a stranded hook-* assignment (#535 follow-up) #547 is scoped to a hook session's worker dying;
this incident is about a session that's very much alive again after a
respawn, just silent. Worth keeping the two issues distinct even if a
shared mechanism ends up serving both.
No recommendation forced here between (1) and (2) — (2) is more surgical
and ties into #546's own lease state, but is more code; (1) is one config
flip whose cost is a message the agent can trivially answer "already
handled" and stop. Lio's call.
Also worth confirming from the incident itself
Independent of the reboot: CodeRabbit's review (16:21:29) and CI's failure
(16:27:16) both landed on PR #546 before the reboot, while the session's
own webhook subscription should have still been live (subscribed ~16:15,
2h TTL) — and neither reached the session either. That gap is not explained
by this issue and wasn't root-caused (no access to the prior boot's
local-webhook receiver logs from here); flagging it here since it compounds
the same symptom, but it may be a distinct bug in the delivery path itself.