Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

cmdcode

A local, multi-provider LLM gateway with taste injection. Speak five protocols in, route to any number of upstream providers out — Command Code, OpenAI-compatible endpoints, native Anthropic and native Gemini — with hot-reloadable config and no vendor lock-in.

What it does

 five protocols in upstream adapters
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ /v1/chat/completions (OpenAI) │ │ command-code (CLI fingerprint) │
│ /v1/messages (Anthropic)│ │ openai (any compatible) │
│ …:generateContent (Gemini) │ ─>│ anthropic (native Messages) │
│ /v1/responses (Responses)│ │ gemini (native generate) │
│ /api/chat, /api/tags (Ollama) │ └────────────┬─────────────────────┘
└─────────────────────────────────┘ │
taste injection · rate limiting · session store
▼
providers.json — any mix, hot reload

Providers are declared in ~/.cmdcode/providers.json, mirroring opencode's provider map. Models route to the provider that declares them; undeclared models fall back to the first enabled entry. Edits apply on the next request — no restart.

Quick start

Prerequisites

No external CLI required. The model catalog is bundled in the binary. Taste files live at ~/.commandcode/taste/taste.md (created by the agent during conversations, or managed via cmdcode taste).

Install

# From crates.io (requires Rust 1.75+)
cargo install cmdcode
# Or build from source
git clone https://github.com/Lythaeon/cmdcode.git
cd cmdcode
cargo install --path crates/cmdcode-cli

Sign in

cmdcode auth

This opens an interactive TUI where you can:

  • Sign in a new account — prints a Studio auth link; after signing in in the browser, the Studio POSTs your API key back to the local callback server automatically. You can also paste a key directly.
  • Switch active account — the proxy reads the active credential on every request refresh (no restart needed).
  • Log out — remove one or more accounts from the vault.

Credentials are backed up to ~/.cmdcode/accounts.json (chmod 0600). The proxy's AuthManager reads the active account from this vault, falling back to the legacy ~/.commandcode/auth.json if the vault is empty.

Run

cmdcode serve
# listening on http://127.0.0.1:18080

Test

curl http://127.0.0.1:18080/health
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"xiaomi/mimo-v2.5","messages":[{"role":"user","content":"Hello"}]}'

Commands

CommandDescription
cmdcode serveStart the proxy server
cmdcode authInteractive TUI: manage accounts (list/use/logout/add, auto-rotate toggle)
cmdcode statusCheck auth and model catalog status
cmdcode modelsList available models
cmdcode configShow current configuration
cmdcode testSend a test request to verify proxy
cmdcode connectInteractive TUI: manage upstream providers (add/enable/disable/remove/test)
cmdcode connect add / remove <id> / enable <id> / disable <id> / test <id> / listNon-interactive provider management
cmdcode setupConfigure client harnesses

Multi-account & auto-rotate

Store multiple Command Code accounts and switch between them without restarting the proxy:

cmdcode auth # TUI: list, use, logout, add
cmdcode auth use # switch active account (TUI select)
cmdcode auth logout# remove accounts (TUI multi-select)

Enable auto-rotate to switch accounts automatically when one hits its credit limit or is rejected:

cmdcode auth # select "Auto-rotate: ON" in the TUI

The proxy reads the active credential from ~/.cmdcode/accounts.json on each TTL refresh — switching accounts takes effect within seconds without a restart. When auto-rotate is enabled and the upstream rejects the account (401/403/429, or a 400 "insufficient credits" response), the proxy rotates to the next account and retries the request.

Taste MCP Server

A standalone MCP server (cmdcode-mcp) exposes the taste tool for agents, replicating command-code's built-in taste learning — fully decoupled from the command-code CLI.

Add to your opencode config (~/.config/opencode/opencode.json):

{
"mcp": {
"cmdcode-taste": {
"type": "local",
"command": ["/path/to/cmdcode-mcp"],
"enabled": true
}
}
}

The server reads taste files from ~/.commandcode/taste/ and sends learning requests to whichever upstream is configured for it: by default the Command Code /alpha/generate endpoint (free — no credit cost); if your providers.json flags an entry with "learning": true, that provider is used instead (OpenAI-compatible chat completions). Results are written back to the same taste files.

The MCP binary also reads CMDCODE_PROVIDERS_CONFIG to point at an alternative providers config.

Usage:

# Build
cargo build --release -p cmdcode-mcp
# Test MCP handshakeecho'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}},"id":1}'| ./target/release/cmdcode-mcp

Features

  • Multi-provider upstreams — four adapter types: command-code (CLI fingerprint, vault auth + rotation), openai (any compatible endpoint), anthropic (native Messages API), gemini (native generateContent)
  • Five protocol frontends — OpenAI /v1/chat/completions, Anthropic /v1/messages, Gemini :generateContent[:stream], OpenAI Responses /v1/responses, Ollama-native /api/chat — every frontend works against every configured upstream
  • Responses session store — server-side previous_response_id chaining with TTL + entry cap; entries stored only after confirmed completion
  • Hot reload — provider edits apply on the next request; broken config files retain the last-good router
  • Runtime enable/disable"enabled": false per provider; toggled via CLI or TUI; all-disabled yields a clean 503
  • Terminal-chunk dedup — duplicate upstream terminal events never reach the client (streaming validators reject them)
  • Streaming — full SSE/NDJSON translation: text, reasoning/thinking, tool-call deltas across every frontend/upstream pair
  • Tool calls — function calling translated across all protocol combinations (nested ↔ flat schemas, tool_result ↔ tool role)
  • Multi-account auth — vault at ~/.cmdcode/accounts.json with TUI management, auto-rotate on credit limits, no proxy restart needed
  • Rust + Pingora — production-grade, sub-millisecond overhead
  • CLI fingerprint — sends the exact headers/body the cmd CLI sends
  • Auto-discovery — model catalog parsed from CLI's bundled models.md
  • Reasoning effortlow/medium/high/xhigh/max support
  • Retry logic — automatic retry on transient upstream failures (502/503/504)
  • Health checkGET /health for monitoring
  • CORS — optional CORS headers for browser clients
  • Concurrency — Pingora handles multiple simultaneous agents
  • Rate limiting — configurable per-key rate limits (local or Redis backend)
  • Security — zeroize, newtypes, constant-time comparison, CRLF sanitization
  • Harness auto-detection — OpenCode, Codex, Hermes, LiteLLM, Ollama, vLLM, Open WebUI
  • Fuzz targets — 14 fuzz targets covering wire format, auth, rate limiting, and harness types

Configuration

Env varDefaultDescription
COMMAND_CODE_PROXY_PORT18080Listen port
COMMAND_CODE_PROXY_HOST127.0.0.1Bind address
COMMAND_CODE_API_BASEhttps://api.commandcode.aiCommand Code API base
CMDCODE_PROVIDERS_CONFIG~/.cmdcode/providers.jsonProviders map path
COMMAND_CODE_PROXY_PROVIDERcommand-codeEnv-only adapter (command-code or openai)
COMMAND_CODE_UPSTREAM_API_KEY(unset)Bearer key for the env-only openai adapter
COMMAND_CODE_PROXY_TIMEOUT600Upstream timeout (seconds)
COMMAND_CODE_PROXY_RETRIES2Retry count for transient failures
COMMAND_CODE_PROXY_CORS(unset)CORS origin header
COMMAND_CODE_PROXY_DEFAULTxiaomi/mimo-v2.5Default model
COMMAND_CODE_PROXY_MODELS(unset)Comma-separated model allowlist
COMMAND_CODE_AUTH_DIR~/.commandcodeLegacy auth directory (vault at ~/.cmdcode is preferred)
COMMAND_CODE_ACCOUNTS_FILE~/.cmdcode/accounts.jsonMulti-account vault path
COMMAND_CODE_PROXY_LOG_FILE(unset)Log file with size-based rotation
COMMAND_CODE_PROXY_LOG_MAX_BYTES52428800Rotate after this many bytes
COMMAND_CODE_PROXY_LOG_KEEP5Rotated log backups to keep
COMMAND_CODE_PROXY_INCOMING_TOKEN(unset)Require bearer token on API routes
COMMAND_CODE_PROXY_TLS_CERT(unset)TLS cert path (with KEY enables HTTPS)
COMMAND_CODE_PROXY_TLS_KEY(unset)TLS key path
COMMAND_CODE_PROXY_RATE_LIMIT_MAX100Max requests per window per key (0 = unlimited)
COMMAND_CODE_PROXY_RATE_LIMIT_WINDOW60Rate limit window in seconds
COMMAND_CODE_PROXY_RATE_LIMIT_BACKENDlocalRate limit backend (local or redis)
COMMAND_CODE_PROXY_RATE_LIMIT_REDIS_URL(unset)Redis URL for distributed rate limiting

Providers

Declared in ~/.cmdcode/providers.json (override with CMDCODE_PROVIDERS_CONFIG). Each entry supports:

FieldDescription
typeAdapter: command-code, openai, anthropic, or gemini
options.baseURLUpstream base URL (adapter-specific default if omitted)
options.apiKeyAPI key — inline value or {env:VAR} reference (preferred for secrets)
modelsModel ids this provider serves (routes + /v1/models listing)
learningServe taste-learning requests from the MCP server
enabledfalse removes it from routing without deleting the entry

The first enabled entry is the fallback for undeclared models. Edits apply on the next request (hot reload); a broken config file keeps the last-good router. Manage entries with cmdcode connect instead of hand-editing.

Endpoints

MethodPathDescription
GET/v1/modelsList available models
GET/healthHealth check (status, version, upstream)
GET/metricsPrometheus-formatted metrics
POST/v1/chat/completionsOpenAI chat completion (stream + non-stream)
POST/v1/messagesAnthropic messages API (stream + non-stream)
POST/v1/responsesOpenAI Responses API (with previous_response_id session chaining)
POST…:generateContent / …:streamGenerateContentGoogle Gemini
GET/POST/api/tags, /api/chatOllama native

See Setup guide for supervision, log rotation, and soak tooling.

Wire it into OpenCode

Add to your opencode.json:

{
"provider": {
"command-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Command Code",
"options": {
"baseURL": "http://localhost:18080/v1"
},
"models": {
"xiaomi/mimo-v2.5": { "name": "MiMo V2.5", "reasoning": true },
"gpt-5.6-luna": { "name": "GPT-5.6 Luna", "reasoning": true }
}
}
},
"model": "default"
}

Wire it into anything

Python:OpenAI(base_url="http://127.0.0.1:18080", api_key="not-needed")

Node.js:new OpenAI({ baseURL: "http://127.0.0.1:18080", apiKey: "not-needed" })

LiteLLM:api_base: http://127.0.0.1:18080, api_key: not-needed

Documentation

License

MIT

About

Local multi-provider LLM gateway: 5 protocol frontends (OpenAI, Anthropic, Gemini, Responses, Ollama) → hot-reloadable upstream routing (command-code, openai-compat, anthropic-native, gemini-native) with taste injection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages