Preflight Checklist
What's Wrong?
When Claude Desktop relaunches (most disruptively via the updater's forced restart: [updater] Auto-restarting app after update pending for 72 hours), every restored session loses Remote Control and nothing ever re-enables it — even with both opt-ins set:
"remoteControlAtStartup": true in ~/.claude/settings.json
ccRemoteControlDefaultEnabled: true desktop preference
The environment-level sessions bridge reconnects fine ([sessions-bridge] Session cse_… reconnected successfully), which makes the machine look healthy, but per-session RC stays dead until the user physically returns to the desktop and re-runs /remote-control in each session. If you relied on RC to reach the machine remotely, a forced update restart locks you out.
Timeline from main.log (Claude Desktop 1.24012.9, Windows):
14:46:40 [remote-control] bridge_state: connected ← RC healthy on session
14:49:18 [updater] Auto-restarting app after update pending for 72 hours
14:49:52 [CCD] Initialized with version 2.1.219
14:49:56 [sessions-bridge] Environment registered: env_… ← env bridge auto-reconnects
14:49:57 [sessions-bridge] Session cse_… reconnected successfully
(no [remote-control] or [rcAutoEnable] lines for any restored session)
15:00:22 Enabling remote control for session local_c330… ← only after manual /remote-control
Note the manual re-enable also mints a new session_… URL, so previously shared/bookmarked RC links die with every restart.
Root cause (from the shipped bundle)
In app.asar, the only automatic RC path is called from enqueueInitialMessage and is gated on isFirstTurn:
const { …, isFirstTurn: n, … } = e;
…
n && this.maybeAutoEnableRemoteControl(i, f)
maybeAutoEnableRemoteControl → rcAutoEnable resolver correctly consults ccRemoteControlDefaultEnabled, then settings remoteControlAtStartup, then org/GrowthBook defaults — but it can only ever run on a session's first turn ever. Restored sessions take the !isFirstTurn branch (transcript reload), so the resolver is never invoked again for the rest of the session's life, regardless of user opt-in.
There is also no external re-arm path: LocalSessions.toggleRemoteControl is renderer-only IPC, and the /^\/remote-control(\s|$)/i fast-path in message delivery doesn't help programmatic senders (cross-session messages arrive label-prefixed, so the regex can't match).
Steps to Reproduce
- Claude Desktop on Windows, sign in, set
"remoteControlAtStartup": true in ~/.claude/settings.json (and/or enable the desktop RC-by-default preference).
- Open a session, confirm RC is active (status shows the claude.ai/code URL).
- Quit and relaunch the desktop app (or wait for the updater's forced 72-hour auto-restart).
- App restores the session. Send it any message.
Expected: restored session re-arms RC automatically (settings say "at startup"), or at minimum the rcAutoEnable resolver runs again on the first turn after restore.
Actual: RC stays off forever; [rcAutoEnable] never logs a verdict for restored sessions; user must manually run /remote-control per session, at the desktop, and all previous RC URLs are invalidated.
Why the obvious fix isn't enough
Simply calling maybeAutoEnableRemoteControl on the first turn after a restore does not solve this, because RC attaches to a live query object:
if (!e.query) {
const c = "Remote Control requires an active session. Send a message first.";
return { ok:!1, error:c, reason:"no_active_session" }
}
A restored-but-paused session has no CLI process, so re-arming still waits for a message — and with RC off, that message can only come from the desktop UI. That's circular for the exact scenario this bug is about: the user is away from the machine.
Compounding it, teardown deliberately discards the state that a restore would need:
e.remoteControlEnabled = !1, e.remoteControlAutoEnabled = void 0,
e.bridgeSessionId = void 0, e.bridgeSessionUrl = void 0
Suggested fix
Persist the set of sessions that had remoteControlEnabled at shutdown, and on relaunch spin their CLI query back up and re-arm RC without waiting for a message.
This does cost process spawns at startup, which is presumably why sessions restore lazily today. Two things make it acceptable here: the set is bounded to sessions the user already had live moments earlier (not all restored sessions), and the restart is usually the app's own doing via the forced-update path. An app-initiated restart severing user-opted-in remote access is a different tradeoff from lazily restoring an idle session the user hasn't touched in days.
If a blanket re-arm is too costly, scoping it to the updater's forced-restart path alone (Auto-restarting app after update pending for 72 hours) would cover the damaging case — the app knows it is about to restart and can record what to bring back.
Environment
- Claude Desktop 1.24012.9 (Microsoft Store / MSIX), Windows 10 Pro 19045
- Bundled Claude Code CLI 2.1.219
- Also present:
ccRemoteControlDefaultEnabled: true, RC worked correctly on session creation — only the restore path is affected
Preflight Checklist
What's Wrong?
When Claude Desktop relaunches (most disruptively via the updater's forced restart:
[updater] Auto-restarting app after update pending for 72 hours), every restored session loses Remote Control and nothing ever re-enables it — even with both opt-ins set:"remoteControlAtStartup": truein~/.claude/settings.jsonccRemoteControlDefaultEnabled: truedesktop preferenceThe environment-level sessions bridge reconnects fine (
[sessions-bridge] Session cse_… reconnected successfully), which makes the machine look healthy, but per-session RC stays dead until the user physically returns to the desktop and re-runs/remote-controlin each session. If you relied on RC to reach the machine remotely, a forced update restart locks you out.Timeline from
main.log(Claude Desktop 1.24012.9, Windows):Note the manual re-enable also mints a new
session_…URL, so previously shared/bookmarked RC links die with every restart.Root cause (from the shipped bundle)
In
app.asar, the only automatic RC path is called fromenqueueInitialMessageand is gated onisFirstTurn:maybeAutoEnableRemoteControl→rcAutoEnableresolver correctly consultsccRemoteControlDefaultEnabled, then settingsremoteControlAtStartup, then org/GrowthBook defaults — but it can only ever run on a session's first turn ever. Restored sessions take the!isFirstTurnbranch (transcript reload), so the resolver is never invoked again for the rest of the session's life, regardless of user opt-in.There is also no external re-arm path:
LocalSessions.toggleRemoteControlis renderer-only IPC, and the/^\/remote-control(\s|$)/ifast-path in message delivery doesn't help programmatic senders (cross-session messages arrive label-prefixed, so the regex can't match).Steps to Reproduce
"remoteControlAtStartup": truein~/.claude/settings.json(and/or enable the desktop RC-by-default preference).Expected: restored session re-arms RC automatically (settings say "at startup"), or at minimum the
rcAutoEnableresolver runs again on the first turn after restore.Actual: RC stays off forever;
[rcAutoEnable]never logs a verdict for restored sessions; user must manually run/remote-controlper session, at the desktop, and all previous RC URLs are invalidated.Why the obvious fix isn't enough
Simply calling
maybeAutoEnableRemoteControlon the first turn after a restore does not solve this, because RC attaches to a live query object:A restored-but-paused session has no CLI process, so re-arming still waits for a message — and with RC off, that message can only come from the desktop UI. That's circular for the exact scenario this bug is about: the user is away from the machine.
Compounding it, teardown deliberately discards the state that a restore would need:
Suggested fix
Persist the set of sessions that had
remoteControlEnabledat shutdown, and on relaunch spin their CLI query back up and re-arm RC without waiting for a message.This does cost process spawns at startup, which is presumably why sessions restore lazily today. Two things make it acceptable here: the set is bounded to sessions the user already had live moments earlier (not all restored sessions), and the restart is usually the app's own doing via the forced-update path. An app-initiated restart severing user-opted-in remote access is a different tradeoff from lazily restoring an idle session the user hasn't touched in days.
If a blanket re-arm is too costly, scoping it to the updater's forced-restart path alone (
Auto-restarting app after update pending for 72 hours) would cover the damaging case — the app knows it is about to restart and can record what to bring back.Environment
ccRemoteControlDefaultEnabled: true, RC worked correctly on session creation — only the restore path is affected