Recreates the PR #17 change (closed without merging, then asked for back
after confirming a real ANTHROPIC_API_KEY would mean separate/duplicate
billing rather than actually using the Pro/Max subscription).
New POST /mcp endpoint (Streamable HTTP transport, stateless — fresh
McpServer+transport per request) exposing one tool, ask_claude_code: runs
the real `claude` binary against a prompt, billed against the subscription
rather than API credits. Works specifically because it's the actual CLI
making the request server-side. Read-only — no Edit/Write/git-push/
git-commit tools.
Also removes litellm-config.yaml's "anthropic-claude" model entry: it only
ever worked when the real claude CLI itself was the caller (proven earlier),
so having it listed as a selectable model was actively misleading — Hermes
picking it directly is exactly what produced the '401: Missing Anthropic
API Key' confusion that led back to this bridge. The MCP tool is the actual
working path now; general_settings.forward_client_headers_to_llm_api is
also removed since nothing uses it anymore.
Tested end-to-end locally again before pushing (built the image, ran it,
full MCP handshake via curl) — real 'pong' from the real claude CLI.
Hermes sends provider-agnostic params like reasoning_effort that OpenRouter's
auto model doesn't accept, causing a 400 on every request until this was
set. Also documents (in a follow-up, not this commit) that getting Hermes to
actually use this gateway needed live 'hermes config set' calls on the
running container (providers.litellm.{api,api_key}, model.provider=litellm,
model.default=auto) — that state lives in the hermes-data volume, not git,
so it isn't reproduced automatically by a fresh deploy. See README.
Earlier this session I removed this route after a curl-based test got
rejected by Anthropic and concluded OAuth subscription forwarding doesn't
work through a proxy at all. That conclusion was wrong: the real `claude`
CLI binary, with ANTHROPIC_BASE_URL pointed at litellm, successfully
completed a request billed against the subscription. The earlier curl test
just didn't replicate whatever header/fingerprint Anthropic requires from
genuine Claude Code CLI traffic — LiteLLM relays that fine when the real
CLI is the caller, but a hand-built request from any other client (Hermes
included) still gets rejected the same way curl did.
- New litellm service (pinned v1.98.0 — litellm 1.82.7/1.82.8 on PyPI were
compromised with credential-stealing malware in March 2026; internal-only,
no Traefik route, no reason to expose an LLM gateway with a master key
publicly).
- Replaces !claude/!ai command prefixes with automatic routing: every plain
message in the control room goes through a classifier (router.js) that
decides chat vs code_task. Chat replies use OpenRouter's own auto-router
(openrouter/auto) via LiteLLM; code_task requests go through the existing
runChatTask() flow (Claude Code CLI, unchanged, still using the
subscription token directly).
- Investigated routing Claude itself through LiteLLM via OAuth token
forwarding (general_settings.forward_client_headers_to_llm_api) so the
Pro/Max subscription could be one of the auto-routable options. Confirmed
non-functional: Anthropic returns a generic rate_limit_error for any
direct API call using this token type outside the real Claude Code CLI,
reproduced with plain curl straight to api.anthropic.com. Not included.
- MATRIX_BOT_USER_ID now required and set explicitly (self-message filtering
can no longer rely on a command-prefix mismatch once there isn't one).