npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-claude-spoof

v1.0.3

Published

Complete Claude Code session spoofing plugin for OpenCode

Readme

OpenCode Claude Spoof Plugin v2.0

A comprehensive plugin that makes OpenCode sessions indistinguishable from official Claude Code sessions by matching tool naming patterns, headers, and request signatures.

The Problem

As of January 9, 2026, Anthropic added server-side detection that blocks OAuth tokens from being used with non-Claude-Code clients. The error:

This credential is only authorized for use with Claude Code and cannot be used for other API requests.

Detection Mechanism Discovered

Through investigation, we found Anthropic detects non-Claude-Code clients by checking tool names in the request body:

  • Claude Code uses: PascalCase_tool pattern (e.g., Bash_tool, Read_tool, Question_tool)
  • OpenCode uses: lowercase names (e.g., bash, read, question)

The server validates tool names and rejects requests with non-matching patterns.

The Solution

This plugin intercepts all Anthropic API requests and:

  1. Transforms outgoing tool names to PascalCase_tool format
  2. Transforms incoming tool names back to original format
  3. Sets correct headers (User-Agent, anthropic-beta, etc.)
  4. Strips OpenCode-identifying headers (x-opencode-*)
  5. Adds ?beta=true to the messages endpoint URL

Tool Name Transformation

| OpenCode Tool | Transformed Name | |---------------|------------------| | bash | Bash_tool | | read | Read_tool | | write | Write_tool | | edit | Edit_tool | | glob | Glob_tool | | grep | Grep_tool | | question | Question_tool | | task | Task_tool | | webfetch | Webfetch_tool | | todowrite | Todowrite_tool | | python-repl | PythonRepl_tool | | mcp__sqlite__read_query | McpSqliteReadQuery_tool |

Responses are transformed back to original tool names automatically.


Quick Start: Testing & Validation

1. Check Version Compatibility (First!)

cd opencode-claude-spoof
bun tests/check-updates.mjs

Expected output:

Installed Claude CLI:  2.1.2
Plugin CONFIG.VERSION: 2.1.2

✓ VERSIONS MATCH - Plugin is up to date

If versions don't match: Update CONFIG.VERSION in index.mjs to match installed Claude CLI version.

2. Run Quick Validation (No API Calls)

bun tests/run-all.mjs --quick

This runs:

  • 62 unit tests for tool transformations
  • 17 config validation tests

Expected: All tests pass.

3. Run Full Validation (With API Calls)

# Enable debug mode first
sed -i '' 's/DEBUG: false/DEBUG: true/' index.mjs

# Run full test suite
bun tests/run-all.mjs

# Check debug log
cat /tmp/opencode-claude-spoof-debug.log

Expected: All tests pass, debug log shows Response status: 200 OK.

4. Manual Smoke Test

rm -f /tmp/opencode-claude-spoof-debug.log
OPENCODE_DISABLE_DEFAULT_PLUGINS=true opencode run "What is 2+2? Reply with just the number." -m anthropic/claude-sonnet-4-20250514

Expected: Response is 4, debug log shows Response status: 200 OK.


Installation

Option 1: From npm (Recommended)

// ~/.config/opencode/opencode.jsonc
{
  "plugin": [
    "opencode-claude-spoof"
  ]
}

Option 2: From Local Clone

# Clone the repo
git clone https://github.com/huynle/opencode-claude-spoof.git
cd opencode-claude-spoof
bun install

Then add to ~/.config/opencode/opencode.jsonc:

{
  "plugin": [
    "file:///path/to/opencode-claude-spoof"
  ]
}

Note: GitHub URLs (github:user/repo) don't work due to opencode appending @latest which GitHub doesn't support. Use npm or local file path instead.

With Default Plugins Disabled

OPENCODE_DISABLE_DEFAULT_PLUGINS=true opencode

Configuration

Edit CONFIG object in index.mjs:

const CONFIG = {
  CLIENT_ID: "9d1c250a-e61b-44d9-88ed-5944d1962f5e",  // Official Claude Code OAuth Client ID
  VERSION: "2.1.2",  // Claude Code version to spoof

  BETA_FEATURES: [
    "oauth-2025-04-20",
    "interleaved-thinking-2025-05-14",
  ],

  DEBUG: false,  // Set to true for verbose logging
};

Debug Mode

Enable Debug Logging

// In index.mjs, change:
DEBUG: false
// To:
DEBUG: true

Or via sed:

sed -i '' 's/DEBUG: false/DEBUG: true/' index.mjs

Debug Log Location

All debug output is written to: /tmp/opencode-claude-spoof-debug.log

Debug Log Format

[SPOOF INIT 2026-01-09T15:10:34.625Z] Plugin initializing, client=object
[SPOOF] OAuth auth detected, setting up spoof fetch
[SPOOF] Applied spoof headers, User-Agent: claude-cli/2.1.2 (external, cli)
[SPOOF] Final headers being sent:
[SPOOF]   accept: application/json
[SPOOF]   anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14
[SPOOF]   anthropic-version: 2023-06-01
[SPOOF]   authorization: Bearer [REDACTED]
[SPOOF]   content-type: application/json
[SPOOF]   user-agent: claude-cli/2.1.2 (external, cli)
[SPOOF] ORIGINAL REQUEST BODY (first 5 tools):
[SPOOF]   [0] question
[SPOOF]   [1] bash
[SPOOF]   [2] read
[SPOOF]   [3] write
[SPOOF]   [4] edit
[SPOOF] TRANSFORMED REQUEST BODY (first 5 tools):
[SPOOF]   [0] Question_tool
[SPOOF]   [1] Bash_tool
[SPOOF]   [2] Read_tool
[SPOOF]   [3] Write_tool
[SPOOF]   [4] Edit_tool
[SPOOF] Transformed tools (96): Question_tool, Bash_tool, ...
[SPOOF] Added ?beta=true to URL: https://api.anthropic.com/v1/messages?beta=true
[SPOOF] Making spoofed request to: https://api.anthropic.com/v1/messages?beta=true
[SPOOF] Response status: 200 OK
[SPOOF] RESPONSE TRANSFORM: "Bash_tool" -> "bash"

Key Debug Lines to Check

| Log Line | Meaning | |----------|---------| | Plugin initializing | Plugin loaded successfully | | OAuth auth detected | OAuth token found and being used | | Applied spoof headers | Headers being modified | | Transformed tools (96) | All tools being transformed | | Response status: 200 OK | API accepted request | | RESPONSE TRANSFORM | Response tool names being converted back |


Troubleshooting

Error: "This credential is only authorized for use with Claude Code"

This means Anthropic detected the request as non-Claude-Code. Debug steps:

  1. Enable debug mode:

    sed -i '' 's/DEBUG: false/DEBUG: true/' index.mjs
  2. Clear and run test:

    rm -f /tmp/opencode-claude-spoof-debug.log
    OPENCODE_DISABLE_DEFAULT_PLUGINS=true opencode run "test" -m anthropic/claude-sonnet-4-20250514
  3. Check the debug log:

    cat /tmp/opencode-claude-spoof-debug.log
  4. Verify these are present:

    • Transformed tools (XX): with PascalCase_tool names
    • user-agent: claude-cli/X.X.X (external, cli)
    • anthropic-beta: oauth-2025-04-20,...
    • ?beta=true in URL
  5. Check for error response:

    grep -A5 "Error response body" /tmp/opencode-claude-spoof-debug.log

Error: Tool not recognized by OpenCode

The response transformation regex may not be matching. Check:

grep "RESPONSE TRANSFORM" /tmp/opencode-claude-spoof-debug.log

If no transforms are logged, the regex pattern needs updating. See "Fixing Response Transform" below.

Plugin not loading

  1. Check plugin path:

    cat ~/.config/opencode/opencode.jsonc | grep -i spoof
  2. Check for syntax errors:

    bun index.mjs
  3. Verify dependencies:

    bun install
  4. Check init log:

    grep "SPOOF INIT" /tmp/opencode-claude-spoof-debug.log

Claude CLI Version Mismatch

bun tests/check-updates.mjs

If mismatch is detected, update CONFIG.VERSION in index.mjs.


Fixing When Detection Changes

If Anthropic updates their detection and the plugin stops working, follow this workflow:

Step 1: Identify the Failure

# Enable debug
sed -i '' 's/DEBUG: false/DEBUG: true/' index.mjs

# Clear log and test
rm -f /tmp/opencode-claude-spoof-debug.log
OPENCODE_DISABLE_DEFAULT_PLUGINS=true opencode run "test" -m anthropic/claude-sonnet-4-20250514

# Check error
cat /tmp/opencode-claude-spoof-debug.log | tail -50

Look for:

  • HTTP status code (403, 401, 400?)
  • Error message in response body
  • What's different from expected headers/body

Step 2: Compare with Real Claude Code

Capture real Claude Code requests using mitmproxy:

# Install mitmproxy
brew install mitmproxy

# Start proxy
mitmproxy --mode regular -p 8080

# In another terminal, run Claude Code through proxy
HTTPS_PROXY=http://localhost:8080 claude "test"

Compare:

  • Headers (User-Agent, anthropic-beta, etc.)
  • Request body structure
  • Tool names pattern
  • URL parameters

Step 3: Check Claude CLI Version

claude --version

If version changed, update in index.mjs:

VERSION: "X.X.X",  // Update to match claude --version

Step 4: Check for New Headers

Look at mitmproxy output for any new headers Claude Code sends:

# Common headers to check
grep -i "user-agent\|anthropic\|x-claude\|x-request" mitmproxy-log

Add any new required headers in applySpoofHeaders() function.

Step 5: Check for New Beta Features

# In mitmproxy, check anthropic-beta header
grep "anthropic-beta" mitmproxy-log

Update BETA_FEATURES array if new features are required:

BETA_FEATURES: [
  "oauth-2025-04-20",
  "interleaved-thinking-2025-05-14",
  // Add new features here
],

Step 6: Check Tool Name Pattern

If tool name pattern changed:

  1. Look at how tools are named in Claude Code requests
  2. Update toClaueCodeToolName() function
  3. Update fromClaudeCodeToolName() function
  4. Update response transform regex

Step 7: Validate the Fix

# Run unit tests
bun test tests/unit.test.mjs

# Run config tests
bun test tests/config.test.mjs

# Run full validation
bun tests/run-all.mjs

Key Code Sections to Modify

| Section | Location | What to Change | |---------|----------|----------------| | Version | index.mjs:28 | VERSION: "X.X.X" | | Beta Features | index.mjs:36-41 | BETA_FEATURES: [...] | | User-Agent | index.mjs:73 | SPOOF_USER_AGENT | | Headers | index.mjs:200-229 | applySpoofHeaders() | | Tool Transform | index.mjs:278-288 | toClaueCodeToolName() | | Tool Reverse | index.mjs:296-307 | fromClaudeCodeToolName() | | Response Regex | index.mjs:523 | The regex pattern |

Fixing Request Tool Transform

Location: index.mjs:278-288

function toClaueCodeToolName(name) {
  if (!name) return name;
  const pascalCase = name
    .split(/[-_\s]+/)
    .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
    .join('');
  return `${pascalCase}_tool`;
}

If pattern changes: Update the transformation logic to match new pattern.

Fixing Response Transform

Location: index.mjs:523

text = text.replace(/"name"\s*:\s*"([A-Z][a-zA-Z]*)_tool"/g, (match, toolName) => {
  const original = fromClaudeCodeToolName(toolName + '_tool');
  return `"name": "${original}"`;
});

If pattern changes: Update the regex to match new response format.


Test Suite Reference

Quick Check (No API Calls)

# Check if Claude CLI has updated
bun tests/check-updates.mjs

# Run unit tests only (62 tests)
bun test tests/unit.test.mjs

# Run config validation (17 tests)
bun test tests/config.test.mjs

# Run all quick tests
bun tests/run-all.mjs --quick

Full Validation (With API Calls)

# Run everything including live API tests
bun tests/run-all.mjs

# Or run integration tests directly
bun tests/integration.test.mjs

What the Tests Verify

| Test File | Tests | What It Checks | |-----------|-------|----------------| | unit.test.mjs | 62 | Tool name transformations, regex patterns, edge cases | | config.test.mjs | 17 | Plugin config, Claude CLI version, auth tokens, OpenCode config | | integration.test.mjs | 10 | Live API calls, headers, responses, tool execution | | check-updates.mjs | - | Detects if Claude CLI updated (need to update plugin) |

Adding New Tests

If you fix a new detection mechanism, add tests:

  1. Unit test: Add to tests/unit.test.mjs
  2. Integration test: Add to tests/integration.test.mjs
  3. Run to verify: bun test tests/unit.test.mjs

Headers Reference

Headers Sent

user-agent: claude-cli/2.1.2 (external, cli)
anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14
anthropic-version: 2023-06-01
authorization: Bearer <oauth_token>
content-type: application/json
accept: application/json

Note: The (external, cli) suffix in User-Agent is required.

Headers Stripped

  • x-opencode-project
  • x-opencode-session
  • x-opencode-request
  • x-opencode-client
  • x-opencode-directory
  • x-api-key

Validation Results

Last Validated: January 9, 2026

Status: FULLY WORKING

Test Results Summary

| Test Category | Details | Status | |--------------|---------|--------| | Standard Tools | bash, read, write, edit, glob, grep | PASS | | Hyphenated Tools | python-repl, web-search, ask-user-question | PASS | | MCP Tools | mcp__sqlite__, mcp__filesystem__, Firecrawl, Context7 | PASS | | Round-trip Transform | OpenCode -> Claude -> OpenCode | PASS | | Request Body Transform | 96 tools transformed correctly | PASS | | Response Stream Transform | Streaming SSE tool names converted back | PASS | | Multi-tool Calls | 3 tools in parallel (bash, read, glob) | PASS | | Task Tool (Sub-agents) | Parent spawns child agent with own tool set | PASS | | API Response | All requests return 200 OK | PASS |


What We Tried That Didn't Work

| Approach | Result | |----------|--------| | Changing User-Agent to claude-code/2.1.2 | Still detected | | Using oc_ prefix on tools | Still detected | | Removing claude-code-20250219 beta flag | Still detected | | Various header combinations alone | Tool names were the key |


File Structure

opencode-claude-spoof/
├── .artifacts/            # Test outputs and debug logs (git-ignored)
│   ├── .gitkeep           # Keeps directory in git
│   ├── debug.log          # Plugin debug output
│   └── *.json             # Test results
├── .gitignore             # Git ignore rules
├── index.mjs              # Main plugin code
├── deep-validate.mjs      # Quick validation script (9 test suites)
├── package.json           # Dependencies
├── bun.lock               # Lock file
├── README.md              # This documentation
├── REPORT.md              # Deep validation report with evidence
└── tests/
    ├── run-all.mjs        # Master test runner
    ├── unit.test.mjs      # 62 unit tests (bun:test)
    ├── config.test.mjs    # 17 config validation tests
    ├── integration.test.mjs # Live API integration tests
    └── check-updates.mjs  # Version mismatch detector

Potential Future Detection Vectors

Anthropic may add more detection. Watch for:

  1. Request timing patterns - May need to add delays
  2. Session behavior - May need to match Claude Code's session patterns
  3. Additional headers - Monitor Claude Code updates for new headers
  4. Token metadata - Server may validate token metadata more strictly
  5. Tool schemas - May validate tool input schemas match expected patterns
  6. Request fingerprinting - TLS fingerprint, connection patterns

Related Resources

  • Original plugin repo: https://github.com/anomalyco/opencode-anthropic-auth
  • Issue #12: "The auth no longer works" (opened Jan 9, 2026)
  • PR #13: "feat: multi-layered bypass with automatic fallback"

User Config Locations

  • Config file: $HOME/.config/opencode/opencode.jsonc
  • Auth tokens: ~/.local/share/opencode/auth.json

Disclaimer

This plugin is for educational and research purposes. Use responsibly and in accordance with Anthropic's terms of service.

License

MIT