Skip to content

read_code_session: a Claude Code session URL should read like a share link #338

Description

@bdelanghe

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.shclaude-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

  • Probe whether list_events / an equivalent transcript read exists on any surface reachable from a session, and record the result either way
  • If it exists: read_code_session verb on bounded-verbs, matching read_session's pagination and modes, plus a test pinning its refusal sentence
  • If it does not: record the refusal in docs/handoffs/chat-relay.md next to the measured 403 table above, so the next session does not re-derive it
  • Either way: claude/context.md gains 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).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions