Skip to content

fix(claude): label Claude requests as Codemux, not the Agent SDK - #668

Open
Zeus-Deus wants to merge 1 commit into
mainfrom
fix/claude-entrypoint
Open

Zeus-Deus wants to merge 1 commit into
mainfrom
fix/claude-entrypoint

Conversation

@Zeus-Deus

Copy link
Copy Markdown
Owner

Problem

Claude Code tags every API request with CLAUDE_CODE_ENTRYPOINT. Codemux never set it. Chats therefore went out as sdk-ts, the Agent SDK default, and the claude --print helpers as sdk-cli. Requests labelled sdk-* use up a Claude subscription's 5-hour window faster: t3code measured about 1.8x more usage for the same work (pingdotgg/t3code#25597). On plans with a 5-hour limit, Codemux users hit it sooner than they would in the CLI.

When Codemux was started from inside a Claude Code session, every chat also inherited that session's label (e.g. claude-desktop) and its session variables.

Fix

Same approach as t3code (pingdotgg/t3code#28410 and #29169). The t3code maintainer reported an informal okay from Anthropic for it.

  • Every Claude process Codemux starts now runs with CLAUDE_CODE_ENTRYPOINT=codemux:
    • Sidecar (claude-env.ts): chat turns, side chats, and the model, command and usage probes. It also runs on remote devices.
    • Rust (claude_env.rs): commit messages, PR descriptions, conflict resolution, automations and utility text.
  • A value in Claude's settings.json env (user or managed) still wins. Claude Code ignores that setting for the entrypoint, so Codemux applies it itself. A relative CLAUDE_CONFIG_DIR resolves against the folder Claude runs in.
  • The variables a launching Claude Code session exports (CLAUDECODE, session id, messaging socket and token, ...) are dropped.
  • Chats still report the bundled Agent SDK version. Only the label changes.
  • Interactive claude started in a terminal is untouched.

Verification

  • Wire check. Real Claude Code 2.1.316 against a local fake API, with a throwaway config and a fake key:

    main this branch
    Chat (SDK) (external, sdk-ts, agent-sdk/0.2.114), cc_entrypoint=sdk-ts (external, codemux, agent-sdk/0.2.114), cc_entrypoint=codemux
    claude --print cc_entrypoint=sdk-cli cc_entrypoint=codemux
    Started inside a Claude session claude-desktop codemux

    The tool list and the system prompt are identical apart from the label.

  • Real app. The debug app ran as the dev instance with fake host-session variables. A real Haiku chat, started through the control socket, completed. In /proc/<pid>/environ the app and sidecar still hold the host values. The live claude child, and the model-discovery probe's claude, have CLAUDE_CODE_ENTRYPOINT=codemux, no host session variables, and SDK version 0.2.114.

  • Checks.

    • Sidecar: bun test (216 pass), tsc --noEmit and the ToS boundary check pass.
    • Rust: cargo check passes, plus 46 focused tests (claude_env, utility_ai, ai::tests, automations::executor).
  • Review. Two rounds with Claude Opus 5.5 (high) and GPT-6.1 Sol (xhigh). Both approved the final head. Their findings are fixed: the Windows managed-settings path, the relative config dir, keeping the SDK version, and test isolation.

  • Not measured here. The usage difference itself; the 1.8x figure is t3code's.


Implemented by Claude Opus 5.5 via Hermes Agent.

Claude Code tags every API request with CLAUDE_CODE_ENTRYPOINT. Codemux
left it unset, so chats went out as `sdk-ts` (the Agent SDK default) and
`claude --print` helpers as `sdk-cli`. t3code measured requests with an
`sdk-*` label draining a Claude subscription's 5-hour window about 1.8x
faster than other labels for the same work (pingdotgg/t3code#25597).

Every Claude process Codemux starts now runs with
CLAUDE_CODE_ENTRYPOINT=codemux: chat turns, side chats, model, command
and usage probes (sidecar), and commit messages, conflict resolution,
automations and utility text (Rust). A value in Claude's settings.json
`env` still wins; a relative CLAUDE_CONFIG_DIR is resolved against the
folder Claude runs in. The variables a launching Claude Code session
exports (CLAUDECODE, session id, messaging socket, ...) are dropped, so
a child never joins that session or inherits its label. Chats still
report the bundled Agent SDK version.

@mario-reviewer mario-reviewer left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of 5248cc5bd43b0049dbbae8ad711045c2a03a46a7

No actionable findings. The changes look fine.

Completed a full first pass of the diff and exact-head context, including the SDK query call sites, Rust CLI launch paths, settings precedence and relative-path handling, environment isolation, SDK-version propagation, and added tests. No prior review findings were present.

Verification was static only. No repository code was built, installed, or executed. The pinned SDK's published source was inspected to check environment propagation.

CI: changes passed; iroh-wasm was skipped. Ubuntu and Windows web checks and Rust checks were still in progress when checked. Pending CI is not a code defect.

Verdict: APPROVE

🤖 Automated review by Mario (AI). Findings may be wrong; a human makes the final call.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants