Opt-in Claude Code identity injection for OAuth subscription tokens (#74) - #75
Merged
Merged
Conversation
Anthropic gates premium models (Sonnet/Opus) behind subscription/OAuth tokens (sk-ant-oat*) unless the request leads with the official Claude Code identity system block. The real client always sends it; raw API/SDK callers omit it and get a bare rate_limit_error on those models while Haiku works. Add NADIRCLAW_CLAUDE_CODE_IDENTITY (default off). When enabled, /v1/messages and the OAuth completion path prepend "You are Claude Code, Anthropic's official CLI for Claude." as the first system block — only for Bearer/OAuth tokens, only when not already present, preserving any caller-supplied system prompt after it. Recorded as claude_code_identity on the request log. Also fix the OAuth completion path forwarding role:"system" messages inside the messages array (Anthropic requires system as a top-level field); system/developer turns are now collected into the top-level system field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the opt-in Claude Code identity injection flag floated in #74. After v0.21.0 fixed the credential path, the reporter (@ThunderEagle) retested and confirmed: Haiku works, but Sonnet/Opus still return an immediate
rate_limit_errorthrough bothnadirclaw testand a directPOST /v1/messages. Haiku-OK-but-premium-gated on the same subscription token is the classic signature of Anthropic gating premium models behind the official Claude Code identity — the real client always leads its requests with a fixed identitysystemblock; raw API/SDK callers omit it.What this does
New env flag
NADIRCLAW_CLAUDE_CODE_IDENTITY=1(default off). When enabled, NadirClaw prependsas the first
systemblock on outgoing Anthropic requests, on both surfaces:/v1/messages(the Anthropic-native path Claude Code + the reporter use)/v1/chat/completionsGuard rails:
sk-ant-oat*tokens. No effect onsk-ant-api*API keys (those usex-api-key).systemprompt is preserved, appended after the identity block;systemis normalized to Anthropic's block-array form.claude_code_identityon the request log.Drive-by fix
The direct Anthropic OAuth path in
/v1/chat/completionswas forwardingrole:"system"messages inside themessagesarray, which Anthropic's/v1/messagesAPI rejects (system must be a top-level field). System/developer turns are now collected into the top-levelsystemfield before forwarding.Testing
TestClaudeCodeIdentityInjectionunit tests for the helper (no-system / string / block-array / already-present / noop cases).test_server.py,test_oauth.py,test_tool_calling.py,test_streaming_fallback.py,test_thinking_passthrough.pypass (91 tests).For the reporter to try
If Sonnet/Opus start returning completions with the flag on, this was the cause. If they still
rate_limit_error, that points to plan-tier model-access gating (Pro vs Max) on the subscription itself rather than anything actionable in NadirClaw.Refs #74 — keeping the issue open until the reporter confirms the flag resolves the gating (or rules it out as plan-tier).
🤖 Generated with Claude Code