TL;DR
Anthropic's server-side detection of third-party clients (OpenCode, Aider, Cline, etc.) doesn't rely on HTTP headers or TLS fingerprinting. It pattern-matches the system prompt content. Replace the static portion of your system prompt with Claude Code's real prompt — requests go through. Keep your custom prompt — blocked. Here's how I proved it.
Background
I use OpenCode with an Anthropic Max (20x) subscription via the opencode-anthropic-auth-community plugin. On April 9, 2026, requests started failing with:
"Third-party apps now draw from your extra usage. To keep using this app, go to Settings to buy extra usage credits."
Same account works fine through Claude Code and Claude Desktop. The block is per-request, not per-account.
The Investigation
Hypothesis 1: HTTP Headers
Theory: Anthropic fingerprints the client via User-Agent, X-Stainless-*, x-app, and other headers that differ between Claude Code and OpenCode.
Experiment: Captured a full Claude Code request (headers + body). Sent the Claude Code body with OpenCode headers.
Result: 200 OK
Conclusion: Headers are not the detection mechanism.
Hypothesis 2: TLS Fingerprint (JA3/JA4)
Theory: Anthropic analyzes the TLS handshake fingerprint. Bun (OpenCode's runtime) has a different JA3/JA4 than Node.js (Claude Code's runtime).
Experiment: Set up a Node.js HTTPS proxy between OpenCode and Anthropic's API. All TLS negotiations now happen from Node.js, not Bun.
Result: Same "Third-party apps" error.
Conclusion: TLS fingerprinting is not the detection mechanism.
Hypothesis 3: System Prompt Content
Theory: Anthropic's server inspects the system field in the request body and rejects prompts that don't match Claude Code's known patterns.
Experiment A: Sent the OpenCode body (with oh-my-openagent's ~30K custom system prompt) using perfect Claude Code headers.
Result: 400 — "Third-party apps"
Experiment B: Replaced only the static portion of the system prompt with Claude Code's real system prompt. Kept all runtime sections (<env>, <directories>, skills, custom AGENTS.md content) from OpenCode.
Result: 200 OK
Conclusion: The detection mechanism is server-side system prompt analysis.
Anatomy of the System Prompt
OpenCode + oh-my-openagent sends the system prompt as an array of blocks:
Index 0: Billing header (cc_version=..., cc_entrypoint=...)
Index 1: Identity line ("You are Claude Code..." or "You are Sisyphus...")
Index 2: Main prompt (static instructions + runtime sections)
Block 2 is the critical one. It contains two parts concatenated together:
[STATIC PART — ~30K chars of agent instructions, personality, orchestration rules]
[RUNTIME PART — <env>, <directories>, skills list, AGENTS.md content]
Only the static part triggers the block. The runtime sections pass through even with completely custom content (custom AGENTS.md, custom skills, custom environment variables).
This means Anthropic is likely doing one of:
- Pattern matching against known Claude Code prompt structure
- Embedding similarity / classification of the static prompt
- Checking for specific anchor phrases that should be present in a legitimate Claude Code prompt
The Fix
The fix is straightforward: load Claude Code's real system prompt and swap only the static portion, preserving runtime sections.
// Load CC system prompt once if (!globalThis.__ccSysPrompt) { const fs = require("fs"); globalThis.__ccSysPrompt = fs.readFileSync("cc-system-prompt.txt", "utf-8"); } // In the system block processing: if (idx === 2 && globalThis.__ccSysPrompt) { const envIdx = text.indexOf("<env>"); if (envIdx !== -1) { const runtime = text.slice(envIdx); // keep runtime text = globalThis.__ccSysPrompt + "\n" + runtime; // swap static } else { text = globalThis.__ccSysPrompt; } }
After this change:
- All OpenCode features work (chat, subagents, tools, memory)
- oh-my-openagent skills and custom AGENTS.md instructions work
- No "third-party apps" error
Trade-off: You lose any custom personality/orchestration instructions that were in the static prompt portion. Workaround: move critical instructions into AGENTS.md, which lands in the runtime section and isn't flagged.
What This Tells Us About Anthropic's Detection
-
It's content-based, not transport-based. Headers, TLS, IP — none of these matter. The server reads your prompt and decides.
-
It's not keyword-based. I ran a binary search through the 30K prompt trying to find a specific trigger phrase. There isn't one. It's the overall "shape" of the text — likely an embedding comparison or a classifier.
-
It only checks the static portion. Runtime-injected content (environment, directory listings, tool descriptions, user-provided AGENTS.md) passes through regardless of content. This makes sense — Anthropic needs to allow Claude Code users to have custom project instructions.
-
It's per-request, not per-account. The same OAuth token works fine when the prompt matches Claude Code's pattern. Switch the prompt back to custom — instant block. No cooldown, no account flag.
Broader Implications
This approach is fragile on both sides:
For Anthropic: Prompt-based detection is trivially bypassed once you know the mechanism. It's security through obscurity — the "secret" is just Claude Code's system prompt, which is already publicly leaked and extractable by asking Claude Code to print its instructions.
For users: Any update to Claude Code's system prompt means your cached copy is outdated and might stop working. You're in a cat-and-mouse game where Anthropic can change the expected prompt at any time.
The real question: Why not just check the OAuth client_id? Third-party tools use the same client_id as Claude Code (that's how the auth plugin works). If Anthropic issued separate client_ids for third-party tools — or required API keys instead of OAuth for non-official clients — this entire class of bypass wouldn't exist. The fact that they're resorting to prompt content analysis suggests the OAuth architecture doesn't cleanly separate official from unofficial clients.
Methodology Notes
All experiments were conducted on April 9, 2026 with:
- OpenCode 1.3.15
- Plugin: @thehugeman/opencode-anthropic-auth-community
- oh-my-openagent with custom Sisyphus agent configuration
- Anthropic Max (20x) subscription
- Windows 11, Node.js v24.13.1
Each hypothesis was tested with controlled variable isolation — changing only one factor at a time while keeping all others constant.
Disclaimer: This is security research documenting how a detection mechanism works. Bypassing platform restrictions may violate Anthropic's Terms of Service. Use this information responsibly.