Skip to content

feat(chat): hibernate idle sessions when their view closes - #6087

Draft
illegalcall wants to merge 26 commits into
mainfrom
codex/chat-hibernation
Draft

illegalcall wants to merge 26 commits into
mainfrom
codex/chat-hibernation

Conversation

@illegalcall

@illegalcall illegalcall commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Code changes: +1459 -161
Tests: +2189 -53
Others: +398 -6

How it works

  • With Developer Mode on, a chat sleeps after its latest visible turn settles and its Chat view closes, if its provider can resume the same conversation. AO stops its background processes and keeps the chat history.
  • Opening the chat or sending a message wakes it automatically. AO-sent messages do too. Agents still working, with queued work, needing input or approval, or running in a terminal stay active.
  • The 30-second sweep is skipped while Developer Mode is off. When on, eligibility checks only the latest visible user turn instead of loading the full transcript.
  • If waking fails, the error appears beside the composer. History and drafts remain; reopening Chat, sending, or selecting Try connecting again retries. Lease renewals do not restart the agent.

Evidence

  • Claude Code before/after interrupted-turn demo: old build kept the host alive; changed build stopped it, woke with history, and slept again.
  • Full macOS demo: Claude and Codex start, reply, sleep with process exit, wake with history, reply again, and sleep again.
  • OpenCode ACP on zai-coding-plan/glm-5.3-flash: a fresh task replied; leaving Chat set hibernated_at and exited host/provider PIDs 41475/41480. Reopening and immediately messaging recalled IBIS-53 using new PIDs 41768/41769; leaving Chat exited both again.
  • Electron retest: a forced Claude 409 appeared in the composer. After restoring the saved ID, Try connecting again restarted the host, kept the draft, and Claude recalled PELICAN-42. A forced 500 remained visible after a 204 lease renewal; retry recovered.

QA matrix

Flow Result
Developer Mode gate; idle sleep and process exit Passed on macOS with Claude ACP, Codex app-server, and OpenCode ACP
Open or message to wake with history; concurrent messages queue once Passed
Long command, compaction, open Chat view stay awake; failed/interrupted turns sleep after leaving Chat Passed
Switch session or shell tab; daemon restart; toggle; kill; Chat→TUI Passed
Invalid API input Missing or null active returns 400; unknown fields remain accepted
Forced failed resume Passed on macOS: error stays visible through renewal; composer retry wakes once without sending the draft
Pending approval Unit tested only
Linux/Windows live app Not run

Other providers need live testing and native conversation resume support.

@github-actions

Copy link
Copy Markdown
Contributor

🏆 Review leaderboard

Sep 23–30, 2026 · UTC

Rank Reviewer PRs reviewed Review rounds PR comments
🥇 @nikhilachale @nikhilachale 28 57 8
🥈 @illegalcall @illegalcall 24 47 6
🥉 @ronishrohan @ronishrohan 23 33 9
4 @Prasad-D-Ware @Prasad-D-Ware 15 27 3
5 @codebanditssss @codebanditssss 13 21 1
6 @Rishet11 @Rishet11 10 19 10
7 @mohakchakraborty2004 @mohakchakraborty2004 8 8 5
8 @Annieeeee11 @Annieeeee11 7 15 5
9 @neversettle17-101 @neversettle17-101 6 8 5
10 @harshitsinghbhandari @harshitsinghbhandari 5 7 0

Ranked by distinct external PRs reviewed, then review rounds, then PR comments. Self-activity and bot activity are excluded.

Show 9 more reviewers
Rank Reviewer PRs reviewed Review rounds PR comments
11 @Vaibhaav-Tiwari @Vaibhaav-Tiwari 5 5 2
12 @Pritom14 @Pritom14 2 2 2
13 @Pulkit7070 @Pulkit7070 2 2 1
14 @somewherelostt @somewherelostt 1 3 2
15 @ApexYash11 @ApexYash11 1 2 2
16 @AgentWrapper @AgentWrapper 1 1 0
17 @aprv10 @aprv10 1 1 0
18 @Ayash-Bera @Ayash-Bera 1 1 0
19 @LaibaFirdouse @LaibaFirdouse 1 1 0

@illegalcall
illegalcall marked this pull request as draft September 30, 2026 19:33
@illegalcall
illegalcall force-pushed the codex/chat-hibernation branch from 6d9a234 to 93c848d Compare October 1, 2026 03:47
@i-trytoohard i-trytoohard added comp/daemon Go daemon, process lifecycle, and backend control plane. enhancement New feature or request labels Oct 1, 2026
@i-trytoohard i-trytoohard added this to the Agents & orchestration milestone Oct 1, 2026
@illegalcall
illegalcall force-pushed the codex/chat-hibernation branch from 93c848d to 7bd51ad Compare October 1, 2026 06:03
@illegalcall

illegalcall commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Full macOS dev-build demo (Developer Mode ON): Claude ACP (0:00) and Codex app-server (1:45) each show a fresh session, first reply, hibernation with host/provider PID exit, reopen and second reply, then PID exit again. The two continuous provider takes are joined; sending before wake completes is not covered.

hibernate-full-journey-claude-codex.mp4

@kvnloo

kvnloo commented Oct 1, 2026

Copy link
Copy Markdown

One lifecycle edge looks worth covering before merge: the view lease is only 30s, the daemon sweep is also 30s, and the renderer renewal is a chained window.setInterval(..., 10_000) in SessionView.

AO does not set Electron backgroundThrottling: false. Chromium background pages can substantially throttle timer wakeups, so a Chat view that is still mounted/selected can miss the 30s lease merely because the AO window is minimized/backgrounded.

That permits:

  1. Chat stays open; no React cleanup sends active:false.
  2. renderer renewal is delayed past chatViewLease.
  3. HibernateIdleChats expires the still-real view and hibernates the provider.
  4. the later heartbeat/foreground wake registers the same view again and resumes the provider.

So “view closed” can become “browser timer was suspended,” causing provider-process churn/native resume while the user never actually left Chat.

I would avoid solving this by globally disabling Chromium throttling. A stronger contract would make view ownership come from a non-throttled Electron/main lifecycle signal, or otherwise make crash-expiry distinguishable from normal background throttling. At minimum the lease should tolerate the browser’s worst-case renewal cadence.

A regression with the Chat component still mounted, renewal paused for >30s, and the hibernation sweep running would make this boundary explicit.

Checked against head 19cca8b5ffa92543f6157b2a72e9144195b79f08.

@i-trytoohard

Copy link
Copy Markdown
Collaborator

Hibernation came up as Dhruv Sharma's committed next work on the Oct 2 call: "as you move out of a session, if the session is idle, it will hibernate. Once you come back to your session, before even you start typing, you just click on the session, then the session wakes up" (30:36).

prateek flagged the risk this PR should design against: "we show an agent to be idle even if it has subagents that are currently working... If our activity detection is wrong and there's actually work happening in the background, hibernation is going to kill that work" (31:08). Dhruv agreed: fix subagent activity detection first, hibernation proceeds after.

Synced from the Oct 2 call: https://discord.com/channels/1476302178913357958/1555642689368891463
Match: semantic, 0.85

@illegalcall

Copy link
Copy Markdown
Collaborator Author

Claude Code before/after in the macOS Electron dev build (Developer Mode on). After an interrupted turn and leaving Chat, the old build kept host PID 66753 alive for over 50 seconds. The changed build stopped PID 62880; reopening started PID 64348, Claude recalled FALCON-73, and leaving Chat stopped it again.

pr6087-claude-before-after.mp4

@illegalcall

Copy link
Copy Markdown
Collaborator Author

Local E2E after 5b58b84 (macOS, isolated Electron dev build, Developer Mode on):

  • Claude ACP: replied, hibernated with host/provider processes exited, reopened with saved history, and recovered from a forced wake failure with the draft preserved.
  • Codex app-server: replied, hibernated with no chat process left, reopened, and accepted a message sent while wake was blocked; it delivered after the host resumed without showing queue or wake details.
  • Focused checks: backend chat/storage tests passed; 178 renderer chat tests passed.
  • Process evidence: hibernated sessions had no process under the isolated data directory; reopening created a new host (for example PID 21928; wake-blocked host PID 33914).

Recording of the isolated dev app:
https://github.com/user-attachments/assets/a5e37160-9141-4d78-9ef3-f7e93223085b

@illegalcall
illegalcall force-pushed the codex/chat-hibernation branch from 5b58b84 to 6179f08 Compare October 6, 2026 12:13
@illegalcall
illegalcall force-pushed the codex/chat-hibernation branch from 6179f08 to 1cdae0c Compare October 6, 2026 12:17
@illegalcall

Copy link
Copy Markdown
Collaborator Author

Short diagnostics demo (macOS, Developer Mode on)

  1. Active: Codex, its chat host, and MCP processes are visible with PIDs.
  2. Hibernated: after leaving the Codex Chat, about 11 seconds later the Codex row disappears because those processes exited.
  3. Woken: opening the chat recreates the row with new PIDs.

The attached video is 26 seconds and labels each phase. The screenshot shows the same three states side by side.

hibernation-diagnostics-demo-annotated.mp4
hibernation-diagnostics-evidence

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/daemon Go daemon, process lifecycle, and backend control plane. enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants