Skip to content

[Bug]: Claude threads rewrite the prompt cache on every new thread (inherited host session env, late MCP connections) #25959

Closed as not planned

Description

@634634624

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

A. Inherited environment

  1. Quit T3. From a terminal inside a Claude Code session (CLAUDECODE=1, CLAUDE_CODE_ENTRYPOINT=claude-desktop), run open -a "T3 Code (Beta)".
  2. Start two Claude threads in the same project with the same short prompt.
  3. Check the transcripts: entrypoint is claude-desktop, and each new thread writes 16k to 19k tokens of 1-hour cache.

B. MCP servers connecting late (also with a clean launch)

  1. Have at least one MCP server that connects in a second or more (a claude.ai connector is enough).
  2. Start three Claude threads with the same prompt.
  3. Compare the first user message of each transcript: the deferred-tool list differs between threads, and each thread writes about 13k to 17k tokens of cache on its first request.

Expected behavior

A new thread in the same project with the same settings reuses the cached prompt prefix. How T3 was started and how fast MCP servers connect do not change the prompt.

Actual behavior

A. The Agent SDK copies process.env, so the spawned Claude Code runs with the parent session's CLAUDE_CODE_ENTRYPOINT=claude-desktop, CLAUDECODE=1, CLAUDE_EFFORT, session id and messaging socket and token. The SDK only sets sdk-ts when the entrypoint is empty.

B. With Claude Code's default non-blocking MCP connect, which servers are connected at the first request varies, so the tool list in the prompt varies per thread.

Measured on one project, question task, Sonnet 5.5, three new threads each:

Setup Entrypoint Cache written per new thread
inherited env claude-desktop 16k to 19k each
env scrubbed sdk-ts 24.3k, 17.6k
env scrubbed + MCP_CONNECTION_NONBLOCKING=false sdk-ts 17.3k (first), then 1.7k, 1.3k

Startup context was identical in the last three threads (34,504 tokens); wall time did not grow (22 to 25 s).

Impact

Major degradation or frequent failure

Version or commit

T3 Code 0.1.2 (macOS arm64), Claude Code 2.1.310

Environment

macOS 27.0.1, Apple silicon

Logs or stack traces

From two consecutive threads, the first user message differs only in the deferred-tool list: one thread lists the mcp__claude_ai_Claude_Docs__* tools, the next lists mcp__t3-code__* tools that had not connected in the first.

Workaround

Point the Claude instance at a wrapper through providerInstances.<id>.config.binaryPath. The wrapper unsets the host-session variables when it detects them (CLAUDE_CODE_HOST_SESSION_ID or CLAUDE_CODE_DESKTOP_APP_VERSION set), resets CLAUDE_CODE_ENTRYPOINT to sdk-ts, exports MCP_CONNECTION_NONBLOCKING=false, then execs claude.

Suggested fix: build the provider env from an allowlist, or drop CLAUDECODE, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_HOST_SESSION_ID, CLAUDE_CODE_MESSAGING_*, CLAUDE_EFFORT and the other desktop-host CLAUDE_CODE_* values before spawning. For B, pass MCP_CONNECTION_NONBLOCKING=false (or wait for MCP servers before the first request), since new-thread cache reuse is worth more than a faster first token.

Part B looks related to #5605 (late MCP servers missing from SDK sessions); the cache side of it is what we measured here.

Found in real use, while benchmarking our own agents.

Written with Claude Code (Claude Opus 5.5).

Activity

  1. 634634624 commented on Oct 27, 2026

    @634634624
    Author

    Measurements

    Same machine, same day, Claude Sonnet 5.5 at low effort, Claude Code 2.1.310.

    1. Harness benchmark (n=20 per harness)

    4 coding and code-reading tasks × 5 rounds, each run a new session or thread, all 60 runs passed a hidden check. Token numbers come from the native Claude Code transcripts.

    Harness Entrypoint seen Cache write per run, median (range) Startup context Cost per passed run*
    Claude Code CLI sdk-cli 965 (0 to 2,682) 29,175 $0.040
    T3 Code, launched by an agent claude-desktop (20/20) 18,706 (18,261 to 19,886) 45,341 $0.122
    OpenBot, launched by an agent claude-desktop (20/20) 17,781 (17,093 to 19,816) 49,474 $0.126

    *Cost proxy: $2 / $10 per MTok input / output, 1-hour cache write 2×, cache read 0.1×. The repeated cache write alone is about $0.071 per run, roughly 85% of the gap between T3 and the CLI.

    2. Control without any app

    env -i HOME=… PATH=… claude -p "Reply with the single word OK." --model claude-sonnet-5-5 --effort low --output-format json, alternating plain and CLAUDE_CODE_ENTRYPOINT=claude-desktop, warm cache:

    Variant cache_read cache_write
    plain, 3 repeats 28,938 0, 0, 0
    CLAUDE_CODE_ENTRYPOINT=claude-desktop, 3 repeats 28,980 16,074, 16,071, 16,074
    MCP_CONNECTION_NONBLOCKING=false, first, then 2 repeats 11,334, then 28,939 17,605, then 0, 0

    So the inherited entrypoint alone makes every new session write ~16k tokens even with nothing else changed: the claude-desktop system prompt carries a per-session part. The MCP setting changes the prefix once and is then stable; in -p mode both variants are stable, the per-thread drift appeared only in the SDK-driven app sessions.

    3. Inside T3 after the fix

    Question task, three new threads each, T3 pointed at a wrapper (binaryPath):

    Setup Cache write per new thread
    env scrubbed only 24,298, 17,637
    env scrubbed + MCP_CONNECTION_NONBLOCKING=false 17,342 (first), then 1,701, 1,344

    Startup context was 34,504 in all three of the last threads; wall time stayed at 22 to 25 s.

    4. Environment inheritance

    CLAUDECODE=1 CLAUDE_CODE_ENTRYPOINT=claude-desktop BENCHMARK_MARK=x open -a TextEdit (and the same with a small probe app that writes its own environment to a file): all three variables show up in the launched app's environment. That is the path by which an agent-launched app gets the parent session's values.

    Not measured: OpenBot after a clean launch (only T3 was re-measured with the fix).

  2. t3dotgg commented on Nov 2, 2026

    @t3dotgg
    Member

    The large cache cost came from the inherited claude-desktop entrypoint, fixed in #28410. #29169 stops Claude from inheriting the rest of the launching session. On Claude Code 2.1.316 a late MCP server adds about 200 tokens, so we are not making the first message wait for MCP servers.

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

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions