Skip to content

croll83/openclaw-billing-proxy

 
 

Repository files navigation

Hermes Billing Proxy

Route Hermes API requests through your Claude Max/Pro subscription instead of Extra Usage billing.

Tested models: Claude Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 4.6, Haiku 4.5, Gemini 2.5 Pro/Flash

What This Does

Sits between Hermes and the Anthropic/Gemini APIs as a transparent HTTP proxy. Hermes sends requests to the proxy, which forwards them to upstream with:

  • Claude Code's billing identifier injected into the system prompt
  • Your Claude Code OAuth token replacing Hermes's auth (auto-refreshed)
  • Hermes-specific keywords sanitized to avoid detection
  • Gemini requests auto-routed to Google Cloud Code API
  • Model-aware beta headers (long-context betas only sent for Opus)
  • Correct TLS fingerprint (Node.js HTTPS client)

Zero external dependencies. Linux only. Node.js 18+.

How It Works

Hermes (Python) --> HTTP proxy:18801 --> HTTPS Node.js --> api.anthropic.com (Anthropic models)
                                                      --> cloudcode-pa.googleapis.com (Gemini models)

The proxy performs bidirectional request/response processing:

Outbound (to API):

  1. Billing Header -- Injects Claude Code billing identifier into system prompt
  2. Token Swap -- Replaces auth token with your Claude Code OAuth token
  3. Keyword Replacement -- Replaces Hermes-specific terms (configurable)
  4. System Prompt Sanitization -- Strips structured config blocks if present
  5. CC Tool Stubs -- Injects Claude Code tool stubs for fingerprint camouflage

Inbound (to Hermes): 6. Reverse Mapping -- Restores all original keywords in SSE and JSON responses

Requirements

  • Node.js 18+
  • Claude Max or Pro subscription
  • Claude Code CLI installed and authenticated
  • Hermes running on the same machine

Installing Claude Code CLI

npm install -g @anthropic-ai/claude-code
claude auth login

Verify:

claude auth status
# Should show: loggedIn: true, subscriptionType: max (or pro)

Quick Start

# 1. Clone
git clone https://github.com/croll83/openclaw-billing-proxy hermes-billing-proxy
cd hermes-billing-proxy

# 2. Run setup (auto-detects credentials and Hermes)
node setup.js

# 3. Start the proxy
node index.js

# 4. Point Hermes ANTHROPIC_BASE_URL to the proxy address

Configuration

The config.json file (generated by setup or created manually):

{
  "port": 18801,
  "credentialsPath": "~/.claude/.credentials.json",
  "stripSystemConfig": true,
  "injectCCStubs": true,
  "replacements": [
    ["~/.hermes/", "~/.config/app/"],
    ["hermes_tools", "code_tools"],
    ["hermes_telegram", "tg_channel"],
    ["hermes-secrets.env", "secrets.env"],
    ["Plan mode for Hermes", "Plan mode"],
    ["hermes_cli", "cli_module"],
    ["from hermes", "from app"],
    ["Hermes", "Assistant"],
    ["hermes", "assistant"]
  ],
  "reverseMap": [
    ["~/.config/app/", "~/.hermes/"],
    ["code_tools", "hermes_tools"],
    ["tg_channel", "hermes_telegram"],
    ["secrets.env", "hermes-secrets.env"],
    ["Plan mode", "Plan mode for Hermes"],
    ["cli_module", "hermes_cli"],
    ["from app", "from hermes"],
    ["Assistant", "Hermes"],
    ["assistant", "hermes"]
  ]
}

Adding New Patterns

If you find new keywords that trigger detection, add them to both replacements and reverseMap:

{
  "replacements": [["new_hermes_term", "new_safe_term"]],
  "reverseMap": [["new_safe_term", "new_hermes_term"]]
}

Running as a Service (systemd)

cat > ~/.config/systemd/user/hermes-billing-proxy.service << EOF
[Unit]
Description=Hermes Billing Proxy
After=network-online.target
Wants=network-online.target

[Service]
Environment="DEBUG_DUMP=1"
Type=simple
ExecStart=$(which node) $(pwd)/index.js
WorkingDirectory=$(pwd)
Restart=always
RestartSec=5
TimeoutStopSec=10

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable hermes-billing-proxy
systemctl --user start hermes-billing-proxy

Token Refresh

The proxy auto-refreshes the OAuth token:

  • Proactive: refreshes 5 minutes before expiry on the next request
  • Reactive: on 401 from upstream, refreshes and retries once transparently
  • Token is persisted to ~/.claude/.credentials.json after refresh

No manual intervention needed. The token refresh uses platform.claude.com/v1/oauth/token.

Health Check

curl http://127.0.0.1:18801/health

Troubleshooting

node troubleshoot.js

Common Issues

"Could not find credentials file"

  • Run claude auth login to authenticate
  • Check ~/.claude/.credentials.json exists and is non-empty

Proxy returns 400 "extra usage"

  • Add more keyword patterns to config.json
  • Check proxy console for DETECTION! log lines

429 Rate Limit

  • Normal if you have active Claude Code sessions sharing the rate bucket
  • Wait and retry

Token Expired / 401

  • Should auto-recover via built-in refresh
  • If persistent, check journalctl --user -u hermes-billing-proxy for [AUTH] lines
  • Manual fallback: claude -p "ping" --max-turns 1 --no-session-persistence

License

MIT

About

Route OpenClaw API requests through Claude Code subscription billing instead of Extra Usage

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • JavaScript 100.0%