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
{{ message }}
Repository navigation
A session that ends its turn waiting on a background task is killed, and the Run fails with 'no PR found' #58
A Run on JacobStephens2/vacation#29 failed with no PR found after the implement session ended while the agent was still waiting on a background test run.
The agent started ./mvnw test -Dtest='GamesPageTest' with run_in_background: true, said "Waiting on the test run's completion notification.", and ended its turn (stop_reason: end_turn, terminal_reason: completed). Headless claude -p then exited and killed both background Bash tasks ("status":"killed" in the stream). The agent never committed, pushed, or ran gh pr create, so the Run's PR check failed. The work survived only because the Failed run path committed and pushed it (2a4a624 on issue-29).
The terminal showed only thirdshift: no PR found, which hides the cause.
Category: bug Summary: A session that ends its turn while waiting on a background Bash task is killed mid-job, and the Run fails with an unexplained no PR found
Current behavior:
thirdshift runs each session with claude -p. If the agent starts a Bash command with run_in_background: true and then ends its turn to wait for the completion notification, the CLI exits and kills the background task. That is different from background sub-agents, which the session does wait for and resume after (the Progress docs assume every waiting session resumes). The implement session therefore stops before committing or opening a PR. The Run then pushes, fails open_pr with no PR found, and takes the Failed run path. Nothing on stderr says the session ended while waiting on a killed task. A Repair session could hit the same thing and leave CI unfixed.
Desired behavior:
Prevention: the prompts for every session kind (prompt::fresh, prompt::continuation, prompt::conflict_repair, prompt::ci_fix_repair) tell the agent that it runs headless: run tests and other long commands in the foreground (raising the Bash timeout if needed), and never end its turn while a background task it depends on is still running, because ending the turn ends the session and kills the task.
Recovery: when a session exits cleanly but its stream shows background tasks that were killed at the end (system events with subtype: "task_updated" and patch.status: "killed", or a task_notification with status: "stopped", after the last result), thirdshift resumes that same session once with claude -p --resume <session_id>. It passes a short prompt saying the background work was killed when the turn ended, and asking the agent to re-run whatever it was waiting on in the foreground and finish its job. The resumed session is logged and reported like any other: its own log file, labelled for example implement-resume, with progress lines and a summary. It runs through the same interrupt handling.
Diagnosis: if the session still ends with killed background tasks after the one resume, the Run fails with an error that says so, naming the session kind and the killed task's description, for example implement session ended while waiting on a background task (./mvnw test ...), which was killed. It does not fall through to no PR found.
Key interfaces:
Progress, or whatever condenses the stream: it records the session_id from system/init and whether background tasks were killed after the last result, and makes both available once the process exits
session::run: returns enough for the caller to know whether a resume is needed (for example a small outcome struct rather than ()), or does the single resume itself
The prompt builders: each gets the headless / no-background-waiting instruction; keep the wording in one place and share it
CONTEXT.md: if the resume counts as its own session kind, add it to the glossary alongside Repair
Acceptance criteria:
Every prompt thirdshift sends includes the instruction to run long commands in the foreground and not end the turn while waiting on a background task
Given a recorded stream whose last result is followed by a killed background task, stream processing reports "killed background work" and the session id; a stream with no killed tasks, or with only background sub-agents that resumed, reports nothing
A session that ends with killed background tasks is resumed exactly once via --resume <session_id>, and the resumed session gets its own log path and progress lines
If the resumed session finishes its job (for implement, a PR exists), the Run continues as normal
If the resumed session also ends with killed background tasks, the Run fails with a message naming the session kind and the killed task, not no PR found
The Failed run path still commits and pushes uncommitted work in every one of these cases
Tests cover the stream detection with fixture lines and the resume-once / fail-with-reason behavior, using the same fake-claude approach the existing Run tests use
Out of scope:
Resuming more than once, or making the resume count configurable
Resuming sessions that ended for other reasons (errors, max_turns, interrupts)
Changing how Repairs are counted against MAX_REPAIRS; a resume is not a Repair
CPU contention between Runs on the same machine (the vacation agent's first test run produced no output, apparently because another worktree was using the CPU); file that separately if it keeps happening
Activity
JacobStephens2 commentedon Sep 25, 2026
Agent Brief
Category: bug
Summary: A session that ends its turn while waiting on a background Bash task is killed mid-job, and the Run fails with an unexplained
no PR foundCurrent behavior:
thirdshift runs each session with
claude -p. If the agent starts a Bash command withrun_in_background: trueand then ends its turn to wait for the completion notification, the CLI exits and kills the background task. That is different from background sub-agents, which the session does wait for and resume after (theProgressdocs assume every waiting session resumes). The implement session therefore stops before committing or opening a PR. The Run then pushes, failsopen_prwithno PR found, and takes the Failed run path. Nothing on stderr says the session ended while waiting on a killed task. A Repair session could hit the same thing and leave CI unfixed.Desired behavior:
prompt::fresh,prompt::continuation,prompt::conflict_repair,prompt::ci_fix_repair) tell the agent that it runs headless: run tests and other long commands in the foreground (raising the Bash timeout if needed), and never end its turn while a background task it depends on is still running, because ending the turn ends the session and kills the task.systemevents withsubtype: "task_updated"andpatch.status: "killed", or atask_notificationwithstatus: "stopped", after the lastresult), thirdshift resumes that same session once withclaude -p --resume <session_id>. It passes a short prompt saying the background work was killed when the turn ended, and asking the agent to re-run whatever it was waiting on in the foreground and finish its job. The resumed session is logged and reported like any other: its own log file, labelled for exampleimplement-resume, with progress lines and a summary. It runs through the same interrupt handling.implement session ended while waiting on a background task (./mvnw test ...), which was killed. It does not fall through tono PR found.Key interfaces:
Progress, or whatever condenses the stream: it records thesession_idfromsystem/initand whether background tasks were killed after the lastresult, and makes both available once the process exitssession::run: returns enough for the caller to know whether a resume is needed (for example a small outcome struct rather than()), or does the single resume itselfAcceptance criteria:
resultis followed by a killed background task, stream processing reports "killed background work" and the session id; a stream with no killed tasks, or with only background sub-agents that resumed, reports nothing--resume <session_id>, and the resumed session gets its own log path and progress linesno PR foundclaudeapproach the existing Run tests useOut of scope:
max_turns, interrupts)MAX_REPAIRS; a resume is not a Repair