Repository navigation
Description
Anthropic third-party gate classifies OpenCode as a third-party app on the claude-code provider (env-instruction fingerprint)
Provider: claude-code (anomalyco#6117 native wire emulation) · Evidence: fleet laptop, 2026-11-06, deployed binary 2.0.30+1add729, Claude Code CLI credential (subscription OAuth).
Symptom
Every real OpenCode session request through the claude-code provider is refused by Anthropic:
HTTP 400 invalid_request_error
"Third-party apps now draw from your extra usage, not your plan limits. Add more at claude.ai/settings/usage and keep going."
while the SAME credential succeeds for: the real claude CLI, minimal prompts in the provider's exact wire shape, and even captured OpenCode requests with one system-prompt line removed (below). Title-generation requests (no env instruction) pass; main session requests fail.
Isolation (all against POST https://api.anthropic.com/v1/messages, provider's captured wire shape)
Wire capture of the deployed binary (local forwarding proxy) showed the main session request carries system blocks: [0] claude-code identity, [1] OpenCode harness prompt, [2] model info, [3] Code Mode catalog + skills + date + <env> block, [4] worktree note, [5] session note. Bisecting the captured body against the live API:
- Dropping block [3] → 200. Dropping block [1] instead → still 400.
- Within block [3], the sole load-bearing trigger is the environment instruction emitted by
packages/core/src/instructions/builtins.ts:43:
Is directory a git repo: yes|no
in the<env>block that followsToday's date: …/ "Here is some useful information about the environment you are running in:" /Working directory:/Workspace root folder:. - Full captured body with ONLY that one line removed → 200, correct reply text. Same body with the value flipped (
no→yesoryes→no) → still 400. Every other env line (Working directory, Workspace root folder, Platform, the /tmp guidance line) individually passes; the git-repo line alone or in pairs passes — it fires only in the complete env block, i.e. Anthropic's classifier fingerprints the env block by that anchor line. - A Claude-Code-shaped prompt (large system prompt + real tool definitions) in the identical wire shape → 200. The gate is content classification, not headers/UA/betas (swapping
User-Agentbetweenopencode/…andclaude-cli/2.1.306changes nothing).
Reading
Anthropic's third-party detection for subscription OAuth keys on the harness's own env instruction: any client whose system prompt contains OpenCode's <env> block is classified "third-party app" and billed to extra usage (which this account does not have funded) instead of plan limits. The native claude-code emulation reproduces the CLI's wire faithfully — the request is rejected because of what OUR harness puts in the prompt, not because of the provider's protocol shape.
Options
- Per-provider instruction shaping: when the target provider is claude-code, omit (or rephrase) the
Is directory a git repoline — or the whole<env>block — from builtin instructions. Verified sufficient at the API level (removal → 200 with the rest of the harness prompt, Code Mode catalog, and tools intact). Cost: the model loses one env fact on this provider only. - Fund extra usage at claude.ai/settings/usage (account-side; Drew's call, changes billing for ALL third-party-classified traffic).
- Accept the provider as title-gen/small-prompt-only — not viable; main sessions are the point.
Option 1 looks like a one-line change in builtins.ts gated on provider, or an instruction-layer filter in the session runner for the claude-code provider id. Filing for the design call; the API-level fix is proven.
Activity
Merge pull request #1826 from developing-today-forks/fix/1819-claude-…
dezren39 commentedon Nov 6, 2026
Fixed by #1826 — MERGED to main as
22c0a6ddbee19878e8e51bde432e995f75ccdd2a.Shape: route-scoped strip in the Claude Code Messages protocol (
packages/ai/src/protocols/claude-code-messages.ts): system parts have the whole line^\s*Is directory a git repo: (yes|no)\s*$removed before the body is lowered. The corecore/environmentbuiltin is unchanged and every other provider keeps the full env block — the omission exists only on the claude-code route, next to the identity-block prepend that already shapes system parts there.Verification:
claude-code.test.ts11/11 pass (4 new tests; oracle = this issue's live-API bisection — compiled env block exact-match minus the line for both values, byte-identical passthrough when absent, scope proof against the API-key Anthropic route, generated-placement invariant test);anthropic-messages.test.ts76/76;bun run typecheckclean.Deploy: rides the developing-today/code flake pin bump to fork main
22c0a6ddbe(with the #1813 endpoint fix) on the nextnixos-rebuild switch. Until then the deployed binary (2.0.30+1add729) still fails earlier at the #1813 endpoint defect, so the gate itself is not yet reachable in production.