Skip to content

Internal Gateway

If your organization runs Claude Code against an internal LLM gateway - typically with an apiKeyHelper for OAuth refresh, custom routing headers, and OTEL telemetry pinned via managed-settings.json.

Not Diamond can sit between Claude Code and the gateway and routes each turn to the cheapest model that still meets quality. Below is what’s supported and how to confirm it’s working.

managed-settings.json is the highest-precedence config layer in Claude Code - above shell env, user settings, and project settings. The proxy steers Claude Code by exporting ANTHROPIC_BASE_URL=http://127.0.0.1:8082 via the launch environment. If managed-settings.json also sets ANTHROPIC_BASE_URL, the managed value wins and Claude Code bypasses the local proxy entirely.

The proxy detects this at startup and refuses to launch. To resolve, remove ANTHROPIC_BASE_URL from managed-settings.json and supply the gateway URL to the proxy instead.

Remove the ANTHROPIC_BASE_URL entry from env. Leave everything else in place - apiKeyHelper, ANTHROPIC_CUSTOM_HEADERS, CLAUDE_CODE_API_KEY_HELPER_TTL_MS, and the OTEL_* exporters are all preserved by the proxy.

// /Library/Application Support/ClaudeCode/managed-settings.json (macOS)
// /etc/claude-code/managed-settings.json (Linux)
// C:\ProgramData\ClaudeCode\managed-settings.json (Windows)
{
"apiKeyHelper": "your-token-refresh-command",
"model": "sonnet",
"effortLevel": "medium",
"env": {
"ENABLE_TOOL_SEARCH": "true",
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-otel-collector",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_TRACES_EXPORTER": "otlp",
// ANTHROPIC_BASE_URL removed - the proxy sets it on launch.
"ANTHROPIC_CUSTOM_HEADERS": "source: claude-code\norg-id: 42\nprovider: anthropic",
"CLAUDE_CODE_API_KEY_HELPER_TTL_MS": "7200000"
}
}
Terminal window
notdiamond login
notdiamond init --credential forwarded --gateway-url https://your-gateway

This writes ~/.notdiamond/config.json with credential type forwarded and your gateway URL.

Terminal window
notdiamond claude

Each operator on a managed Claude Code install needs to run steps 2 and 3 once.

ItemHow it’s preserved
apiKeyHelper tokenClaude Code stamps the refreshed Authorization: Bearer … on every outbound request. The proxy forwards it to the gateway verbatim. No token is stored by the proxy.
ANTHROPIC_CUSTOM_HEADERS (source, org-id, provider, …)The proxy captures every inbound header that isn’t reserved and forwards it to the gateway, so your routing layer sees the same metadata it does without the proxy.
OTEL_* exportersClaude Code emits OTEL directly to your collector - it never touches the proxy. Unaffected.

After notdiamond claude launches, check that requests are reaching the proxy and the proxy is calling your gateway:

Terminal window
notdiamond status # shows provider = forwarded and uptime
notdiamond logs -f # tails per-request rows

A healthy turn shows one line per request with status: 200 and a non-null routed_model / routed_effort. To confirm exactly which headers arrived at the gateway, check the gateway’s own access log - the proxy never logs raw bearer tokens locally.

If notdiamond logs shows status: 502 with an error: field containing a gateway message, the gateway rejected the request. The message usually identifies what’s missing (an expected routing header, an unrecognized token, etc.). For more detail per request, use notdiamond logs --debug.

Note that if your account has routing visibility hidden from members, the --debug long-context diagnostics are redacted for regular users. They are still visibile to Owners and Admins.

  • Pinning ANTHROPIC_BASE_URL in managed-settings.json. The proxy refuses to launch. Move the gateway URL to notdiamond init --gateway-url instead.
  • Stripping or rewriting the inbound Authorization header. The proxy passes the bearer through; the gateway is responsible for validating it.
  • Hot-reload of managed-settings.json changes. Restart Claude Code to pick up new managed-settings values. The proxy itself does not need to be restarted.