https://claude.ai/code/session_015MHtz7BxTVDRuvvG5o7rGi should be as readable as a claude.ai/share/… link is today via read_chat. It is not, and #337's dogfood is the proof: a child session completed its work and the session that launched it could not retrieve a single sentence of the result.
read_chat reads shared chats. read_session reads local ones off ~/.claude/projects. A Code session in another container is neither, and that is the whole missing leg.
Measured, 2026-09-01
Every direct read path, from a session with the full claude-code-remote MCP surface attached:
| path |
result |
WebFetch https://claude.ai/code/session_015MHtz7BxTVDRuvvG5o7rGi |
403 (only claude.ai/code/artifact/{uuid} is fetchable) |
WebFetch claude.ai/api/claude_code/sessions/{id} |
403 |
WebFetch claude.ai/api/sessions/{id}/events |
403 |
WebFetch claude.ai/api/claude_code/session/{id}/events |
403 |
get_session({session_id}) |
record only — title, status, timestamps, usage, post_turn_summary. No turns. |
ToolSearch select:…__list_events |
No matching deferred tools found |
ToolSearch select:…__send_message |
No matching deferred tools found |
ListAgents |
No reachable agents — a cloud session is a different container |
ListMcpResourcesTool |
GitHub UI resources only; no transcript resource |
read_session({session_id}) |
resolves against local disk; another container's disk is not on it |
Note the shape of get_session's own reply envelope: it is labelled "Another Claude session's record, transcript events, or run log (JSON)". The envelope for transcript-bearing reads already exists on this surface. Nothing on this surface fills it.
And create_session's own tool description says: "Combine with send_message for fan-out orchestration: spawn a sibling, send it a task, poll list_events for the result." Both named tools are absent. The documented orchestration loop cannot be closed.
The gap is directional
We can push into another live session — create_trigger with persistent_session_id delivers a prompt and wakes it. We cannot pull. Push-only plus a bare session with no out-channel (#337, measurement 6) means work happens and the result is stranded in a transcript nobody can open.
Two candidate doors
(a) Surface the platform read — preferred. list_events (or any transcript read) on the claude-code-remote MCP, authenticated as the account that already owns the session. No new credential, no new tier, nothing held anywhere. read_code_session on bounded-verbs then becomes what read_session already is: a thin, paginating adapter over an audited underlying reader, same transcript/graph modes, same limit/offset contract, feeding the same toolpath Graph. This is a vendor-surface ask, not something we can build — so the honest first step is a probe and a request, not an implementation.
(b) A relay tier holding a credential. The chat-fetch.sh → claude-relay shape, extended to Code session URLs. This puts a long-lived credential behind a door and reads a surface the vendor has not published — the same ToS-gray class we deliberately deferred for private un-shared chats in .github-private#835 Phase 2. It should stay deferred for exactly the same reason, and it should be deferred by the same decision, not drifted into because (a) was slow.
Recommendation
Do (a): probe for the tool, ask for it, and record the refusal or the grant. Do not do (b) as a workaround.
In the meantime the buildable half is the other direction — give a spawned session a channel out so a push-only world still returns answers (#337's fix 2). That needs no vendor surface at all.
Scope of this issue
Sibling of #337. Related: #325, #326 (discoverability), .github-private#835 (private-chat Phase 2, and the ToS line this issue must not cross).
https://claude.ai/code/session_015MHtz7BxTVDRuvvG5o7rGishould be as readable as aclaude.ai/share/…link is today viaread_chat. It is not, and #337's dogfood is the proof: a child session completed its work and the session that launched it could not retrieve a single sentence of the result.read_chatreads shared chats.read_sessionreads local ones off~/.claude/projects. A Code session in another container is neither, and that is the whole missing leg.Measured, 2026-09-01
Every direct read path, from a session with the full claude-code-remote MCP surface attached:
WebFetch https://claude.ai/code/session_015MHtz7BxTVDRuvvG5o7rGiclaude.ai/code/artifact/{uuid}is fetchable)WebFetch claude.ai/api/claude_code/sessions/{id}WebFetch claude.ai/api/sessions/{id}/eventsWebFetch claude.ai/api/claude_code/session/{id}/eventsget_session({session_id})post_turn_summary. No turns.ToolSearch select:…__list_eventsNo matching deferred tools foundToolSearch select:…__send_messageNo matching deferred tools foundListAgentsNo reachable agents— a cloud session is a different containerListMcpResourcesToolread_session({session_id})Note the shape of
get_session's own reply envelope: it is labelled "Another Claude session's record, transcript events, or run log (JSON)". The envelope for transcript-bearing reads already exists on this surface. Nothing on this surface fills it.And
create_session's own tool description says: "Combine withsend_messagefor fan-out orchestration: spawn a sibling, send it a task, polllist_eventsfor the result." Both named tools are absent. The documented orchestration loop cannot be closed.The gap is directional
We can push into another live session —
create_triggerwithpersistent_session_iddelivers a prompt and wakes it. We cannot pull. Push-only plus a bare session with no out-channel (#337, measurement 6) means work happens and the result is stranded in a transcript nobody can open.Two candidate doors
(a) Surface the platform read — preferred.
list_events(or any transcript read) on the claude-code-remote MCP, authenticated as the account that already owns the session. No new credential, no new tier, nothing held anywhere.read_code_sessiononbounded-verbsthen becomes whatread_sessionalready is: a thin, paginating adapter over an audited underlying reader, sametranscript/graphmodes, samelimit/offsetcontract, feeding the same toolpath Graph. This is a vendor-surface ask, not something we can build — so the honest first step is a probe and a request, not an implementation.(b) A relay tier holding a credential. The
chat-fetch.sh→claude-relayshape, extended to Code session URLs. This puts a long-lived credential behind a door and reads a surface the vendor has not published — the same ToS-gray class we deliberately deferred for private un-shared chats in.github-private#835Phase 2. It should stay deferred for exactly the same reason, and it should be deferred by the same decision, not drifted into because (a) was slow.Recommendation
Do (a): probe for the tool, ask for it, and record the refusal or the grant. Do not do (b) as a workaround.
In the meantime the buildable half is the other direction — give a spawned session a channel out so a push-only world still returns answers (#337's fix 2). That needs no vendor surface at all.
Scope of this issue
list_events/ an equivalent transcript read exists on any surface reachable from a session, and record the result either wayread_code_sessionverb onbounded-verbs, matchingread_session's pagination and modes, plus a test pinning its refusal sentencedocs/handoffs/chat-relay.mdnext to the measured 403 table above, so the next session does not re-derive itclaude/context.mdgains a bullet for Code session URLs, so a session reaches for the verb instead of inventing a fetch — the Org verb MCP server: expose read_chat (the relay) as a session tool via .mcp.json + register-mcp.mjs #326 lesson (a blind agent invented a bot-gate bypass across six dead ends rather than find the tool that existed)Sibling of #337. Related: #325, #326 (discoverability),
.github-private#835(private-chat Phase 2, and the ToS line this issue must not cross).