Skip to content

RewardKit: 3 auth bugs block grading on a Claude subscription #1771

Description

@Kurry

RewardKit can't grade on a Claude subscription end to end. Three independent bugs force a subscriber onto the paid Console API key — or crash the verifier outright.

Background

  • CLAUDE_CODE_OAUTH_TOKEN (sk-ant-oat01…) authenticates on a Claude subscription (Pro/Max) — free.
  • ANTHROPIC_API_KEY (sk-ant-api03…) authenticates on the Console account — metered/paid.

These are different Anthropic orgs. The OAuth token only works as an OAuth bearer (litellm auto-detects the sk-ant-oat prefix and routes it correctly); it 401s if sent as x-api-key.

Environment: harbor-rewardkit==0.1.4, litellm 1.86.2.

What main already supports (and where it stops half-way)

Subscription grading is already partly wired in main — each bug is the point where that support stops short, not a net-new feature:

Already in main Where it stops short (the bug)
The claude-code agent judge already grades on the subscription — it shells out to the claude CLI, which inherits CLAUDE_CODE_OAUTH_TOKEN. This is the working free path today. A stray container ANTHROPIC_API_KEY silently shadows that OAuth (CLI auth precedence), breaking the working path — Console bill, or 401 crash on an invalid key. → Bug 3
litellm itself already authenticates a subscription via ANTHROPIC_AUTH_TOKEN (OAuth bearer). The litellm LLM judge never passes the OAuth token to litellm — it calls acompletion() with no api_key, so the subscription is unreachable from that judge. → Bug 1
REWARDKIT_JUDGE already globalizes judge selection (runner.py:79). There is no parallel REWARDKIT_MODEL, so a global REWARDKIT_JUDGE=claude-code silently drops the rubric's pinned model. → Bug 2

So this is finishing half-built support, not adding a new capability.


Bug 1 — litellm LLM judge ignores the subscription token

Expected: with only CLAUDE_CODE_OAUTH_TOKEN set, an anthropic/* LLM judge grades on the subscription.
Actual: it fails — judges._arun_llm_call calls litellm.acompletion(model=…) with no api_key, so litellm reads ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN from the env and never the OAuth token.

unset ANTHROPIC_API_KEY
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...     # a real subscription token
# rubric:  [judge] judge = "anthropic/claude-sonnet-4-6"
uvx --from 'harbor-rewardkit==0.1.4' rewardkit tests/
litellm.exceptions.AuthenticationError: AnthropicException - Missing Anthropic API Key -
 A call is being made to anthropic but no key is set ... Please set `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN`

Bug 2 — REWARDKIT_JUDGE=claude-code silently drops the pinned model

Expected: a rubric that pins its model survives a global judge override.
Actual: REWARDKIT_JUDGE overrides the whole [judge].judge field. When a rubric encodes its model there (judge = "anthropic/claude-opus-4-8"), overriding judge to the agent name claude-code leaves the agent's model = None, so the claude CLI runs its built-in default model — the pinned model vanishes with no error. There is no global REWARDKIT_MODEL to set the model once.

# rubric:  [judge] judge = "anthropic/claude-opus-4-8"
export REWARDKIT_JUDGE=claude-code
uvx --from 'harbor-rewardkit==0.1.4' rewardkit tests/
# → agent judge runs the claude CLI's DEFAULT model, not opus-4-8 (silent)

Bug 3 — stray ANTHROPIC_API_KEY shadows OAuth in the agent judge

Expected: the claude-code agent judge grades on the subscription via CLAUDE_CODE_OAUTH_TOKEN.
Actual: the CLI's auth precedence puts ANTHROPIC_API_KEY above CLAUDE_CODE_OAUTH_TOKEN, so a key present in the verifier container ([verifier.env]) wins: a valid key silently grades on Console (paid); an invalid key 401s and the judge crashes with no reward written.

export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
export ANTHROPIC_API_KEY=sk-ant-api03-invalid       # stray / invalid key in the container
# rubric:  [judge] judge = "claude-code"
uvx --from 'harbor-rewardkit==0.1.4' rewardkit tests/
ValueError: Agent CLI 'claude' exited with code 1:
  {"is_error":true,"api_error_status":401, ... "result":"Invalid API key · Fix external API key"}
→ RewardFileNotFoundError   (no reward.json written)

Note: this only bites when ANTHROPIC_API_KEY reaches the verifier container ([verifier.env] is an explicit allowlist). A host-only .env value is harmless; an empty value is ignored by the CLI; only a non-empty invalid key crashes, and a valid one silently bills Console.


Fix

Proposed in #1770 — resolves each path free-first behind one opt-out flag (REWARDKIT_FORCE_API_KEY=1 keeps the paid API key for bugs 1 & 3), and adds REWARDKIT_MODEL to pin the model globally. Companion to #1766 (same auth for harbor check / harbor analyze).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions