feat(coding-agent): whole-tree idle eviction - #588
Merged
Merged
Conversation
This was referenced Aug 2, 2026
snimu
added a commit
that referenced
this pull request
Aug 3, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 3, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
added a commit
that referenced
this pull request
Aug 3, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 3, 2026 12:05
aa98c9a to
19a2be1
Compare
snimu
added a commit
that referenced
this pull request
Aug 3, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 19a2be1. Configure here.
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 00:44
19a2be1 to
4a062fa
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 06:10
4a062fa to
cc8b7d0
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 07:42
cc8b7d0 to
262aabc
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 18:46
92d8c2a to
cfd8ddf
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 20:25
cfd8ddf to
d9241ea
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 20:56
d9241ea to
92ede8d
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
sethkarten
self-requested a review
August 4, 2026 21:44
sethkarten
approved these changes
Aug 4, 2026
snimu
force-pushed
the
feat/whole-tree-eviction
branch
from
August 4, 2026 22:35
92ede8d to
1231a19
Compare
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…eep snapshot atomicity - Finding 22: async snapshot creation exposed clients before attach initialization; publish client attachment only after the snapshot resolves. origin: PR #587 - Finding 23: catch-up validity was checked only before async snapshot creation; revalidate session and client attachment after the await. origin: PR #587 - Finding 25: deterministic ambiguous selectors entered the 30-second remote-send retry loop; fail fast for Ambiguous errors. origin: PR #588 - Finding 28: active rows ignored stable file-keyed schedule pins during active-id rebinding; consult both id- and file-keyed heartbeat/cron sets. origin: PR #588 - Finding 29: passivation sampled activity before an asynchronous passive-registry walk; complete the walk before atomically sampling summary and admission markers. origin: PR #589
snimu
added a commit
that referenced
this pull request
Aug 4, 2026
…n, summary refresh, pulse, and settings cycling - Finding 18: stale saved-catalog readiness could destructively drop scope during refresh; reset readiness when refresh starts. origin: PR #586 - Finding 19: resolved scope roots were lost across view remounts, swallowing early Left navigation; persist and restore the root summary. origin: PR #586 - Finding 20: post-attach crashes left backSession pointing at the prior session; assign the opened summary before interactive mode runs. origin: PR #586 - Findings 21 and 24: startup seeding could leave subagent counts stale and background subagents drove an unused render pulse; refresh every seed and pulse only while streaming. origin: PR #587 - Finding 27: custom idle-eviction values cycled directly to off; include custom numeric values in the sorted cycle. origin: PR #588
Track A PR 6 of the recursive-agent-harness plan (D5, eviction shape 1): - supervisor idle sweep stops worker processes whose entire session tree has been idle past the threshold; evicted trees become ordinary inactive rows (non-archive stop; catalog preserved; attach and a2a wake them via the existing lazy-hydration paths) - pure canEvictWorker() predicate (extends the session-action-store policy module): every session must be non-busy (isSessionSummaryBusy = active or running RLM children), detached, schedule-free, and idle past threshold; fail-closed on missing timestamps; rejects starting/recovering/stopping/ owned/update-preparing workers; eviction never cascades across workers - per-session residency metadata on summaries: lastActivityAt (max across all message types), heartbeat/cron pins (active heartbeats only; passive sessions matched by resolved session file); schema rev 10 (additive) - a2a to an evicted/inactive session resolves through the saved catalog, opens a fresh worker, and delivers after binding; ambiguity errors propagate distinctly from unknown-target errors - idleEvictionMinutes setting (default 90, 'off' disables) via /settings; supervisor re-reads settings each sweep
- Ignore finite message timestamps outside the JavaScript Date range so one corrupt persisted timestamp cannot abort session-list generation. - Preserve valid latest-message activity when invalid timestamps are present. - Narrow passive RLM snapshot rows to resident roots so the branch remains type-safe.
- Forward resolved same-worker agent message targets through the guarded worker delivery command. - Fail genuinely unknown selectors without returning them to the source worker.
- Validate agent messages before resolving local or remote targets. - Retry remote delivery only for failures before a supervisor response. - Cover nonresident validation and deterministic supervisor rejection paths.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.

Worker processes used to stay alive forever, even when every session in them had been idle for hours. This PR makes the supervisor notice and stop them.
A background sweep checks each worker. If every session in it has been idle past a threshold, and nothing is attached, and no timers (heartbeats/cron jobs) are pinned to it, the worker process is stopped. Nothing is lost: the sessions become ordinary inactive entries, and attaching to one — or sending it a message — starts a fresh worker and picks up where it left off.
The threshold is a new
idleEvictionMinutessetting (default 90;offdisables it), which you can change in/settings.The check errs on the side of caution: if a worker's state is at all unclear (busy session, running subagent, missing timestamps, mid-startup or mid-shutdown), it's left alone.
This is part 1–7 of a stack (each PR builds on the one before it):
/rlm-max-depthcommand to control how deep agents can nestTests: the full suite at the top of the stack fails only on tests that already fail on the base branch. Each branch in the stack also passes checks and its own tests independently.
Note
Add whole-tree idle eviction to the coding agent daemon supervisor
canEvictWorkerinsession-action-store.tsto evaluate eviction eligibility: a worker is evictable only when ready, connected, unowned, not updating, and all sessions have been idle beyond the configured threshold with no attachments, heartbeats, or cron jobs.idleEvictionMinutestoSettingsManager(default 90 minutes;'off'disables eviction) and exposes it in the interactive settings UI as an 'Idle worker eviction' option.runIdleEvictionSweep, which reloads settings, evaluates candidates viacanEvictWorker, and stops eligible workers. Sweep interval is bounded between 1 and 5 minutes.SessionSummarywithhasRegisteredHeartbeat,hasRegisteredCronJob, andlastActivityAtfields (protocol schema bumped to revision 12).Macroscope summarized b184c50.
Note
Medium Risk
Changes supervisor worker lifecycle, session protocol schema, and cross-worker messaging wake paths; mistakes could stop workers prematurely or mishandle a2a delivery, though policy is conservative and heavily tested.
Overview
Introduces whole-tree idle worker eviction: a global
idleEvictionMinutessetting (default 90,offto disable) in settings and/settings, plus purecanEvictWorkerpolicy that only stops a worker when every session is past the threshold with no attachments, active heartbeats, or registered cron jobs.The daemon supervisor runs periodic sweeps (interval derived from the threshold), reloads settings each pass, fences mutating commands during eviction, and stops eligible workers while logging evictions. Session list rows gain
hasRegisteredHeartbeat,hasRegisteredCronJob, andlastActivityAt(from message timestamps); daemon schema revision 12 documents these fields. Paused heartbeats no longer pin residency.Agent-to-agent messaging improves for non-resident targets: the supervisor can catalog-resolve a selector (including exact names, with ambiguity errors when a name collides with an id prefix), wake a saved session through the existing create path, and deliver the message; workers validate messages before remote fallback and do not retry supervisor rejections.
Also refreshes generated model catalog entries (pricing/limits and a few provider models).
Reviewed by Cursor Bugbot for commit b184c50. Bugbot is set up for automated code reviews on this repo. Configure here.