Skip to content

fix: auto-resume Claude session on genie spawn - #994

Merged
namastex888 merged 3 commits into
devfrom
fix/spawn-auto-resume
Apr 2, 2026
Merged

namastex888 merged 3 commits into
devfrom
fix/spawn-auto-resume

Conversation

@namastex888

Copy link
Copy Markdown
Contributor

Summary

  • Auto-resume dead workers: When genie spawn is called for an agent that previously had a running Claude Code session (now dead), it now resumes the existing session instead of creating a new one, preserving all conversation context.
  • Fix sessionExists name mismatch: sessionExists() in team-lead-command.ts now also checks for {name}-{name} format, matching how Claude Code stores team-prefixed session names.
  • Extract helper for lint compliance: Moved dead-worker detection into a standalone findDeadResumable() helper to keep handleWorkerSpawn under the cognitive complexity threshold.

Root cause

handleWorkerSpawn() always generated a new sessionId via crypto.randomUUID(), and rejectDuplicateRole() unregistered dead workers before their claudeSessionId could be used for resume. The new logic runs before rejectDuplicateRole to detect and resume dead workers that have a saved Claude session.

Files changed

  • src/term-commands/agents.ts — auto-resume detection + findDeadResumable helper
  • src/lib/team-lead-command.ts — sessionExists() name format fix

Test plan

  • bun run build passes
  • bun test src/term-commands/agents.test.ts — 9 tests pass
  • bun test src/lib/team-lead-command.test.ts — 16 tests pass
  • Manual: spawn an agent, stop it, spawn again — verify it resumes the existing session
  • Manual: spawn a fresh agent with no prior session — verify normal fresh spawn works

Test added 3 commits April 2, 2026 16:56
When `genie spawn` is called for an agent that previously had a running
Claude Code session (now dead), it always created a new session, losing
all conversation context. This adds auto-resume detection in
handleWorkerSpawn before rejectDuplicateRole cleans up the dead worker
entry, preserving the claudeSessionId for resume.

Also fixes sessionExists() in team-lead-command.ts to check for the
team-prefixed session name format ({name}-{name}) that Claude Code
actually stores.
…xity

Moves the dead-worker detection logic from inline in handleWorkerSpawn
into a standalone findDeadResumable() helper, keeping the function
under the lint complexity threshold.
@coderabbitai

coderabbitai Bot commented Apr 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e7214686-b714-468f-96e7-db861742efd7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/spawn-auto-resume

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@namastex888
namastex888 merged commit 4f7b357 into dev Apr 2, 2026
6 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 83fafb96fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1216 to +1217
await resumeAgent(deadResumable);
return deadResumable.id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip auto-resume when tmux context is unavailable

This branch always calls resumeAgent for a dead Claude worker, but resumeAgent hard-exits when process.env.TMUX is unset. As a result, running genie spawn from a non-tmux shell now fails whenever a stale dead worker exists, instead of falling back to normal spawn behavior (including cases where the caller intended a fresh spawn). Gate auto-resume on a valid tmux context and continue through the regular spawn path when resume cannot run.

Useful? React with 👍 / 👎.

Comment on lines +1211 to +1212
const deadResumable = await findDeadResumable(team, effectiveRole);
if (deadResumable) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect explicit provider override before auto-resume

Auto-resume runs before provider resolution and does not consider options.provider, so a dead Claude worker with the same role/team will be resumed even when the user explicitly requested --provider codex. This returns early and bypasses the normal spawn flow, making provider selection ineffective in this scenario. Auto-resume should be conditional on the requested/resolved provider being Claude.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces auto-resume capabilities for Claude sessions and improves session name matching to include team-prefixed formats. It adds a mechanism to find and resume dead workers with existing session IDs during the worker spawn process. Feedback suggests improving the selection logic for resumable workers by excluding those in a 'done' state and prioritizing the most recent session, as well as ensuring the logic respects the user's auto-resume preference.

Comment on lines +983 to +985
const candidate = existing.find(
(w) => w.role === role && w.team === team && w.claudeSessionId && w.provider === 'claude',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If multiple dead workers exist for the same role and team, find() will return the first one encountered in the registry list, which may not be the most recent session. Additionally, we should avoid resuming workers that reached a done state. Sorting by startedAt descending ensures the most recent context is resumed.

Suggested change
const candidate = existing.find(
(w) => w.role === role && w.team === team && w.claudeSessionId && w.provider === 'claude',
);
const candidate = existing
.filter((w) => w.role === role && w.team === team && w.claudeSessionId && w.provider === 'claude' && w.state !== 'done')
.sort((a, b) => b.startedAt.localeCompare(a.startedAt))[0];

return process.exit(1) as never;
}
// Auto-resume: if a dead worker exists with a Claude session, resume instead of fresh spawn.
const deadResumable = await findDeadResumable(team, effectiveRole);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The auto-resume logic should respect the autoResume option. If a user explicitly passes --no-auto-resume (setting options.autoResume to false), they likely intend to start a fresh session rather than resuming a dead one.

Suggested change
const deadResumable = await findDeadResumable(team, effectiveRole);
const deadResumable = options.autoResume !== false ? await findDeadResumable(team, effectiveRole) : null;

@namastex888
namastex888 deleted the fix/spawn-auto-resume branch April 10, 2026 16:19
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.

1 participant