OpenAI-compatible gateway for trusted CommandCode deployments.
CommandCode Bridge is a trusted-environment HTTP bridge that exposes a small OpenAI-compatible API for a CommandCode account. It lets local, LAN, VPN, or tailnet clients call CommandCode-backed models through standard /v1/models and /v1/chat/completions endpoints.
CommandCode required. This project is not a public standalone DeepSeek proxy and does not include or repackage CommandCode's CLI bundle. You need the official CommandCode CLI/account environment (
cmdfrom thecommand-codenpm package) or equivalent CommandCode API credentials. Install/authenticate CommandCode from the official site: https://commandcode.ai/install.
Status. Internal/trusted-environment bridge. The upstream CommandCode
/alpha/generatepath behaves like an alpha/internal API and may change.
| Area | Summary |
|---|---|
| API surface | /health, /dashboard, /v1/models, /v1/chat/completions, and redacted admin diagnostics. |
| Core value | OpenAI-compatible clients can use CommandCode-backed models without spawning cmd per request. |
| Routing | Multi-key credential selection with daily-burn, balance-priority, round-robin, and drain-first policies. |
| Operations | Mobile-first dashboard for bind settings, routing, credentials, model toggles, diagnostics, save, restart, and Korean/English/Chinese UI. |
| Safety boundary | No upstream secrets are bundled; expose only on localhost or a trusted VPN/tailnet/private proxy. |
One-shot smoke test after install:
BRIDGE=http://127.0.0.1:9992; \
curl -fsS "$BRIDGE/health" && echo && \
curl -fsS "$BRIDGE/v1/models" | head -c 400A healthy bridge returns JSON health/version data and a non-empty OpenAI-compatible model list. Run a chat completion only after confirming your CommandCode account has usable credits.
- Provides OpenAI-compatible endpoints:
GET /healthGET /dashboardGET /v1/modelsPOST /v1/chat/completionsGET /admin/configandGET /admin/commandcode/credentialsfor redacted read-only dashboard statePUT /admin/configandPOST /admin/restartfor authenticated dashboard writes/restart
- Converts CommandCode streaming events into OpenAI chat completion responses or SSE chunks.
- Supports non-streaming and streaming OpenAI clients, including usage chunks for
stream_options.include_usage. - Supports tool calls emitted by CommandCode and maps them back to OpenAI
tool_calls. - Supports
developer,system,user,assistant, andtoolmessages. - Hides reasoning deltas by default (
INCLUDE_REASONING=false). - Fails closed on empty visible
finish_reason: lengthresponses by default instead of returning a blank success. - Loads CommandCode upstream credentials from a CLI auth file, a single API key, a multi-key env var, or a JSON credentials file.
- Includes a multi-key credential router with routing policies designed for rotating multiple CommandCode keys safely.
- Includes a mobile-first
/dashboardfor server bind settings, routing policy, key management, model toggles, diagnostics, JSON save, restart, and Korean/English/Chinese localization. - Includes optional balance alerts and an optional
commandcode-routerprocess for routing across multiple bridge hosts.
Current bridge version: v0.32.4.
The version is also returned from /health and shown in the top-right of the web dashboard.
This bridge release is aligned with the official command-code npm package 0.32.4:
- The default upstream
x-command-code-versionheader now advertises0.32.4unlessCOMMANDCODE_CLI_VERSIONoverrides it. - The bridge package/runtime version is also
0.32.4so/health, the dashboard, and the npm metadata match the CommandCode CLI version being targeted. - Direct inspection of the
command-code@0.32.4bundle confirmed that the bridge-critical API paths remain compatible:/alpha/generate,/alpha/whoami,/alpha/billing/credits,/alpha/billing/subscriptions, and/alpha/usage/summary. - The model catalog was checked against the
0.32.4CLI bundle. Existing enabled defaults stay conservative, while additional discovered entries such as Qwen 3.6 Max Preview, MiniMax M3, MiniMax M2.5, Kimi K2.5, Step 3.5 Flash, Gemini 3.5 Flash, Gemini 3.1 Flash Lite, GLM-5, GPT 5.4/5.3 Codex, and Claude 4.6/4.7/4.8 remain disabled by default unless explicitly enabled in config.
OpenAI-compatible client
-> CommandCode Bridge :9992
-> POST https://api.commandcode.ai/alpha/generate
-> CommandCode stream events
-> OpenAI chat.completion or chat.completion.chunk
The bridge does not spawn cmd for every request. It calls the same upstream API path used by the CommandCode CLI, then normalizes the response shape for OpenAI-compatible clients. This avoids CLI stdout parsing, reduces latency, and prevents CLI-side local tools/memory from inflating token usage.
A single chat-completion request stays bound to one upstream credential from start to finish. Parallelism comes from distributing independent requests across eligible keys and, optionally, across multiple bridge hosts.
- Node.js 20+
- npm 10+
- Linux, macOS, or WSL for manual/source operation
- Linux user systemd if you use the bundled
install.sh - Official CommandCode CLI (
cmd, npm packagecommand-code) or equivalent CommandCode upstream API key - A CommandCode account with usable balance/credits for real generation
The installer and manual setup are designed around three common states:
- CommandCode CLI is already installed and authenticated
- The bridge can import the existing
~/.commandcode/auth.jsoncredential as its first upstream key.
- The bridge can import the existing
- CommandCode CLI is installed but not authenticated
- Run
cmd login, then restart the bridge.
- Run
- CommandCode CLI is missing
- Install it first:
npm install -g command-code cmd login
- The Linux installer can offer to run
npm install -g command-codefor you when the CLI is missing.
- Install it first:
From a source checkout or package root:
./install.shThe installer:
- checks for Node.js, npm, user systemd, and CommandCode CLI;
- offers to install
command-codewith npm if the CLI is missing; - imports an existing CommandCode CLI auth key when available;
- generates a client-facing
BRIDGE_API_KEYif you do not provide one; - installs the bridge under
~/.local/share/commandcode-bridge; - writes private runtime env to
~/.config/commandcode-bridge/env; - creates a
commandcode-bridgeuser systemd service; - starts the service unless
--no-startis supplied.
Examples:
# Interactive, safe local-only default: 127.0.0.1:9992
./install.sh
# Non-interactive local install
./install.sh --yes --host 127.0.0.1 --port 9992
# Tailnet/LAN exposure; keep BRIDGE_API_KEY enabled
./install.sh --host 0.0.0.0 --port 9992Useful service commands:
systemctl --user status commandcode-bridge --no-pager
systemctl --user restart commandcode-bridge
journalctl --user -u commandcode-bridge -f
curl -fsS http://127.0.0.1:9992/health | jqIf the service must run before login on a Linux host:
sudo loginctl enable-linger "$USER"Uninstall while preserving private config:
./uninstall.shRemove service, installed files, and private config:
./uninstall.sh --purge-configgit clone <your-commandcode-bridge-repository-url> commandcode-bridge
cd commandcode-bridge
npm install --include=dev
cp .env.example .envEdit .env or export environment variables. Minimal local-only setup using the CommandCode CLI auth file:
HOST=127.0.0.1
PORT=9992
BRIDGE_API_KEY=replace-with-a-long-random-client-key
COMMANDCODE_ROUTING_POLICY=daily_burn_priority
COMMANDCODE_EMPTY_VISIBLE_RESPONSE_POLICY=error_on_lengthIf you prefer an explicit upstream key:
COMMANDCODE_API_KEY=your_commandcode_api_keyBuild and run:
npm run build
npm startDocker is supported for deployments that have a full source checkout. The Dockerfile runs the verification/build pipeline before producing the runtime image.
docker build -t commandcode-bridge .
docker run --rm -p 127.0.0.1:9992:9992 \
-e HOST=0.0.0.0 \
-e COMMANDCODE_API_KEY="$COMMANDCODE_API_KEY" \
-e BRIDGE_API_KEY="$BRIDGE_API_KEY" \
commandcode-bridgeOr use:
cd release
docker compose up -d --buildSee docs/DEPLOYMENT.md and release/docker-compose.yml for production details.
Health check:
curl -fsS http://127.0.0.1:9992/health | jqIf BRIDGE_API_KEY is configured, authenticated model list:
export BRIDGE_API_KEY='<same value as your bridge env>'
curl -fsS http://127.0.0.1:9992/v1/models \
-H "Authorization: Bearer $BRIDGE_API_KEY" | jqNon-streaming chat completion:
curl -sS http://127.0.0.1:9992/v1/chat/completions \
-H "Authorization: Bearer $BRIDGE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "default",
"messages": [{"role": "user", "content": "Reply exactly: OK"}],
"max_tokens": 64,
"temperature": 0
}' | jqStreaming:
curl -N http://127.0.0.1:9992/v1/chat/completions \
-H "Authorization: Bearer $BRIDGE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek/deepseek-v4-pro",
"stream": true,
"messages": [{"role": "user", "content": "Count to three."}],
"stream_options": {"include_usage": true}
}'Project smoke script:
npm run smokeThe smoke script reads .env, then the installed-service env file at ~/.config/commandcode-bridge/env on Linux or /Users/yorha/.config/commandcode-bridge/env on Yorha's macOS bridge host, then explicit shell variables. Set BRIDGE_ENV_FILE=/path/to/env when validating another installed bridge. Explicit shell values such as BRIDGE_BASE_URL and BRIDGE_API_KEY always win.
If the account is reachable but temporarily blocked by balance/credit, use the routing-only fail-closed smoke mode:
SMOKE_ACCEPT_UPSTREAM_ERRORS=1 npm run smokeThis mode confirms that the bridge surfaces explicit upstream/fail-closed errors instead of returning blank success. It is not a generation-readiness canary.
Open:
http://127.0.0.1:9992/dashboard
If the bridge is bound to 0.0.0.0 behind Tailscale/VPN/LAN, open:
http://<host-or-tailnet-ip>:9992/dashboard
The dashboard is intentionally mobile-first. It is useful from a phone on the same trusted tailnet.
- The dashboard ships with Korean, English, and Chinese UI strings.
- Korean is the hard fallback language. On first load, the dashboard chooses English or Chinese when the browser locale starts with
enorzh; otherwise it uses Korean. - Use the flag buttons beside the compact
CommandCode Bridgetitle to switch manually: 🇰🇷 Korean, 🇺🇸 English, 🇨🇳 Chinese. - The selected language is stored in browser
localStorage, so subsequent dashboard visits keep the operator preference. - Active language flags render in color; inactive language flags are desaturated/grayscale.
- Header
- Shows bridge online/offline state.
- Shows bridge version, for example
v0.32.4.
- Server Bind
- Choose
127.0.0.1for local-only use. - Choose
0.0.0.0only for LAN/Tailscale/VPN/reverse-proxy use. - Edit the port.
- Save/copy the browser-local Admin API Key for authenticated writes.
- Choose
- Routing Policy
- Select how eligible upstream keys are chosen.
- Edit the per-key concurrency limit. Routine default is 4 in-flight requests per key.
- Credentials
- Add, rename, enable/disable, delete, and refresh upstream CommandCode keys.
- The dashboard preserves existing secrets when you rename a key or leave the secret field blank.
- Billing/diagnostic data is redacted and shown as operator-friendly balance/day summaries.
- Models
- Toggle configured model catalog entries on/off.
- Changes require restart.
- Footer
Save JSONwrites the dashboard JSON config.Restart Bridgerestarts the LaunchAgent/system service path where supported.
GET /dashboard,GET /admin/config, and redactedGET /admin/commandcode/credentialscan be read withoutBRIDGE_API_KEYso a phone browser can load status and saved redacted state on a trusted network.- These public read-only dashboard endpoints are still metadata-bearing: they can reveal service version, bind/port, configured model IDs, credential IDs/previews, counts, and redacted balance summaries. Expose them only on localhost or a trusted VPN/tailnet.
- Writes and restarts require
BRIDGE_API_KEY:PUT /admin/configPOST /admin/restart- all
/v1/*inference calls whenBRIDGE_API_KEYis configured
- The dashboard never returns raw CommandCode upstream keys.
- The dashboard is not designed as a public internet control plane. It relies on a trusted network boundary plus bearer-token-protected writes, not cookie-based sessions.
- Change bind host, port, routing policy, credentials, or models.
- Click Save JSON.
- Click Restart Bridge.
- Verify
/healthand/v1/models.
If you rotate the client-facing bridge key, update any clients that use it. For Hermes, keep COMMANDCODE_BRIDGE_API_KEY and the bridge's BRIDGE_API_KEY in sync, then restart the Hermes gateway/session that uses the bridge. During a key rotation, clients that still hold the old key will receive 401 Unauthorized until they reload the new value.
The bridge loads upstream CommandCode credentials in this order:
COMMANDCODE_CREDENTIALS_FILECOMMANDCODE_CREDENTIALSorCOMMANDCODE_API_KEYS- legacy single-key
COMMANDCODE_API_KEY ~/.commandcode/auth.json~/.config/commandcode/auth.json
If multiple credentials are configured, /health reports only the count and routing policy. Raw keys are never included.
COMMANDCODE_API_KEY=your_commandcode_api_keyCOMMANDCODE_API_KEYS=primary=cmd_key_one,secondary=cmd_key_two
COMMANDCODE_ROUTING_POLICY=daily_burn_priorityRecommended for dashboard-managed or multi-key setups:
COMMANDCODE_CREDENTIALS_FILE=/home/you/.config/commandcode-bridge/credentials.jsonExample credentials.json:
{
"server": {
"host": "127.0.0.1",
"port": 9992
},
"routing": {
"policy": "daily_burn_priority",
"fallbackPolicy": "round_robin",
"maxInFlightPerCredential": 4,
"maxTotalInFlight": null,
"maxTotalInFlightMultiplier": 3
},
"models": [
{ "id": "deepseek/deepseek-v4-pro", "enabled": true },
{ "id": "deepseek/deepseek-v4-flash", "enabled": true },
{ "id": "MiniMaxAI/MiniMax-M2.7", "enabled": true },
{ "id": "Qwen/Qwen3.6-Plus", "enabled": true },
{ "id": "zai-org/GLM-5.1", "enabled": true },
{ "id": "moonshotai/Kimi-K2.6", "enabled": true },
{ "id": "openai/gpt-5.5", "enabled": false },
{ "id": "anthropic/claude-opus-4.7", "enabled": false },
{ "id": "anthropic/claude-sonnet-4.6", "enabled": false }
],
"credentials": [
{ "id": "primary", "apiKey": "cmd_key_one", "weight": 1, "enabled": true },
{
"id": "flash-only",
"apiKey": "cmd_key_two",
"weight": 1,
"enabled": true,
"allowedModels": ["deepseek/deepseek-v4-flash"]
}
]
}Protect it:
chmod 600 ~/.config/commandcode-bridge/credentials.jsonCommandCode Bridge can run with several upstream CommandCode keys and choose among them per request. This is the key operational feature: you can spread traffic, avoid hammering one key, and automatically skip unhealthy or expired credentials.
| Policy | Purpose |
|---|---|
daily_burn_priority |
Default. Prioritizes keys that need more daily usage before the current billing/credit period ends. Legacy depletion_aware is normalized to this policy. |
balance_priority |
Prefer keys with more usable balance. |
round_robin |
Rotate across eligible keys, respecting weight and availability. |
drain_first |
Use the first eligible key until it is blocked/exhausted, then move to the next. |
A credential can be skipped when it is:
- manually disabled in the dashboard/JSON;
- outside its
allowedModelsscope; - at the per-key in-flight limit;
- in cooldown after 429/5xx/timeouts;
- out of usable billing balance or expired for the current period.
If an upstream error arrives before visible output and another eligible credential exists, the bridge can retry/fail over. If visible output has already started, the bridge surfaces the error instead of retrying and risking duplicated partial output.
Routine default:
COMMANDCODE_MAX_IN_FLIGHT_PER_CREDENTIAL=4DeepSeek V4 Flash load testing was healthy at higher parallelism, but 4 in-flight requests per key is the recommended normal operating value. Increase only after observing diagnostics and upstream behavior.
-
Configure at least two credentials with distinct IDs.
-
Restart the bridge.
-
Refresh diagnostics:
curl -sS 'http://127.0.0.1:9992/admin/commandcode/credentials?refresh=true' \ -H "Authorization: Bearer $BRIDGE_API_KEY" | jq
-
Send several concurrent low-token requests.
-
Refresh diagnostics again and confirm different credentials show selection/in-flight movement.
-
Confirm all responses are either successful generations or explicit upstream/fail-closed errors.
Set BRIDGE_API_KEY to require clients to authenticate.
BRIDGE_API_KEY=replace-with-a-long-random-client-keyClients may send either:
Authorization: Bearer <BRIDGE_API_KEY>
or:
x-api-key: <BRIDGE_API_KEY>
/health intentionally remains unauthenticated and secret-free. Admin writes and /v1/* requests require the key when configured.
| Variable | Default | Description |
|---|---|---|
HOST |
127.0.0.1 |
Bind address. Use localhost unless behind VPN, tailnet, or reverse proxy. |
PORT |
9992 |
HTTP port. |
BRIDGE_API_KEY |
unset | Client-facing API key. Strongly recommended; required for admin writes. |
COMMANDCODE_API_KEY |
unset | Legacy single upstream CommandCode key. |
COMMANDCODE_API_KEYS |
unset | Comma-separated multi-key list such as primary=...,secondary=.... |
COMMANDCODE_CREDENTIALS |
unset | JSON credentials array/object or comma-separated multi-key list. |
COMMANDCODE_CREDENTIALS_FILE |
unset | JSON dashboard/credential file. Highest upstream credential precedence. |
COMMANDCODE_ROUTING_POLICY |
daily_burn_priority |
daily_burn_priority, balance_priority, round_robin, or drain_first. depletion_aware is accepted as a legacy alias. |
COMMANDCODE_MAX_IN_FLIGHT_PER_CREDENTIAL |
4 |
Per-key concurrency cap. |
COMMANDCODE_MAX_TOTAL_IN_FLIGHT |
unset | Optional explicit total in-flight cap. |
COMMANDCODE_MAX_TOTAL_IN_FLIGHT_MULTIPLIER |
3 |
Legacy/default multiplier used when an explicit total cap is not set. |
COMMANDCODE_BILLING_REFRESH_MS |
300000 |
Billing/usage cache TTL for routing diagnostics. |
COMMANDCODE_BILLING_TIMEOUT_MS |
10000 |
Billing probe timeout. |
COMMANDCODE_CREDENTIAL_COOLDOWN_MS |
60000 |
Cooldown after upstream failures. |
COMMANDCODE_API_BASE |
https://api.commandcode.ai |
Upstream API base. Do not change unless testing a known alternate upstream. |
COMMANDCODE_DEFAULT_MODEL |
deepseek/deepseek-v4-pro |
Model used for default. |
COMMANDCODE_ALLOWED_MODELS |
Pro + Flash/catalog defaults | Comma-separated allowlist. |
COMMANDCODE_ALLOW_UNKNOWN_MODELS |
false |
Pass arbitrary model IDs upstream. Not recommended. |
COMMANDCODE_CLI_VERSION |
0.32.4 |
Version header sent upstream. |
COMMANDCODE_TIMEOUT_MS |
300000 |
Upstream request timeout. |
COMMANDCODE_EMPTY_VISIBLE_RESPONSE_POLICY |
error_on_length |
error_on_length fails closed on empty visible finish_reason: length; allow preserves legacy blank success behavior. |
REQUEST_BODY_LIMIT_BYTES |
1048576 |
Fastify body limit. |
RATE_LIMIT_MAX |
60 |
Requests per rate-limit window. |
RATE_LIMIT_WINDOW |
1 minute |
Rate-limit window string. |
LOG_LEVEL |
info |
Fastify/Pino log level. |
CORS_ORIGIN |
unset | Optional CORS origin. |
INCLUDE_REASONING |
false |
Append reasoning deltas to visible output. Keep false for normal clients. |
COMMANDCODE_BALANCE_ALERT_ENABLED |
false |
Enables periodic balance alerts. Disabled by default. |
COMMANDCODE_BALANCE_ALERT_WEBHOOK_URL |
unset | Optional JSON webhook for alerts. |
Supported request fields:
modelmessagesstreammax_tokenstemperaturetop_pstoptoolswith function schemastool_choiceonly when omitted,"auto", or"none"response_format(json_object/json_schemareceive JSON-only prompt reinforcement)stream_options.include_usageuser
Unsupported forced tool selection returns unsupported_tool_choice because CommandCode /alpha/generate does not expose a stable forced-tool selector.
commandcode-router is a separate process for multi-host deployments. It preserves one /v1 endpoint while routing independent requests to the least-in-flight healthy bridge backend.
COMMANDCODE_ROUTER_BACKENDS=local=http://127.0.0.1:19992,pc2=http://<tailnet-ip>:9992
COMMANDCODE_ROUTER_BACKEND_MAX_INFLIGHT=1
COMMANDCODE_ROUTER_BACKEND_TIMEOUT_MS=300000
COMMANDCODE_ROUTER_HEALTH_TIMEOUT_MS=3000
COMMANDCODE_ROUTER_COOLDOWN_MS=60000Use this only when you operate more than one bridge host. For most users, the built-in multi-key credential router inside a single bridge process is enough.
npm install --include=dev
npm run typecheck
npm run lint
npm run format:check
npm test
npm run build
npm run verifynpm run verify runs typecheck, lint, format check, tests, and build.
- Do not expose the bridge to the public internet without TLS, authentication, and a trusted network boundary.
HOST=0.0.0.0means every interface on the machine. Use it only behind Tailscale/WireGuard/VPN/firewall/reverse proxy; it is not a security control by itself.- Prefer
127.0.0.1, Tailscale, WireGuard, a VPN, or a private reverse proxy. - Always set
BRIDGE_API_KEYfor non-localhost deployments. - Treat dashboard read-only endpoints as metadata-bearing even though they are redacted.
- Do not commit
.env,~/.commandcode/auth.json,credentials.json, upstream API keys, bridge keys, billing details, router backend topology, or dashboard-exported secrets. - Treat CommandCode credentials as personal upstream credentials.
- This repository does not include CommandCode's proprietary/UNLICENSED CLI bundle source.
- The bridge does not bypass CommandCode account limits, billing, rate limits, or terms.
- The bridge is not a general public proxy service.
See docs/SECURITY.md for more details. For private security reports, use the GitHub Security Advisory form at https://github.com/yelixir-dev/commandcode-bridge/security/advisories/new or email yelixir.dev@gmail.com.
/health is public. /v1/* requires BRIDGE_API_KEY when configured.
export BRIDGE_API_KEY='<same value as bridge env>'
curl -fsS http://127.0.0.1:9992/v1/models \
-H "Authorization: Bearer $BRIDGE_API_KEY" | jqThe client-facing key changed in the bridge, but the client still has the old key. For Hermes, keep these paired:
- bridge runtime env:
BRIDGE_API_KEY - Hermes env/client setting:
COMMANDCODE_BRIDGE_API_KEY
Update both and restart the bridge/Hermes gateway or session that loads the env.
Run:
cmd loginThen restart the bridge. Or provide COMMANDCODE_API_KEY, COMMANDCODE_API_KEYS, or COMMANDCODE_CREDENTIALS_FILE explicitly.
Use diagnostics:
curl -sS 'http://127.0.0.1:9992/admin/commandcode/credentials?refresh=true' \
-H "Authorization: Bearer $BRIDGE_API_KEY" | jqFor bridge behavior testing only:
SMOKE_ACCEPT_UPSTREAM_ERRORS=1 npm run smokeReal generation readiness requires a normal smoke without that flag.
Most dashboard changes write JSON and require restart. Click Restart Bridge, or restart your service manually.
lsof -nP -iTCP:9992 -sTCP:LISTEN
# or on Linux
ss -ltnp '( sport = :9992 )'Stop the conflicting process or change PORT.
Contributions are welcome when they preserve the bridge's trust boundary: no bundled upstream secrets, no public-internet-by-default exposure, and no CommandCode CLI redistribution. Before opening a change, run:
npm run verifyFor security-sensitive changes, read docs/SECURITY.md first and avoid including credentials, local env files, private topology, or billing details in issues, logs, screenshots, or fixtures.
README.ko.md— Korean README.docs/DEPLOYMENT.md— deployment and operations guide.docs/DEPLOYMENT.ko.md— Korean deployment and operations guide.docs/ARCHITECTURE.md— architecture and data flow.docs/KNOW_HOW.md— CommandCode API notes and operational lessons.docs/SECURITY.md— security model and deployment guardrails.docs/PRD.md— product requirements.docs/IMPLEMENTATION_PLAN.md— implementation plan.docs/PROCESS_LOG.md— work log.
MIT. CommandCode itself is separate software and may have different terms.
