Skip to content

feat(restart): restart running agents in place, resuming their conversation#27

Merged
jakemassoth merged 1 commit into
mainfrom
restart-resume
Jul 20, 2026
Merged

feat(restart): restart running agents in place, resuming their conversation#27
jakemassoth merged 1 commit into
mainfrom
restart-resume

Conversation

@jakemassoth

Copy link
Copy Markdown
Owner

What

Adds yeschef restart: swap every live agent in the brigade — the head chef and all running line cooks — for a fresh process in place, resuming each one's prior conversation.

This is the "I just updated Claude Code, pick up the new binary without losing context" button.

Why

There was no way to restart the running Claude Code sessions (e.g. after a Claude Code update) without killing each window and losing the brigade layout — and re-spawning starts a fresh conversation. restart swaps only the process inside each window and resumes where the agent left off.

How

  • New TmuxBackend::respawn_window wraps tmux respawn-pane -k -c <cwd>, which kills a pane's current process and relaunches a command in the same pane. The window (name, tab position, @status colour) survives untouched — unlike kill + new-window, which drops and recreates the tab.
  • run_restart walks the ticket registry intersected with the live window list, respawning cooks first and the head chef last — so a restart issued from the head chef's own window (respawning window 0 kills the caller) still brings every cook back up first. Gone windows are skipped; an absent session errors clearly (nothing to restart).
  • Conversation resume: claude-family agents are relaunched with --continue (reopen the latest conversation in the pane's cwd); other agents (codex, aider, …) restart verbatim — no portable resume flag — keeping yeschef agent-agnostic.

Tests

  • Unit (mock-backed): resume-flag logic (claudeclaude --continue, others verbatim), cook-first/head-chef-last ordering, skipping gone windows, and the no-session error.
  • E2E (real tmux): restart_respawns_agent_in_place proves the window survives while the agent process is genuinely relaunched in the same worktree (a stand-in agent ticks a file on each start — one tick after spawn, a second after restart); restart_without_session_errors covers the empty-brigade case.

Full CI gate green locally: nix flake check (fmt + nixfmt + clippy-pedantic + unit) and nix run .#e2e (19/19).

…sation

Add `yeschef restart`: swap every live agent in the brigade — the head
chef and all running line cooks — for a fresh process without disturbing
the brigade layout, resuming each one's prior conversation. This is the
"I just updated Claude Code, pick up the new binary without losing
context" button.

- New `TmuxBackend::respawn_window` wraps tmux `respawn-pane -k -c <cwd>`,
  which kills the pane's current process and relaunches a command in the
  SAME pane. The window (name, tab position, `@status` colour) survives
  untouched — unlike kill + `new-window`, which drops and recreates the
  tab.
- `run_restart` walks the ticket registry intersected with the live
  window list, respawning cooks first and the head chef last so a
  restart issued from the head chef's own window (respawning window 0
  kills the caller) still brings every cook back up first. Gone windows
  are skipped; an absent session errors clearly.
- Claude-family agents are relaunched with `--continue` to resume their
  latest conversation in the pane's cwd; other agents restart verbatim
  (no portable resume flag), keeping yeschef agent-agnostic.

Tests: unit tests cover the resume-flag logic, cook-first/head-chef-last
ordering, skipping gone windows, and the no-session error; an e2e test
proves the real tmux respawn keeps the window while relaunching the
process in the same worktree.
@jakemassoth
jakemassoth merged commit ec2ae10 into main Jul 20, 2026
2 checks passed
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