Skip to content

(bg-agents): stop relaunched background conversations from running twice (#1020) - #1032

Merged
devsuitup merged 10 commits into
mainfrom
wt/1020
Nov 9, 2026
Merged

devsuitup merged 10 commits into
mainfrom
wt/1020

Conversation

@devsuitup

Copy link
Copy Markdown
Owner

Closes #1020.

Relaunching a background conversation could start a second copy. The CLI's /exit forks the session (continuedInSessionId), then Switchboard respawned the old id beside the fork.

  • Handoff: after /exit, the handoff adopts the fork the CLI created, and stops the old CLI if it outlives the exit timeout. If the conversation already runs in the background, the tab is left untouched and points to the sidebar.
  • Continuation evidence:
    • A continued-in record still being written counts as uncertain, so a respawn waits or refuses instead of trusting it.
    • An ordinary user or assistant line cut mid-write stays sealed evidence: its first key is not type, and the CLI writes continuation records type-first (checked against CLI 2.1.302).
  • Respawn:
    • Dead jobs in state working, done, running or failed are restored automatically; blocked and stopped jobs keep an explicit Respawn.
    • Concurrent respawns of one job run once, and a successful respawn is shared with every caller that joined it.

Follow-up, not in this PR: a manual Respawn clicked within the seconds after a restore's claude respawn returns, before the daemon publishes the new worker, can still respawn again.

Harness-Claim: true
Agent: switchboard-dev
Host: ANCHOR
Base-Ref: origin/main
Base-SHA: e0f144b
Claimed-At: 2026-11-07T17:26:54.967654Z
Nonce: 7a26dddc72e719b3
…#1020)

On exit the CLI may fork the session into a background job. The handoff took the
terminal's exit to mean the conversation was free and respawned the old id, so
two copies ran with the same crons. Adopt a new continuation, refuse a respawn
when one is live or unknown, and do not bring such a job back at restore.
… out

Restore still respawns dead working, done and running jobs unless a live
continuation exists; a dead blocked job waits for a Respawn click that now works.
An unreadable or deleted continuation no longer refuses forever, the check skips
the job itself, and the handoff checks continuations before typing /exit.
…record from respawning

A conversation already running in the background is refused instead of adopted; an unterminated continued-in record no longer counts as proof, and dead failed jobs restore automatically like done and running ones.
…urce after adopting its fork

A continued-in record cut before its type tag no longer counts as proof that no continuation exists; adopting a fork after the exit timeout now stops the old CLI; concurrent respawns of one job run once.
A torn user or assistant line, whose first key is not type, no longer counts as a possible continuation; a joining respawn with different parameters runs its own check.
A restore or click that overlaps a respawn which already succeeded takes its result instead of respawning again while the daemon has not yet published the new worker.
@devsuitup
devsuitup merged commit 3aefedd into main Nov 9, 2026
11 of 12 checks passed
@devsuitup
devsuitup deleted the wt/1020 branch November 9, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

(bg-agents): sending a resumed tab to background duplicates the conversation when the CLI forks it on exit

1 participant