Repository navigation
[Bug]: ocx claude uses caller account despite enabled Anthropic account pool #3749
Description
Client or integration
Claude Code, launched through ocx claude -p against a local OpenCodex proxy.
Area
Authentication and account pool
Summary
With the Anthropic OAuth account pool enabled and Account A displayed as Active, a successful ocx claude -p request for a genuine Claude model used the Claude Code login belonging to Account B. OpenCodex recorded the request as anthropic-native.
I understand that native passthrough intentionally preserves the caller's subscription credentials. The problem is the interaction with an explicitly enabled account pool: the dashboard's Active account and quota strategy do not govern these requests, without making that exception apparent in the pool controls. Users cannot rely on the pool settings to control which account their OCX-launched Claude work consumes.
The account-pool section of the affected version's guide says, "By default every request uses the active account only," then describes the enabled pool's selection and failover behavior. That section does not state the native-passthrough exception; the native authentication behavior is explained separately later in the guide.
Expected outcomes:
- Provide a clearly supported way for the enabled pool to govern genuine-Claude calls launched through OCX, with the effective selected account verifiable through a non-sensitive account label.
- When caller-native authentication is used instead, disclose at the pool controls and launch/request diagnostics that pool selection does not apply. Keep intentional native caller authentication available.
The exact configuration or UI design is a maintainer decision. These are requested outcomes, not claims that a changed routing path has already been validated.
Reproduction
Observed configuration and execution:
- Store two Anthropic OAuth accounts, A and B, in OpenCodex.
- Enable the Anthropic account pool, use
quota, set the threshold to 80, and select the five-hour window. - Select Account A as Active in OpenCodex. The dashboard showed both accounts below the threshold when diagnosing the behavior.
- Leave the local Claude Code subscription login on Account B.
- Leave the entire
claudeCodeconfiguration object absent, as in the affected installation. - Start a new nonpersistent Claude Code invocation through the OCX launcher using a real Claude model, with no model-map or gateway alias.
The actual invocation had the following shape. Only local filenames have been replaced with generic names; empty-mcp.json contained {"mcpServers":{}}.
type input.txt | call ocx.cmd claude -p --model "claude-fable-5-1[1m]" --fallback-model "claude-fable-5-1[1m]" --effort xhigh --tools "" --strict-mcp-config --mcp-config empty-mcp.json --setting-sources "" --output-format json --no-session-persistence > result.json 2> stderr.txtThe original input was a private review request and is not attached. A short synthetic input can be used for a prospective reproduction, but that reduced-input reproduction has not been run. This report is based on an existing successful invocation and subsequent source/configuration inspection, not a new controlled A/B experiment.
Version
- Installed
@bitkyc08/opencodex: 2.42.0 - Claude Code: 2.1.261
- Behavior on newer releases has not been tested.
Operating system
Windows, version 25H2, build 26200.8875. Local proxy on loopback.
Provider and model
Configured provider: anthropic, adapter anthropic, authMode: "oauth".
CLI model: claude-fable-5-1[1m].
OpenCodex logged model: claude-fable-5-1.
OpenCodex logged provider: anthropic-native.
Logs or error output
The saved launcher script confirms that it invoked ocx.cmd claude -p. This was not an unwrapped direct Claude CLI call.
The saved CLI result reported is_error: false, num_turns: 1, and duration_ms: 379465. Two matching OCX usage records shared the same conversation key:
[
{"provider":"anthropic-native","model":"claude-fable-5-1","durationMs":7649},
{"provider":"anthropic-native","model":"claude-fable-5-1","durationMs":379319}
]For account attribution, a private local check reconstructed the conversation hash from the saved CLI session ID and the Claude Code metadata identity belonging to Account B; it matched those OCX records. The identity values and identifiers are omitted here. This establishes the caller identity used in the native route; it is not an independent measurement of subscription quota deltas or billed cost.
Screenshots and supporting files
Source-level explanation in the affected release:
- Native eligibility checks the native-passthrough setting, genuine model, caller credential, and unchanged model resolution. It does not check
anthropicAccountPool.enabled. - The Messages handler returns through native passthrough first.
- Managed Anthropic pool selection happens later in the translated Responses path.
Consequently, changing quota versus fill-first does not affect a request already taking this native branch.
Related reports reviewed:
- P0: stop Claude gateway quota burn and cache churn #2939 discusses native authentication and caching, including the maintainer's explanation that native passthrough preserves caller credentials.
- Bug: preserve Anthropic thinking replay through proxy-auth translation and clarify prompt-cache behavior #3719 tracks thinking replay/cache behavior on the translated route. That is a separate concern when considering
nativePassthrough: false; disabling passthrough has not been tested as a remedy in this report. - [UX] Background helper 기본값이 Sonnet native 호출로 떨어질 때 안내가 없습니다 #331 concerns unexpected native background-helper calls. This report concerns an explicitly requested main Claude model and account-pool selection.
I searched open and closed issues/PRs for nativePassthrough, anthropic-native, native passthrough plus pool, and Claude account pool, and did not find an issue covering this exact interaction.
Redacted configuration
Relevant excerpt only:
{
"anthropicAccountPool": {
"enabled": true,
"autoSwitchThreshold": 80,
"strategy": "quota",
"stickyLimit": 1,
"quotaWindow": "five-hour"
}
}The claudeCode object is absent. In this version, absence leaves native passthrough eligible: its guard disables the path only when nativePassthrough === false. No explicit native-passthrough override was configured.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Sep 6, 2026
리뷰 · 우선순위 48 / 80
이 이슈는
ocx claude -p로 진짜 Claude 모델을 돌릴 때, 대시보드에서 Anthropic 계정 풀을 켜고 Active를 Account A로 두어도 요청이 Claude Code 쪽 호출자 로그인(Account B)으로 나가anthropic-native로만 기록된다는 보고입니다. 보고 버전은 설치된@bitkyc08/opencodex2.42.0이고, 지금 점검 기준dev는 HEAD00d0cc140(패키지 2.44.0)입니다. 증상 자체는 “풀이 깨졌다”기보다 네이티브 패스스루가 풀 선택보다 먼저 끝나는 설계와 맞습니다.현재 HEAD의
src/server/claude-messages.ts에서wantsNativePassthrough()는 대략 이렇게만 봅니다.claudeCode.nativePassthrough가false가 아닌지, 모델이claude/anthropic으로 시작하는지, 요청에sk-ant-호출자 자격이 있는지, alias/modelMap이 모델을 바꾸지 않았는지, (비루프백이면) 전용 입학 헤더가 있는지.anthropicAccountPool.enabled는 조건에 없습니다. 조건이 맞으면 Messages 핸들러가 번역·Responses 경로로 가기 전에anthropicNativePassthrough()로 바로 돌아가고, 로그 provider는anthropic-native입니다. 그 함수는 호출자Authorization/x-api-key를 거의 그대로api.anthropic.com으로 넘깁니다. 그래서 풀 Active·quota/fill-first·sticky는 이 가지에 닿지 않습니다.풀 선택은 다른 길에 있습니다.
src/oauth/anthropic-routing.ts의resolveAnthropicAccountForSession()과isAnthropicAccountPoolEnabled()는, 번역된 Responses 경로에서 Anthropic OAuth를 쓸 때src/server/responses/core.ts가 계정 스냅샷을 고를 때 쓰입니다. 가이드docs-site/src/content/docs/guides/claude-code.md의 계정 풀 절은 “기본적으로 active만 쓴다 / 켜면 strategy로 고른다”고 말하고, 네이티브 패스스루 예외는 같은 절에 없고 아래 “native passthrough” 절에만 따로 있습니다. 보고자가 말한 UX 갭(풀 컨트롤을 믿었는데 호출자 구독이 청구됨)과 문서 배치가 일치합니다. 관련으로#2939(네이티브가 호출자 자격 유지),#3719(번역 경로 thinking replay — 이번 트레인 non-goal),#331(백그라운드 헬퍼 네이티브)과 겹치되, 풀이 켜진 상태에서 메인 Claude 호출의 계정 지배권을 직접 다루는 이슈는 이 건이 맞습니다.우선순위 48인 이유다. 사용자에게는 계정·할당량 체감이 큰 버그/UX 이슈이고, HEAD에서도 경로 분리는 그대로입니다. 다만 지금 release-244 스냅샷 순서는
#3743task-input(이미 HEAD) → kiro-results → opaque/combo → grok-terminal → quota-proxy → usage-source → dashboard → release입니다. Anthropic 풀·네이티브 지배권은 그 칸이 아니고,#3719재설계·새 프로바이더·라이브 Kiro도 non-goal입니다. 그래서 트레인 점프 머지 대상이 아니라 문서/진단 먼저 + 동작 변경은 유지보수 판단 후 별 슬롯이 맞습니다. types.ts/config.ts 대분할로 무효화되는 PR도 아니고, 닫을 중복도 아닙니다.경로/심볼 -
src/server/claude-messages.tswantsNativePassthrough- 풀 enabled 미검사. 자격·진짜 모델·alias만 봄라인 719-720 (
claude-messages.ts) - 조건 맞으면 번역 전에anthropicNativePassthrough반환. provider=anthropic-native경로/심볼 -
anthropicNativePassthrough- 호출자 헤더를 Anthropic으로 전달. 풀 스냅샷 미사용경로/심볼 -
src/oauth/anthropic-routing.tsresolveAnthropicAccountForSession/isAnthropicAccountPoolEnabled- 번역 Responses·OAuth 경로에서만 Active/strategy 적용경로/심볼 -
src/server/responses/core.tsAnthropic pool 분기 - native Messages 가지와 분리경로 -
docs-site/.../guides/claude-code.md계정 풀 절 vs native passthrough 절 - 풀 예외가 풀 UI/가이드 앞단에 안 보임경로/심볼 - 설정
claudeCode.nativePassthrough: false- 지금 우회로(번역+풀).#3719부작용 가능. 보고자는 미검증메인테이너의 판단이 필요한 지점
nativePassthrough: false를 임시 완화로 문서화할지(#3719non-goal과 충돌 주의)너의 추천
닫지 말고 열어 두세요. 코드상 재현 경로는 HEAD에서도 성립합니다. 당장 트레인을 막지 않으니, 1) 풀 가이드·대시보드·
ocx claude진단에 “네이티브면 풀 미적용”을 먼저 적고, 2) 풀이 진짜 Claude를 지배하게 만들지는 별 설계 이슈로 쪼개세요.#3719재설계나 라이브 Anthropic 실험은 이 이슈에 묶지 마세요. 중복 close 대상 아님.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 6, 2026
u should use anthropic ocx model in model picker thats native pass through