[BUG] Remote Control sessions are hidden from the local /resume picker (filtered as entrypoint=sdk-cli)
Preflight Checklist
- [x] I have searched existing issues and this is not a duplicate
- [x] This is a bug report, not a feature request
What's Wrong?
Conversations started through claude remote-control (claude rc) run on the local machine and are persisted to the local project transcript directory, but the local claude --resume picker never lists them.
Root cause (from the bundled source of 2.1.274): claude rc spawns each conversation as a headless child
claude --print --sdk-url https://api.anthropic.com/v1/code/sessions/<id> --session-id <id> --input-format stream-json --output-format stream-json …
which sets CLAUDE_CODE_ENTRYPOINT=sdk-cli, so every transcript record carries "entrypoint":"sdk-cli", "promptSource":"sdk". The picker's exclusion predicate skips any session whose transcript head has an SDK entrypoint:
var fwt = new Set(["sdk-cli", "sdk-ts", "sdk-py"]);
function cto(e, n) {
let t = ele(e, "entrypoint") ?? I1(n, "entrypoint");
if (t && fwt.has(t)) return !0; // ← Remote Control sessions hit this
let r = e.split("\n").find(a => a.includes('"parentUuid":')) ?? e,
i = ele(r, "sessionKind");
return i === "daemon" || i === "daemon-worker";
}
The filter presumably targets scripted claude -p / SDK runs. Remote Control reuses the same headless transport, but these are human, interactive conversations the user reasonably expects to find locally.
What Should Happen?
The Remote Control conversation is listed in claude --resume (run from the same project directory) like any other local session — ideally with a "Remote Control" badge, matching how ListAgents already labels them.
Suggested fix: distinguish bridge-spawned sessions from generic SDK runs — record a distinct entrypoint (e.g. remote-control) or a sessionKind for them and exempt it in the filter, or tag the transcript with the bridge session id (a ~/.claude/bridge-spawn/<id> directory already exists per conversation).
Error Messages/Logs
Debug log string emitted by the picker: filtered from /resume: entrypoint=sdk-cli
Transcript head of the hidden session:
{"type":"ai-title","aiTitle":"Hello world","sessionId":"5981c850-…"}
… "type":"user","promptSource":"sdk","userType":"external","entrypoint":"sdk-cli","cwd":"/home/ivan/code/dough-tools","version":"2.1.274" …
Workaround: claude --resume <uuid> with the uuid taken from ~/.claude/projects/<slug>/ works, so the transcript is valid and resumable.
Steps to Reproduce
- In a project directory run
claude rc, then start a conversation with that machine from claude.ai/code. - Send a message so
~/.claude/projects/<slug>/<uuid>.jsonlis created. - In another terminal,
cdto the same project directory and runclaude --resume. - The conversation is absent from the list;
claude --resume <uuid>opens it fine.
Claude Model
Opus 5
Is this a regression?
Not sure
Claude Code Version
2.1.274 (native build)
Platform
CLI (terminal)
Operating System
Linux (Ubuntu, kernel 6.8)
Terminal/Shell
bash
3 Comments
Same on macOS — and with the Desktop app there is no workaround at all.
Setup: macOS (Apple silicon), Claude Code CLI 2.1.274 (npm), Claude Desktop 2.110.1 (bundled Claude Code 2.1.271).
claude remote-controlruns as a launchd agent; sessions are started from the mobile app and from the Desktop app on another machine.Confirming the report, plus three additions.
1. The workaround works, so the transcript itself is fine.
claude --resume <uuid> --fork-session -p "…"on a session the picker hides returned normally. Only the listing hides it.2. The Desktop app ships the same predicate, so GUI-only users have no path.
In
Claude.app/Contents/Resources/app.asar:The Desktop app's
/resumeis declared withargumentHint: "[search]"and searches that already-filtered list, so passing the uuid doesn't help either. Net effect for someone who only uses the Desktop app and the mobile app: a conversation started from the phone can never be continued as a Desktop-hosted session. The Desktop sidebar does show it under the Remote Control device group, but the app is only a viewer there, so none of the app-hosted affordances (browser panel, Terminal, Open in, Continue in) are available for it.3.
sessionKind: daemon/daemon-workerhits the same predicate, so this is not only about thesdk-clientrypoint.Why promotion looks cheap: a Desktop local-session record (
~/Library/Application Support/Claude/claude-code-sessions/<account>/<org>/local_<uuid>.json) is essentially{sessionId, cliSessionId, cwd, title, model, effort, permissionMode, …}, and the app resumes whatevercliSessionIdpoints at. The transcript is already on the same machine, so ending the server-hosted process and re-opening that transcript as an app-hosted session appears to be all that is missing. Live tool/subagent state would be lost, the same tradeoff--teleportalready makes.Requests, in order of usefulness:
remote-control) or a bridge marker, so these stop being classified as generic SDK runs./resumelist with a badge.claude remote-controlon this machine.Related: #94369, #94546, #95073.
Still present in 2.1.278 (native build, Linux/WSL2), and I can add one detail that I think matters for how this gets fixed: the filter is permanent, because it only reads the transcript head.
Reproduced today with two Remote Control sessions started from the mobile app (
claude remote-controlrunning locally, default same-dir spawn). Both are written to~/.claude/projects/<slug>/with"entrypoint":"sdk-cli"on the first record, and the picker's own debug log shows the exclusion:Two things that do not help, verified:
/renamefrom the remote client. On the second session I ran/rename <title>from the phone before closing. The{"type":"custom-title","customTitle":"…"}record is correctly persisted in the local.jsonl, but since the session never reaches the list, the title is never shown andclaude --resume "<title>"finds nothing. So the "name your session so you can find it later" advice does not work for Remote Control sessions.claude --resume <uuid>on that same session and kept working in it interactively from the terminal. The transcript now has 68 records with"entrypoint":"cli"appended after the 191sdk-cliones — it is, by any reasonable definition, a local interactive session. The picker still hides it:This matches the predicate quoted above (
ele(e, "entrypoint")on the head chunk): whatever entrypoint the session started with decides its visibility forever. A session that was born on the phone and lived the rest of its life in the terminal is never listed.Practical consequence for the "start on mobile, continue at the desk" flow: the only way to get back to the conversation is to know the UUID, and nothing in the product prints it (
claude.ai/codeshows a differentsession_01…id;~/.claude/sessions/<pid>.jsonis deleted on exit; thebridge-pointer.jsonin the project dir holds the bridgesession_…id, not the local UUID).Any of the fixes proposed above would do (distinct entrypoint/sessionKind for bridge-spawned sessions, or honoring a later
clientrypoint /custom-titleas a signal that this is a human session). Happy to test a build.Still reproduces on 2.1.285. The filter is unchanged (
new Set(["sdk-cli","sdk-ts","sdk-py"])). My rc session's transcript starts with"entrypoint":"sdk-cli"records and does not appear inclaude -r.