[BUG] Desktop: Remote Control never re-arms on restored sessions after app relaunch — auto-enable is gated on `isFirstTurn`, so `remoteControlAtStartup` / `ccRemoteControlDefaultEnabled` are silently ignored for every restored session

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 1 comment · opened Jul 24, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (closest: #80400 resume-from-sleep toggle state, #34255 mid-session transport drop, #80826 pref collision on first message — all different mechanisms)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

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)

maybeAutoEnableRemoteControlrcAutoEnable 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

  1. Claude Desktop on Windows, sign in, set "remoteControlAtStartup": true in ~/.claude/settings.json (and/or enable the desktop RC-by-default preference).
  2. Open a session, confirm RC is active (status shows the claude.ai/code URL).
  3. Quit and relaunch the desktop app (or wait for the updater's forced 72-hour auto-restart).
  4. 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

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗