A reverse proxy that converts Command Code API to OpenAI / Anthropic compatible endpoints. Single file, zero external dependencies.
Built by analyzing official CLI v0.32.3 network traffic to accurately replicate the Command Code API request protocol.
Features: OpenAI Chat Completions + Anthropic Messages API | Streaming & non-streaming | Tool calling (tool_use) | Multimodal image input | Reasoning effort | Dynamic model list | Cache hit metrics | 30s/90s stream timeout
Community: Linux.do — a friendly Chinese tech community.
npm start # Start (default http://0.0.0.0:3000)
npm run dev # Watch mode (auto-reload on file changes)API Key is passed via the Authorization request header — no need to store it in config files. Key must start with user_ (automatically matched with any prefix, e.g. Bearer token_user_xxx):
curl http://127.0.0.1:3050/v1/chat/completions \
-H "Authorization: Bearer user_xxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'commandcode/
├── config.json # Port / log path etc.
├── LICENSE # MIT License
├── package.json # npm start / npm run dev
├── proxy.mjs # Single-file proxy core (~1400 lines)
├── AGENTS.md # AI dev instructions
├── README.md # This document (English)
└── README_zh.md # Chinese documentation
| Field | Default | Description |
|---|---|---|
port |
3000 |
Listen port |
host |
0.0.0.0 |
Listen address |
apiBase |
https://api.commandcode.ai |
CC API base URL |
projectSlug |
cc-proxy |
x-project-slug header |
logFile |
"" |
Log file path (empty = console only) |
logLevel |
info |
Log level |
useProviderModels |
true |
Dynamically fetch model list from Provider API |
modelRefreshIntervalMs |
300000 |
Model list cache refresh interval (5 min) |
| Variable | Overrides |
|---|---|
PORT |
port |
HOST |
host |
CC_API_BASE |
apiBase |
PROJECT_SLUG |
projectSlug |
LOG_FILE |
logFile |
CC_USE_PROVIDER_MODELS |
useProviderModels |
OpenAI Chat Completions compatible. Supports streaming, non-streaming, tool calling, multimodal image input, and reasoning effort.
Request parameters:
| Parameter | Required | Description |
|---|---|---|
model |
Yes | Model ID (see model list) |
messages |
Yes | Conversation messages, supports system/user/assistant/tool roles |
max_tokens |
No | Max tokens to generate (default 64000) |
stream |
No | SSE streaming (default false) |
temperature |
No | Sampling temperature (0-2) |
reasoning_effort |
No | Reasoning intensity: low/medium/high/max |
tools |
No | Tool definitions (OpenAI function calling format) |
tool_choice |
No | Tool selection strategy |
parallel_tool_calls |
No | Allow parallel tool calls |
Simple request:
{
"model": "deepseek/deepseek-v4-flash",
"messages": [{ "role": "user", "content": "hello" }],
"stream": true
}Multimodal image input (vision model required):
{
"model": "xiaomi/mimo-v2.5",
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "Describe this image" },
{ "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,..." } }
]
}]
}Tool calling:
{
"model": "deepseek/deepseek-v4-flash",
"messages": [...],
"tools": [{
"type": "function",
"function": { "name": "get_weather", "description": "...", "parameters": {...} }
}],
"tool_choice": "auto"
}Streaming response (SSE):
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","reasoning_content":"thinking..."}}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"}}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":20,"total_tokens":30,"prompt_tokens_details":{"cached_tokens":8}}}
data: [DONE]
Non-streaming response (with cache hits):
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1234567890,
"model": "deepseek/deepseek-v4-flash",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello!",
"reasoning_content": "The user said hello, I should respond."
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 7558,
"completion_tokens": 42,
"total_tokens": 7600,
"prompt_tokens_details": { "cached_tokens": 7552 }
}
}Anthropic Messages API compatible endpoint. Supports streaming, non-streaming, and tool calling.
Request body:
{
"model": "claude-sonnet-4-6",
"max_tokens": 1000,
"system": "You are a helpful assistant.",
"messages": [
{ "role": "user", "content": "hello" }
],
"stream": true
}Anthropic protocol conversion (automatic):
| Concept | Anthropic Format | Conversion |
|---|---|---|
| System prompt | Top-level system field |
Auto-converted to OpenAI system message |
| Message content | content array (text/tool_use/tool_result) |
Auto-mapped to corresponding roles |
| Tool results | tool_result blocks in user messages |
Auto-converted to role: "tool" |
| Tool definitions | input_schema |
Auto-mapped to parameters |
tool_choice |
{type:"auto"/"any"/"tool"} |
any→required, tool→function object |
| Reasoning | thinking.budget_tokens |
Auto-mapped to reasoning_effort (≥10000→high, ≥5000→medium, ≥2000→low) |
| Stop reason | end_turn/max_tokens/tool_use |
Auto-mapped to stop/length/tool_calls |
| Token usage | input_tokens/output_tokens + cache |
Passed through, cache fields mapped to Anthropic format |
Streaming response (SSE, Anthropic format):
event: message_start
data: {"type":"message_start","message":{"id":"msg_xxx","type":"message","role":"assistant","content":[],"model":"...","usage":{"input_tokens":0,"output_tokens":0}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":10,"cache_read_input_tokens":0,"input_tokens":100}}
event: message_stop
data: {"type":"message_stop"}
Non-streaming response:
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"model": "deepseek/deepseek-v4-flash",
"content": [{ "type": "text", "text": "Hello!" }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 7558,
"output_tokens": 42,
"cache_read_input_tokens": 7552,
"cache_creation_input_tokens": null
}
}Returns available model list. Fetched dynamically from Provider API (5 min cache), falls back to hardcoded list on failure.
Health check. Returns OK.
| HTTP Status | Description |
|---|---|
| 400 | Invalid request format |
| 401 | API Key missing / invalid format / rejected (Key must start with user_) |
| 429 | Rate limited (includes retry_after field) |
| 502 | CC upstream error |
| 503 | Service temporarily unavailable |
The proxy returns a live model list via GET /v1/models. Below are common models for reference; the actual list depends on the live API response — see Command Code Pricing for plan details.
| Model ID | Description | Features |
|---|---|---|
deepseek/deepseek-v4-flash |
DeepSeek V4 Flash | Fast, general-purpose |
deepseek/deepseek-v4-pro |
DeepSeek V4 Pro | High-precision reasoning |
claude-sonnet-4-6 |
Claude Sonnet 4.6 | Long context |
claude-opus-4-8 |
Claude Opus 4.8 | Best reasoning |
moonshotai/Kimi-K2.5 |
Kimi K2.5 | Multimodal / frontend |
xiaomi/mimo-v2.5 |
MiMo V2.5 | Image input supported |
Qwen/Qwen3.7-Max |
Qwen 3.7 Max | Large parameters |
google/gemini-3.5-flash |
Gemini 3.5 Flash | Reasoning model |
⚠️ Some models (e.g.deepseek-v4-flash,claude-sonnet-4-6) do not support image input. Usexiaomi/mimo-v2.5,Kimi-K2.5, or other vision models for multimodal.
from openai import OpenAI
client = OpenAI(
api_key="user_xxxxxxxxx",
base_url="http://127.0.0.1:3050/v1",
)
response = client.chat.completions.create(
model="deepseek/deepseek-v4-flash",
messages=[{"role": "user", "content": "hello"}],
stream=True,
)
for chunk in response:
print(chunk.choices[0].delta.content or "", end="")curl http://127.0.0.1:3050/v1/chat/completions \
-H "Authorization: Bearer user_xxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4-flash",
"messages": [{"role": "user", "content": "hello"}],
"stream": true
}'Add a Custom Provider in Cursor settings:
- API Base URL:
http://127.0.0.1:3050/v1 - API Key:
user_xxxxxxxxx - Model: Choose from the model list
import anthropic
client = anthropic.Anthropic(
api_key="user_xxxxxxxxx",
base_url="http://127.0.0.1:3050",
)
message = client.messages.create(
model="deepseek/deepseek-v4-flash",
max_tokens=1000,
system="You are helpful.",
messages=[{"role": "user", "content": "hello"}],
)
print(message.content[0].text){
"provider": "openai-compatible",
"baseUrl": "http://127.0.0.1:3050/v1",
"apiKey": "user_xxxxxxxxx"
}Based on analysis of official CLI v0.32.3 traffic:
| Mechanism | Implementation |
|---|---|
| Per-Key Session | One session per API key, 12h expiry + 1h random jitter |
| Version | x-command-code-version auto-fetched from npm registry (24h refresh) |
| CLI Envelope | config/memory/taste/permissionMode/params/threadId |
| OpenTelemetry | traceparent (W3C Trace Context) |
| Environment | x-cli-environment: production |
| Project Slug | Custom x-project-slug |
| Reasoning Effort | reasoning_effort pass-through (low/medium/high/max) |
| Key Validation | Regex user_[a-zA-Z0-9_-]+, auto-cleans extra paths/prefixes, rejects sk-xxx format |
| Stream Timeout | 30s streaming / 90s non-streaming auto-abort on idle |
{
"config": {
"workingDir": "C:\\project",
"date": "2026-06-07",
"environment": "win32-x64, Node.js v24.16.0",
"structure": [],
"isGitRepo": false,
"currentBranch": "",
"mainBranch": "",
"gitStatus": "",
"recentCommits": []
},
"memory": "",
"taste": "",
"skills": "",
"permissionMode": "standard",
"params": {
"model": "deepseek/deepseek-v4-flash",
"messages": [...],
"max_tokens": 64000,
"stream": true,
"reasoning_effort": "max"
},
"threadId": "<uuid>"
}The CLI sends images in this format:
{
"role": "user",
"content": [
{ "type": "image", "image": "data:image/jpeg;base64,..." },
{ "type": "text", "text": "What does this image say?" }
]
}The proxy receives OpenAI image_url format and converts it to the above CC format transparently.
This project is for educational and research purposes only.
- Unofficial: This project is not affiliated with Command Code in any way.
- Personal Use: Users assume all responsibility. Please comply with the Command Code Terms of Service.
- API Key: This project does not collect, upload, or leak your API Key. The key must be sent in every request via the
Authorization: Bearer <key>header and is never stored in configuration. - Compliance: The protocol is based on passive observation of local CLI network traffic. No unauthorized access, cracking, or tampering of the server has been performed.
- Account Risk: Keep usage frequency consistent with normal CLI usage. Extremely high concurrent calls may trigger risk controls.
# Start with watch mode (auto-reload on file changes)
npm run dev