Skip to content

[Bug]: ocx claude uses caller account despite enabled Anthropic account pool #3749

Closed

Description

@daehwanahn

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:

  1. Store two Anthropic OAuth accounts, A and B, in OpenCodex.
  2. Enable the Anthropic account pool, use quota, set the threshold to 80, and select the five-hour window.
  3. Select Account A as Active in OpenCodex. The dashboard showed both accounts below the threshold when diagnosing the behavior.
  4. Leave the local Claude Code subscription login on Account B.
  5. Leave the entire claudeCode configuration object absent, as in the affected installation.
  6. 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.txt

The 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:

Consequently, changing quota versus fill-first does not affect a request already taking this native branch.

Related reports reviewed:

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

  1. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    cliCLI, config inject, packaging flags
    toolstool_calls, MCP, web-search / sidecar tools
    on Sep 6, 2026
  2. lidge-jun commented on Sep 6, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 48 / 80

    이 이슈는 ocx claude -p로 진짜 Claude 모델을 돌릴 때, 대시보드에서 Anthropic 계정 풀을 켜고 Active를 Account A로 두어도 요청이 Claude Code 쪽 호출자 로그인(Account B)으로 나가 anthropic-native로만 기록된다는 보고입니다. 보고 버전은 설치된 @bitkyc08/opencodex 2.42.0이고, 지금 점검 기준 dev는 HEAD 00d0cc140(패키지 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 스냅샷 순서는 #3743 task-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.ts wantsNativePassthrough - 풀 enabled 미검사. 자격·진짜 모델·alias만 봄
    라인 719-720 (claude-messages.ts) - 조건 맞으면 번역 전에 anthropicNativePassthrough 반환. provider=anthropic-native
    경로/심볼 - anthropicNativePassthrough - 호출자 헤더를 Anthropic으로 전달. 풀 스냅샷 미사용
    경로/심볼 - src/oauth/anthropic-routing.ts resolveAnthropicAccountForSession / isAnthropicAccountPoolEnabled - 번역 Responses·OAuth 경로에서만 Active/strategy 적용
    경로/심볼 - src/server/responses/core.ts Anthropic pool 분기 - native Messages 가지와 분리
    경로 - docs-site/.../guides/claude-code.md 계정 풀 절 vs native passthrough 절 - 풀 예외가 풀 UI/가이드 앞단에 안 보임
    경로/심볼 - 설정 claudeCode.nativePassthrough: false - 지금 우회로(번역+풀). #3719 부작용 가능. 보고자는 미검증

    메인테이너의 판단이 필요한 지점

    • 풀이 켜져 있을 때 진짜 Claude도 풀 계정으로 보낼지(캐시·구독 정체성 깨짐), 아니면 네이티브를 유지하고 풀 UI·런치·요청 로그에 “풀 미적용”만 분명히 할지
    • 적용 시 민감한 id 없이 어떤 라벨로 “선택된 계정”을 보여 줄지
    • release-244 밖 후속 이슈로 둘지, dashboard/usage 칸과 묶을지
    • nativePassthrough: false를 임시 완화로 문서화할지(#3719 non-goal과 충돌 주의)

    너의 추천
    닫지 말고 열어 두세요. 코드상 재현 경로는 HEAD에서도 성립합니다. 당장 트레인을 막지 않으니, 1) 풀 가이드·대시보드·ocx claude 진단에 “네이티브면 풀 미적용”을 먼저 적고, 2) 풀이 진짜 Claude를 지배하게 만들지는 별 설계 이슈로 쪼개세요. #3719 재설계나 라이브 Anthropic 실험은 이 이슈에 묶지 마세요. 중복 close 대상 아님.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 6, 2026

    @lidge-jun
    Owner

    u should use anthropic ocx model in model picker thats native pass through

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

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingcliCLI, config inject, packaging flagstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions