Metadata-Version: 2.5
Name: ccgw
Version: 0.1.1
Summary: Local multi-provider Anthropic-protocol gateway for Claude Code: coconut, GLM and MiMo in one /model menu.
Project-URL: Homepage, https://github.com/XuNeo/ccgw
Project-URL: Repository, https://github.com/XuNeo/ccgw
Project-URL: Issues, https://github.com/XuNeo/ccgw/issues
Author: XuNeo
License-Expression: MIT
License-File: LICENSE
Keywords: anthropic,claude,claude-code,gateway,glm,llm,mimo,proxy
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.115
Requires-Dist: httpx>=0.27
Requires-Dist: uvicorn[standard]>=0.32
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Description-Content-Type: text/markdown

# cc-gateway

A local multi-provider gateway that impersonates the Anthropic Messages API for
Claude Code, so you can switch between models from different backends at any
point in any session.

It forwards the Anthropic dialect only. Every backend must expose an
Anthropic-compatible endpoint; there is deliberately no OpenAI translation
layer.

## Providers

| provider | endpoint | auth |
| --- | --- | --- |
| `coconut` | `http://127.0.0.1:8787` (local daemon) | `Bearer coconut` |
| `glm` | `https://open.bigmodel.cn/api/anthropic` | `x-api-key`, `$GLM_API_KEY` |
| `mimo` | `https://token-plan-cn.xiaomimimo.com/anthropic` | `x-api-key`, `$MIMO_API_KEY` |

## Install

Requires Python 3.11+ (`tomllib` is stdlib there).

```bash
uv tool install ccgw
# or
pipx install ccgw
```

## Run

The gateway reads its provider registry from a `config.toml`, looked up in
this order: `$CCGW_CONFIG`, `./config.toml`, `~/.config/ccgw/config.toml`.

```bash
export GLM_API_KEY=...      # never stored in this repo
export MIMO_API_KEY=...
ccgw                        # listens on 127.0.0.1:8788
ccgw --port 9000            # or --config /path/to/config.toml
```

A source checkout can run the same entry point directly:

```bash
pip install -r requirements.txt
python serve.py
```

Point Claude Code at it in `~/.claude/settings.json`:

```json
{
  "env": {
    "ANTHROPIC_BASE_URL": "http://127.0.0.1:8788",
    "ANTHROPIC_AUTH_TOKEN": "ccgw",
    "ANTHROPIC_API_KEY": "",
    "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1"
  }
}
```

Claude Code may request built-in Opus, Sonnet, or Haiku ids for background
work. Keep those mappings explicit under `[routing.aliases]`; any unlisted model
fails closed instead of silently running an arbitrary provider.

## Model naming

Public ids keep the v0.1.0 form: `claude-<slug(upstream)>` plus a `[1m]`
suffix for models with a 1M context window. Both parts are load-bearing:

* Claude Code's gateway discovery drops any id that does not contain `claude`
  or `anthropic`, so the prefix is mandatory for a model to appear in `/model`.
* Claude Code infers a 1M window from a `[1m]` substring, which is how the
  gateway communicates window size. `/v1/models` cannot carry it: Claude Code's
  parser keeps only `id` and `display_name`.

The suffix is presentation only. It is stripped before the request goes
upstream, because neither GLM nor MiMo accepts a `[1m]` model name on these
endpoints (both reject it outright), even though their Coding Plan docs
describe the suffix.

## Behaviour worth knowing

**Transparent by default.** Request history and parameters are forwarded unless
a `[providers.<name>.compat]` option explicitly enables an adapter. Unknown
models return 404 rather than silently running the first configured model;
`[routing.aliases]` provides auditable mappings for Claude Code background model
ids.

**Thinking provenance.** Same-route history is preserved. Once a session has
switched model routes, provider-bound thinking blocks are stripped from later
replays. A provider may also explicitly enable one retry without thinking after
a thinking-shaped 400.

**Tool repair is opt-in.** `compat.repair_tools = true` normalises invalid tool
ids and supplies interrupted tool results. Tool names and tool inputs are never
rewritten.

**Errors.** Upstream failures are re-shaped into the Anthropic envelope while
preserving their message. Retry, request-id, and rate-limit response headers are
relayed to Claude Code.

**Streaming.** The upstream is requested without content compression and read
through a decoding iterator. Complete SSE events are relayed as units, so the
15-second keepalive ping cannot split an event.

**Token counting.** `/v1/messages/count_tokens` follows the selected model to
its upstream endpoint. Unsupported providers return their real error so Claude
Code can use its own fallback; the gateway never invents a tokenizer estimate.

## Tests

```bash
python tests/selftest.py
```

The self-test uses loopback stub servers only; it needs no provider credentials
or external network.

## License

[MIT](LICENSE)
