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
fix(automation): do not resume scheduled worker sessions on restore - #506
A scheduled automation worker pane now restores as a plain shell. Its headless agent run is no longer reopened as an interactive session after a server restart, in that lifetime or any later one. Interactive panes, manual ORCH workers, and active_agent automations resume as before.
Follow-up to #488/#490. #488 promised to check how the optional Luvus Devin hook behaves in a scheduled run. That check, run on the merged Devin automation profile, found that the next server restart reopened the worker's session. The cause turned out to be agent-agnostic, so this PR fixes it for every agent instead of special-casing Devin.
src/app/board.rs: task_start marks the pane in App::automation_worker_panes when it launches TaskAgentLaunch::Automation. Manual task starts and active_agent targets are never marked.
src/app/mod.rs: a pane leaves the set when it closes, at the same point as backend_non_restorable. Restore reads the mark back and ignores any agent_session a marked pane still carries, for example from a hand-edited snapshot.
src/persist.rs:
PaneSnap::automation_worker (#[serde(default, skip_serializing_if = "Not::not")]), so ordinary panes keep the existing session.json shape and older snapshots still load.
A worker's reported run is claimed before pass 1. Pass 1 then leaves the worker unbound, exactly as it does a duplicate report, and discovery can't hand that conversation to another pane.
A worker without a report stays in its (agent, cwd) discovery group, so an interactive pane beside it remains ambiguous, as today. resolve_pane_sessions never binds a worker, whether by title or as "one pane, one session".
The live pane.report_session binding is unchanged, so Mission Control and usage still see the run. It is only kept out of resume.
Docs: automation guide (recovery after restart), agents guide (session resume), and website/public/agent-readme.md. Neither skill copy describes restore, so both are unchanged.
Design choices
#497 raised two open questions, each with two options. This PR deliberately takes the first option in both. Either one can be switched if you prefer the other.
Persisted mark vs. leaving workers out of restore: chosen: keep the pane and persist the mark. The finished worker's screen stays visible after a restart, and ORCH needs no change. The other option would also need the pass-2 grouping above: today's backend_non_restorable path drops a pane from its discovery group, and that would let an interactive pane in workspace mode inherit the worker's conversation.
An agent started by hand in a finished worker pane: chosen: the mark lasts for the pane's lifetime, so that pane doesn't resume either. It keeps the rule simple and predictable. The alternative, clearing the mark when an interactive agent appears, would be a small change.
Why
Neither api_pane_report_session nor capture_session_evidence knew that a pane was an automation worker. A worker pane could be bound in either snapshot pass: by a hook report, as measured with Devin and Claude, or by native discovery when its run was the only session in its directory, as measured with Codex. The next restart then ran <agent> --resume <id> interactively, without the worker's access policy, and kept doing so on every restart after that.
It shows up when the run finishes with no client attached, which is the usual case for a scheduled job, or when the server restarts during a run. With a TUI attached, process scans clear the binding when the agent exits. The full measurements are in #497.
The mark can't come from ORCH: pane ids are reallocated on restart, and assignee is either cleared or stale by then. A mark kept only in memory is not enough either. After one restart a restored worker screen can re-identify Codex, and the next restart would rebind it.
Screenshots
The same scheduled Codex worker in both images: workspace mode, run with no client attached, then a server restart and a TUI attach. AGENTS is filtered to Active.
Before, on main: the finished worker tab reopened codex resume by itself and is waiting at Codex's trust prompt. AGENTS shows a live blocked codex that nobody started.
With this PR: the worker tab restores as a shell with the finished run's output. AGENTS shows only the scheduled definition.
Verification
Windows 11, base f6c68e9.
cargo fmt --all --check (Rust 1.99.0, the current stable used by CI)
app::automation: active_agent_run_delivers_without_creating_an_orch_worker now also asserts that no pane is marked.
Each guarded line was reverted on its own, and at least one of the tests above failed every time. The checks were: marking at start, claiming the reported run, the pass-2 lone-worker guard, keeping an unbound worker in its group, the title guard, saving and restoring the mark, the restore filter, and close cleanup. That check also caught one design mistake before this PR: excluding a reported worker from pass 1 explicitly made an interactive pane beside it lose its own session. an_interactive_pane_keeps_its_own_session_beside_a_reported_worker covers that.
Existing tests unchanged and passing: reported_session_*, agent_session_persists_and_resumes, app::automation::tests, persist::title_resolution_tests.
cargo test --locked: on this Windows checkout the full suite stalls in five lock-heavy groups, as it does on unmodified main. With those groups skipped (integration::tests, diff::notes::tests, config::tests, cli::tests::wait_status_stream, i18n::cli), this branch reports 2152 passed and 32 failed. The 32 failures are exactly the ones unmodified main reports on this machine (CRLF docs tests, git::local, OSC 8, worktree, module titles, ipc::api streams, uhp::gateway). A few uhp::gateway and app::dispatch::tests::agents tests are flaky here under full-suite load on unmodified main too, and they pass in isolation. CI covers the full suite on Ubuntu and macOS.
Fork CI (run 38669110602): fmt · clippy · test (Ubuntu, including the Unix-only persist::tests), macos test, windows protocol · ConPTY, both nix flake jobs, cargo audit, npm audit, and the binary-size jobs passed.
cargo build --release --locked
npm run build in website/
End to end with the debug binary, in an isolated LUVUS_HOME and named sessions. The production server was not touched.
Claude worker (read-only, worktree) with its session reported from the worker pane, plus an interactive pane with a reported session:
snapshot: the worker gets agent_session: null and "automation_worker": true; the interactive pane keeps its session and gets no new field;
restart 1: the worker is a shell, and the interactive pane runs claude --resume '<id>';
inside the restored worker pane, I reported its run again, as a hook would;
restart 2: the worker is still a shell, it still carries the mark, and the interactive pane still resumes.
A Codex worker with no hook report (discovery pass), identified from its screen text: saved with agent_session: null, and restored as a shell. Before this change, the same case saved the exec rollout and restored with codex resume '<id>'.
A snapshot with the mark and a session: not resumed. A snapshot without the mark (written before this change): resumed, as noted below.
Devin 3000.11.3 with luvus integration install devin, which was the original report. The worker's SessionStart hook bound its run (authority: prior_identity) as before. The snapshot saved it as null with the mark, and two restarts left a shell with no devin --resume. The Devin config was restored byte for byte afterwards.
Workspace mode with Codex, beside a pane in the same directory: that pane kept its session and resumed. After the restart, the restored worker screen was re-identified as an agent, and the next snapshot still saved no session for it because the mark was persisted.
With a TUI attached: the worker was saved and restored the same way, and kept its mark across two snapshots.
Notes
A session.json written before this change has no mark, so the first restart after upgrading still reopens an already-bound worker pane interactively. From then on that pane is an ordinary interactive agent pane and keeps resuming, as it does today, until it is closed. Workers started after the upgrade are marked.
The worker's conversation stays in the agent's own store and can still be resumed deliberately (<agent> --resume <id>).
Measured on Windows only. Unix-only persist::tests run in CI.
Confidence Score: 5/5
The PR appears safe to merge; no actionable issues were found.
Summary
Scheduled automation worker panes now restore as shells instead of reopening their agent conversations.
Scheduled worker panes restore as shells instead of reopening agent runs.
Interactive panes keep their own sessions beside scheduled workers.
Intentional limits acknowledged by paulork: older snapshots have no worker mark, and agents started manually inside marked panes do not resume automatically.
Review used code inspection; no tests were run.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Scheduled worker starts] --> B[Mark worker pane]
B --> C[Save pane and mark]
C --> D[Exclude worker session from resume]
D --> E[Restore plain shell]
E --> F[Keep mark for later restarts]
F --> C
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.
📝 Summary
Summary by CodeRabbit
Behavior Changes
Scheduled automation worker panes now restore as plain shells after a server restart instead of reopening their agent conversations. Those conversations remain available to resume using the agent’s resume command.
Worker panes no longer claim saved agent sessions that could otherwise be associated with interactive panes.
Documentation
Updated the agent and automation guides with details on session restoration and resuming conversations.
Scheduled automation worker panes are marked at launch and recorded in snapshots. Session resolution prevents their agent sessions from binding to workers or neighboring panes. Restoration opens marked panes as shells. Tests and documentation cover the behavior.
Changes: Scheduled worker session restoration
Layer / File(s)
Summary
Mark scheduled worker panes src/app/board.rs, src/app/mod.rs, src/app/automation.rs
Successful scheduled launches add panes to the runtime worker set. Pane cleanup removes the mark. Tests cover scheduled and worktree launches, failed starts, manual workers, and active-agent delivery.
Snapshots record worker identity, and session resolution excludes worker sessions from restoration and discovery assignments. Restoration retains the mark and restores workers without an agent session. Tests and guides cover persistence, compatibility, and restart behavior.
sequenceDiagram
participant task_start
participant App
participant PaneSnap
participant resolve_pane_sessions
participant App_restore
task_start->>App: mark scheduled worker pane
App->>PaneSnap: save worker mark
PaneSnap->>resolve_pane_sessions: provide worker identity and session evidence
resolve_pane_sessions->>App_restore: omit worker agent session
App_restore->>App: restore worker as shell and retain mark
Loading
Suggested reviewers:rizriyz
Merge Risk:⚪ Minimal · up to 9ecf1
Scheduled workers are intended to restore as shells, and no actionable merge-blocking issue remains after normal checks.
Pre-merge checks: 4 · 1
Failed checks: 1 inconclusive
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 76.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 3 files. (4 skipped: …
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Linked Issues check
Issue #497 requires scheduled automation workers to avoid interactive session resume after restart while preserving live reporting and preventing session reassignment. task_start marks only `TaskAge…
Out of Scope Changes check
The changes stay within issue #497. The added tests verify the worker distinction and preserve manual ORCH and active_agent behavior. The documentation updates describe the new restore behavior. No …
Title check
The title clearly and concisely describes the primary change: scheduled worker sessions are not resumed during restore.
Description check
The description covers the user-facing result, behavior changes, rationale, verification, screenshots, compatibility details, and known limitations. It is detailed and aligned with the repository temp…
Full details: Docstring Coverage
Explanation
Docstring coverage is 76.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 3 files. (4 skipped: 3 unsupported, 1 too large.)
✨ Finishing Touches
🧪 Generate unit tests (beta)
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
area: agentsAgent detection, lifecycle, resume, fork, hooks, and skillsarea: orchestrationTasks, leases, boards, and worktreesarea: serverServer, IPC, sessions, persistence, and loggingarea: websiteWebsite and public documentationbugSomething isn't working
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A scheduled automation worker pane now restores as a plain shell. Its headless agent run is no longer reopened as an interactive session after a server restart, in that lifetime or any later one. Interactive panes, manual ORCH workers, and
active_agentautomations resume as before.Follow-up to #488/#490. #488 promised to check how the optional Luvus Devin hook behaves in a scheduled run. That check, run on the merged Devin automation profile, found that the next server restart reopened the worker's session. The cause turned out to be agent-agnostic, so this PR fixes it for every agent instead of special-casing Devin.
Closes #497
What
src/app/board.rs:task_startmarks the pane inApp::automation_worker_paneswhen it launchesTaskAgentLaunch::Automation. Manual task starts andactive_agenttargets are never marked.src/app/mod.rs: a pane leaves the set when it closes, at the same point asbackend_non_restorable. Restore reads the mark back and ignores anyagent_sessiona marked pane still carries, for example from a hand-edited snapshot.src/persist.rs:PaneSnap::automation_worker(#[serde(default, skip_serializing_if = "Not::not")]), so ordinary panes keep the existingsession.jsonshape and older snapshots still load.(agent, cwd)discovery group, so an interactive pane beside it remains ambiguous, as today.resolve_pane_sessionsnever binds a worker, whether by title or as "one pane, one session".pane.report_sessionbinding is unchanged, so Mission Control and usage still see the run. It is only kept out of resume.website/public/agent-readme.md. Neither skill copy describes restore, so both are unchanged.Design choices
#497 raised two open questions, each with two options. This PR deliberately takes the first option in both. Either one can be switched if you prefer the other.
backend_non_restorablepath drops a pane from its discovery group, and that would let an interactive pane in workspace mode inherit the worker's conversation.Why
Neither
api_pane_report_sessionnorcapture_session_evidenceknew that a pane was an automation worker. A worker pane could be bound in either snapshot pass: by a hook report, as measured with Devin and Claude, or by native discovery when its run was the only session in its directory, as measured with Codex. The next restart then ran<agent> --resume <id>interactively, without the worker's access policy, and kept doing so on every restart after that.It shows up when the run finishes with no client attached, which is the usual case for a scheduled job, or when the server restarts during a run. With a TUI attached, process scans clear the binding when the agent exits. The full measurements are in #497.
The mark can't come from ORCH: pane ids are reallocated on restart, and
assigneeis either cleared or stale by then. A mark kept only in memory is not enough either. After one restart a restored worker screen can re-identify Codex, and the next restart would rebind it.Screenshots
The same scheduled Codex worker in both images: workspace mode, run with no client attached, then a server restart and a TUI attach. AGENTS is filtered to Active.
Before, on
main: the finished worker tab reopenedcodex resumeby itself and is waiting at Codex's trust prompt. AGENTS shows a liveblocked codexthat nobody started.With this PR: the worker tab restores as a shell with the finished run's output. AGENTS shows only the scheduled definition.
Verification
Windows 11, base
f6c68e9.cargo fmt --all --check(Rust 1.99.0, the current stable used by CI)cargo clippy --all-targets -- -D warnings(Rust 1.99.0, Windows)app::board:a_scheduled_worker_does_not_save_its_reported_session_for_resumea_scheduled_worker_is_not_bound_to_its_discovered_sessionan_interactive_pane_does_not_inherit_a_workers_sessionan_interactive_pane_keeps_its_own_session_beside_a_reported_workera_restored_scheduled_worker_stays_unbound_when_identified_againa_restored_worker_keeps_its_mark_across_restartsa_worker_snapshot_that_names_a_session_does_not_resume_itthe_worker_mark_is_saved_only_for_workers(including a snapshot without the field)a_worktree_scheduled_worker_is_marked_and_not_resumeda_failed_scheduled_start_leaves_no_worker_markclosing_a_scheduled_worker_forgets_ita_manual_task_worker_still_saves_its_reported_sessionpersist::title_resolution_tests:a_scheduled_worker_title_never_resolves_its_own_runapp::automation:active_agent_run_delivers_without_creating_an_orch_workernow also asserts that no pane is marked.an_interactive_pane_keeps_its_own_session_beside_a_reported_workercovers that.reported_session_*,agent_session_persists_and_resumes,app::automation::tests,persist::title_resolution_tests.cargo test --locked: on this Windows checkout the full suite stalls in five lock-heavy groups, as it does on unmodifiedmain. With those groups skipped (integration::tests,diff::notes::tests,config::tests,cli::tests::wait_status_stream,i18n::cli), this branch reports 2152 passed and 32 failed. The 32 failures are exactly the ones unmodifiedmainreports on this machine (CRLF docs tests,git::local, OSC 8, worktree, module titles,ipc::apistreams,uhp::gateway). A fewuhp::gatewayandapp::dispatch::tests::agentstests are flaky here under full-suite load on unmodifiedmaintoo, and they pass in isolation. CI covers the full suite on Ubuntu and macOS.fmt · clippy · test(Ubuntu, including the Unix-onlypersist::tests),macos test,windows protocol · ConPTY, bothnix flakejobs,cargo audit,npm audit, and the binary-size jobs passed.cargo build --release --lockednpm run buildinwebsite/LUVUS_HOMEand named sessions. The production server was not touched.read-only, worktree) with its session reported from the worker pane, plus an interactive pane with a reported session:agent_session: nulland"automation_worker": true; the interactive pane keeps its session and gets no new field;claude --resume '<id>';agent_session: null, and restored as a shell. Before this change, the same case saved the exec rollout and restored withcodex resume '<id>'.luvus integration install devin, which was the original report. The worker'sSessionStarthook bound its run (authority: prior_identity) as before. The snapshot saved it asnullwith the mark, and two restarts left a shell with nodevin --resume. The Devin config was restored byte for byte afterwards.Notes
session.jsonwritten before this change has no mark, so the first restart after upgrading still reopens an already-bound worker pane interactively. From then on that pane is an ordinary interactive agent pane and keeps resuming, as it does today, until it is closed. Workers started after the upgrade are marked.<agent> --resume <id>).persist::testsrun in CI.

Confidence Score: 5/5
The PR appears safe to merge; no actionable issues were found.Summary
Scheduled automation worker panes now restore as shells instead of reopening their agent conversations.
Intentional limits acknowledged by
paulork: older snapshots have no worker mark, and agents started manually inside marked panes do not resume automatically.Review used code inspection; no tests were run.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Scheduled worker starts] --> B[Mark worker pane] B --> C[Save pane and mark] C --> D[Exclude worker session from resume] D --> E[Restore plain shell] E --> F[Keep mark for later restarts] F --> CReviews (1) · Last reviewed commit: "fix(automation): do not resume scheduled..." · Reviewed by Greptile