Command Code (CLI + Provider API)
Reference for Command Code (commandcode.ai): the cmd coding CLI and its OpenAI-compatible Provider API. Read this before any Command Code adapter, headroom or fleet work.
Every claim carries a tag. VERIFIED means measured on the developer machine on 2026-09-17 against a live individual GOAT subscription with CLI v1.54.2, unless the line names a later date. DOCS means vendor documentation or the shipped bundle, not exercised live. Where the two disagree, the measurement wins and the disagreement is recorded under Documented disagreements. The 2026-09-19 re-check of a second session's findings is its own section, 2026-09-19 re-verification.
No account state lives in this file: no key, no user name, no subscription id, no balance. The key is stored by the CLI in ~/.commandcode/auth.json (mode 0600) and mirrored into the repo's gitignored .env as CMD_API_KEY.
Official docs: https://commandcode.ai/docs, Provider API: https://commandcode.ai/docs/provider-api, changelog: https://commandcode.ai/changelog.
Two integration seams
| Seam | Wire | Cyberine shape | Status |
|---|---|---|---|
| Provider API | OpenAI Chat Completions at https://api.commandcode.ai/provider/v1 | LoopAgentAdapter (loop-commandcode-build) | shipped 2026-09-17 (kd5f6) |
cmd CLI | headless NDJSON (cmd -p --output-format json) | CliAgentAdapter factory makeCommandCodeAdapter (command-code) | surface VERIFIED; worker built 2026-09-17 after the km3ga bake-off (kd823), verified offline only |
One account is one credit pool shared by both seams. A CLI worker and a loop worker draw on the same rolling windows.
Plans and entitlement
- VERIFIED: the GOAT plan (
planId: individual-goat) has Provider API access. Every endpoint below answered on it. - DOCS: every plan except Go has API access; a Go plan calling the API gets
403 upgrade_required. - VERIFIED: Anthropic models are NOT on GOAT. Calling one returns a
permission_errorwith aMODEL_NOT_IN_PLAN:message (DOCS: Pro and above, or extra on-demand usage). - VERIFIED: GOAT caps are 14 credits per rolling 5 hours, 35 per rolling week, and a monthly pool of 70. The caps read back from the billing endpoint match the docs exactly.
Provider API
Endpoints and auth
| Endpoint | Shape | Tag |
|---|---|---|
POST /provider/v1/chat/completions | OpenAI Chat Completions | VERIFIED |
POST /provider/v1/messages | Anthropic Messages | VERIFIED (reachable; its models are off-plan on GOAT) |
GET /provider/v1/models | {id, object, created, owned_by, name, context_length} entries | VERIFIED |
- VERIFIED:
Authorization: Bearerwith the account key.x-api-keyis also accepted on/messages. - VERIFIED: the same key authenticates the CLI and the API.
- VERIFIED: responses carry
x-trace-idon every call and are served through Cloudflare. They carry NOx-ratelimit-*headers and NO cost headers, so headroom must be polled or parsed out of a refusal. - VERIFIED:
/provider/v1/usage,/credits,/me,/account,/keyand/limitsall return 404. The documented API has no billing surface.
Tool calling
- VERIFIED: a
tools+tool_choice: "auto"request to/chat/completionson a free model returnedfinish_reason: "tool_calls"with a well-formedmessage.tool_calls[](id,type: "function",function.name,function.argumentsas a JSON string).LoopAgentAdaptercan run against this endpoint. - VERIFIED: non-standard extras appear in the payload and are tolerated by the
openaiSDK:choices[].delta: nullon a NON-streaming reply,matched_stop,lastOne, andmessage.reasoning_contentcarrying the chain of thought. - VERIFIED 2026-09-17 through
loop-commandcode-build: streaming (stream: truewithstream_options.include_usage) and full multi-turn tool loops to completion. A one-file implement-task run ondeepseek/deepseek-v4-flashfinished all three steps (design, implement, review) with 965,446 input and 13,655 output tokens, 87-93% of input served from cache, and drew 0.0326 credits. - NOT TESTED: images (DOCS: accepted; audio, file and document parts are rejected by the schema).
Usage and cache accounting
- VERIFIED:
/chat/completionsusage carriesprompt_tokens_details.cached_tokensandcache_creation_input_tokens, so the cache-hit rate is measurable per request.
Error envelopes
| Case | Status | Body | Tag |
|---|---|---|---|
| Anthropic model on GOAT | error | {"type":"error","error":{"type":"permission_error","message":"MODEL_NOT_IN_PLAN: ..."}} | VERIFIED |
Claude id sent to /chat/completions | 400 | invalid_request_error, code: "unsupported_model", message says it must be called via /provider/v1/messages | VERIFIED |
| Unknown model id | 400 | invalid_request_error, code: "unsupported_model", message Model "..." is not supported on this endpoint. | VERIFIED |
| Unregistered route | 404 | {"success":false,"status":404,"message":"404 Not found...","cause":"... is not a registered API route"} | VERIFIED |
| Go plan calling the API | 403 | upgrade_required | DOCS |
| Zero data retention with no ZDR upstream | 422 | cmd_zdr_no_providers | DOCS |
| Usage window exhausted | 429 | RATE_LIMITED plus a rateLimit object (below) | DOCS (read from the CLI bundle, never provoked live) |
Classification rules an adapter must follow:
MODEL_NOT_IN_PLANis a PERMISSION error, not a billing error. Treat the worker as unavailable for the whole run and never retry it.unsupported_modelmeans a wrong endpoint for the id (aclaude-*id belongs on/messages) or an unknown id. Not retryable.- A 429 is a window exhaustion that reopens at a fixed timestamp named in the payload. Park until then; blind backoff wastes the interval.
The 429 payload
DOCS (from the CLI's own handler in its shipped bundle, not provoked live). The CLI keys on code === "RATE_LIMITED" or status 429 and then reads:
- The bundle reads the fields below off the response body's
errorobject (error.rateLimit), and the code from the transport error orerror.code. Cyberine also accepts a top-levelrateLimitby rewrapping such a body undererror. rateLimit.window:"fiveHour"or"weekly"; the bundle also recognises"daily".rateLimit.reset: epoch SECONDS (the CLI multiplies it by 1000).rateLimit.model: optional, present when the limit is per model (the CLI then says "today's limit on ").- When the object is missing it falls back to the human message:
/usage limit for your plan/inames the window (weeklywhen the text says so, otherwise the 5-hour one), andresets at <ISO timestamp>gives the reset.
Undocumented /alpha billing endpoints
VERIFIED live, but found in the CLI bundle rather than in the docs. The /alpha prefix marks them unstable: every caller must degrade to headroom-unknown on a 404 or a shape change, never crash.
| Endpoint | Returns |
|---|---|
GET https://api.commandcode.ai/alpha/billing/credits | credits.{monthlyCredits, purchasedCredits, freeCredits, belowThreshold, creditThreshold} and windowLimits.{limited, exceeded, fiveHour, weekly}, each window {used, cap, exceeded, resetAt} |
GET https://api.commandcode.ai/alpha/usage/summary | totalCount, totalCost, averageCost, successRate, completedCount, failedCount, totalTokensIn, totalTokensOut, totalTokens, totalCredits, totalFreeCredits, totalMonthlyCredits, totalPurchasedCredits, periodBasis |
GET https://api.commandcode.ai/alpha/billing/subscriptions | status, planId, currentPeriodStart, currentPeriodEnd, cancelAtPeriodEnd, quantity, orgId, pendingPhase |
- VERIFIED:
credits.monthlyCreditsis REMAINING and counts DOWN from the pool; it moves at roughly 1e-10 precision, which makes per-run credit deltas exact. - VERIFIED:
resetAton the billing endpoint is epoch MILLISECONDS. UNIT TRAP: the 429 body'srateLimit.resetis SECONDS.
Cost model
- VERIFIED on
meituan/LongCat-2.0:free: a free model costs exactly zero credits. A full headless CLI run on it (51,610 input tokens, one tool call) leftmonthlyCreditsandfiveHour.usedbyte-identical before and after. - VERIFIED 2026-09-17 (kp1nc) on all three free models through
loop-commandcode-build: FLEET-BENCH batches of about 454,000, 765,000 and 661,000 input tokens leftmonthlyCreditsandfiveHour.usedbyte-identical. - VERIFIED 2026-09-17 (kp1nc): the free daily cap is per model per account and is not specific to Ling.
meituan/LongCat-2.0:freeanswered HTTP 429 with{"error":{"message":"You've used all 100 free LongCat 2.0 requests for today. Your quota resets at 2026-09-17T00:00:00.000Z. Run /model or -m to pick another model.","type":"rate_limit_error","code":"RATE_LIMITED"}}: norateLimitobject and no rate-limit headers, the reset only in the message text. - VERIFIED 2026-09-17 (kp1nc):
poolside/laguna-s-2.1-freeanswered429 Upstream model provider is temporarily unavailable. Please try again in a moment.on every request for stretches of more than ten minutes, with no reset time. Treat it as capacity, not quota. - DOCS: free models keep working after a paid window closes;
inclusionai/ling-3.0-flash-sante:freeis capped at about 100 requests a day; all free models are offered while capacity lasts. - Derived from the VERIFIED caps: on paid models the binding constraint for parallel work is the 14-credit rolling 5-hour window, shared by every worker on the account.
- NOT TESTED: any concurrency or requests-per-minute ceiling (none documented, no header), and behaviour at an exhausted window.
Model catalog
The catalog rotates (deals carry expiry dates), so no model table is kept here. The live sources are GET /provider/v1/models and cmd --list-models.
Stable facts:
- VERIFIED: the API lists 69 models and the CLI lists 70 on the same day. VERIFIED 2026-09-19: the API lists 71.
- VERIFIED 2026-09-17: three models were free:
meituan/LongCat-2.0:free,poolside/laguna-s-2.1-free,inclusionai/ling-3.0-flash-sante:free. - VERIFIED 2026-09-25 (kz9mk): DeepSeek's 2026-09-10 update retired V4 Flash upstream and only temporarily routes the legacy name
deepseek-v4-flashto V4.1 Flash. Command Code listsdeepseek/deepseek-v4.1-flashin bothGET /provider/v1/models(81 models that day) andcommand-code --list-models(1.58.1), soCMD_MODELandCYBERINE_COMMANDCODE_MODELnow default to it.deepseek/deepseek-v4-flashis still listed and still accepted when set explicitly. - VERIFIED 2026-09-19: the LongCat free tier is retired. The catalog lists only the paid
meituan/LongCat-2.0, and a run on the:freeid exits 4 with a result line whoseerrorreads403 The free LongCat 2.0 tier has been retired. LongCat 2.0 is now a paid model. Two free ids remain:poolside/laguna-s-2.1-freeandinclusionai/ling-3.0-flash-sante:free. The CLI bundle's own model list still marks the retired id free, so it is stale for free-tier status; the free lane reads the live catalog and is unaffected. - VERIFIED: GOAT covers the open-model catalog (DeepSeek, Kimi, GLM, MiniMax, MiMo, Qwen and others) but no Anthropic model.
- VERIFIED: ids are case-insensitive on input; the API echoes the canonical mixed-case id. Store the canonical form.
- VERIFIED: the CLI also resolves a short name after the last
/(cmd --model kimi-k2.5).
cmd CLI
Install and identity
- VERIFIED:
npm i -g command-codeinstallscmd,cmdc,command-codeandcommandcode, all pointing at one entry. Requires Node 22 or newer (engines.node). - VERIFIED: the package is licensed UNLICENSED (not open source as of 2026-09-17).
- VERIFIED: the CLI self-updates by default;
--no-auto-updatedisables that for one run. An orchestrated worker should always pass it. - VERIFIED 2026-09-19: the gate is
shouldRunAutoUpdate: !skipCommands.has(cmd) && !args.includes("--no-auto-update")in the v1.54.2 bundle, so any invocation without the flag may start the background updater. It installs through whichevernpmis first onPATH: on this machine it put 1.58.0 under/opt/homebrew/lib/node_modules/command-codewith no bin links while the nvm copy onPATHstayed 1.54.2. With the flag,updates.jsonwas left untouched across every probe, but each run still emits anoticeeventupdate available: v1.58.0 (installing in the background ...)read from the pending state, which is misleading: nothing installs.
Flags an adapter needs
| Flag | Meaning | Tag |
|---|---|---|
-p, --print [query] | non-interactive, exits after the answer. The value is optional, so a query in the next argv entry that starts with - is parsed as an option: -p "- say ok" exits 1 with No query provided, while --print=- say ok answers (VERIFIED 2026-09-17 on a free model). An adapter passes --print=<query> | VERIFIED |
--output-format text|json | json is an NDJSON event stream plus one final result line | VERIFIED |
--max-turns <n> | default 100; hitting the cap exits 8 | flag VERIFIED, exit code DOCS |
-m, --model <model> | full id or short name | VERIFIED |
--skip-onboarding | skips taste onboarding; required for automated runs | VERIFIED |
--permission-mode <m> | default, standard, plan, auto-accept, dont-ask | dont-ask VERIFIED accepted (see disagreement 4); the rest DOCS |
--yolo | bypass mode, alias --dangerously-skip-permissions | VERIFIED (km3ga bake-off: the only way a print-mode run writes files) |
-t, --trust | skips the first-run project trust prompt | VERIFIED accepted |
-w, --worktree [name] | runs inside a CLI-managed worktree | DOCS |
--no-session | in-memory only, nothing persisted | VERIFIED accepted |
--local-only | BYOK only, no Command Code traffic (same as CMD_LOCAL_ONLY=1) | DOCS |
--list-models | prints the catalog | VERIFIED |
--verbose | prints session: <id> on stderr | VERIFIED |
Headless output
- VERIFIED: a run emits NDJSON on stdout. Event types seen:
run_start,turn_start,message_start,model_request_start,model_trace,thinking_start,thinking_delta,thinking_end,message_update,model_request_end,message_end,tool_queued,tool_running,tool_completed,turn_end,text_delta,run_end. - VERIFIED: the final line has keys
type,subtype,sessionId,stopReason,usage,durationMs,finalText, withtype: "result"andsubtype: "success"on a clean run. - VERIFIED:
usageis NOT the OpenAI shape. It is{inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens}. There is no cost field; cost comes from the billing endpoint. - DOCS:
subtype,usage,durationMsandfinalTextare always present;sessionIdandstopReasonare OPTIONAL and absent on an early failure (auth, bad input). Ignore unknowntypevalues; the event list grows. - VERIFIED 2026-09-17 offline (the real binary inside Cyberine's Seatbelt profile with the network denied, so nothing reached the service): every line before the result is a wrapper
{"type":"event","event":{"type":"<name>",...}}, so the event names above are the INNERevent.type.api_retry,run_errorandrun_endalso appear. A failed run's result line is{"type":"result","subtype":"error",...,"finalText":"","error":"Error: ..."}and carriessessionIdonly when the harness had started: the no-credential run had none, the connection-refused run had one. - DOCS (read from the v1.54.2 bundle,
classifyPrintModeErrorandclassifyPrintOutcome): the result line'ssubtypeissuccess,max_turnsorerror, and on a failure it adds anerrorstring. The exit codes are0ok,1general error,3auth,4permission denied (including a spend cap),5rate limited (a usage window: the message names the window and saysResets in <duration>, with no ISO timestamp),6connection error,7server error,8max turns (subtypemax_turns, usage kept),9no final text (subtypesuccess),10insufficient credits,130interrupted. - VERIFIED 2026-09-17 offline: exit
3with no credential (Error: Not authenticated. Please run "cmd login" first., nosessionId, zero usage, under a second) and exit6with a placeholder key and the network denied (sevenapi_retryevents, then the result line).0,3and6are the observed codes; the rest are the bundle's table. - VERIFIED: the system prompt plus repo context is large. A trivial read-only task consumed 51,610 input tokens, 16,000 of them cache reads.
Permission modes
DOCS. Rules live under permissions in settings.json as deny, ask and allow lists, checked in that order, with Claude-Code-shaped matchers such as Edit(src/**).
| Mode | Reads | Writes | Shell |
|---|---|---|---|
default | free | prompt | prompt |
auto-accept | free | allowed | safe filesystem commands only |
plan | free | blocked except a plan file | read-only |
bypass (--yolo) | free | allowed | allowed |
dont-ask | free | allowlist only | allowlist only |
For an orchestrated worker, dont-ask with an allowlist is fail-closed (a call outside the list is denied instead of hanging on a prompt), while --yolo is fail-open. deny wins in every mode, ask denies under dont-ask, and ask_user_question, agent and run_command skip the lists.
VERIFIED 2026-09-17 on v1.54.2: in headless -p mode none of this unlocks writes. With --permission-mode dont-ask and a project .commandcode/settings.json allowing Edit(**), Write(**) and Bash(**), a write is still refused with Tool "write_file" requires permissions. Use --yolo (or --dangerously-skip-permissions) to enable file writes and shell commands in print mode. Only --yolo lets a print-mode run edit files or run shell commands, and --yolo has no path confinement (a bake-off run reached git outside its assigned worktree). The refused run still exits 0 with subtype: "success", and the model may claim it wrote the file, so a worker must judge the diff, never the result line. An orchestrated CLI worker therefore runs --yolo inside Cyberine's host sandbox.
Files and isolation
- DOCS: user state lives under
~/.commandcode/(auth.json,config.json,settings.json,providers.json,mcp.json,projects/,worktrees/,plans/). Project state lives under.commandcode/(settings.jsonto commit,settings.local.jsonto ignore,agents/,skills/,taste/), plusAGENTS.mdas project memory and.mcp.json. - VERIFIED:
auth.jsonholds the key in plaintext at mode 0600. - DOCS: CLI-managed worktrees live OUTSIDE the repo at
~/.commandcode/worktrees/, on branchworktree-<name>. A.worktreeincludefile (gitignore syntax) copies untracked files such as.envinto them. - VERIFIED 2026-09-17 on this machine and offline: a headless run with
--no-sessionstill writes~/.commandcode/projects/<slug>/<sessionId>.meta.jsonand.checkpoints.jsonl(the slug is the lowercased, dash-joined cwd), and a run that edits files writes backups under~/.commandcode/file-history/<sessionId>/. The bundle also writesupdates.json,update.lock,telemetry-install-id,sessions/hooks-audit-*.jsonland a scratchpad under/tmp/commandcode-<uid>/. - DOCS (bundle):
~/.commandcode/projects/<slug>/mcp.jsonis the LOCAL MCP scope, the highest-precedence one, and~/.commandcode/mods/*.tsare code the CLI loads. A process that can write either controls what the operator's next interactive session executes. - DOCS (bundle,
getCommandAuthKey): the CLI reads its key fromCOMMAND_CODE_API_KEYfirst and falls back toauth.json'sapiKey. It never readsCMD_API_KEY; that name is Cyberine's own for the Provider API. - Integration rule: isolation has exactly one owner. A Cyberine CLI worker runs inside the worktree
src/engine/worktreeSandbox.tscreated and never passes-w.
Environment variables
DOCS (docs plus the shipped bundle): CMD_ZDR=1 (zero data retention), CMD_LOCAL_ONLY=1 (BYOK only, disables telemetry, billing checks and the catalog), DO_NOT_TRACK=1 (telemetry off), CMD_TOOLS_<TOOL>_ENABLE=true and CMD_TOOLS_ALL_ENABLE=true (re-enable tools a headless run withholds).
BYOK
DOCS. ~/.commandcode/providers.json points the CLI at our own OpenAI-compatible or Anthropic Messages endpoints, with the key referenced as $ENV_VAR or {env:VAR} rather than pasted. Requests then go straight to that endpoint, and --local-only removes all Command Code backend contact. BYOK models are outside the catalog, so context-window and cost metadata must be supplied in the config. The zero-credit claim is unverified; kjrrv measures it.
Documented disagreements
- Model-id casing. VERIFIED:
cmd --list-modelsprints ids in lowercase (minimaxai/minimax-m3), whileGET /provider/v1/modelsreturns canonical mixed case (MiniMaxAI/MiniMax-M3). The API accepts both on input and echoes the canonical form, so an adapter may send either but should store the canonical one. - GOAT API access. The launch blog said the Provider API needs "Pro plan or higher"; the docs said every plan except Go. VERIFIED on 2026-09-17: the docs were right, GOAT has API access.
- Model count. VERIFIED: 70 models from the CLI versus 69 from the API on the same day. Treat the API list as the dispatchable set.
dont-askpermission mode.cmd --helplists onlystandard, plan, auto-acceptfor--permission-mode, while the docs and the shipped bundle implementdont-ask(the bundle's own description: never prompts, anything that would need approval is denied instead). VERIFIED on 2026-09-17:cmd -p ... --permission-mode dont-askis accepted and exits 0 withsubtype: "success", so the help text is stale as a list of valid modes. But accepted is not effective: in print mode an allowlist underdont-askdoes not unlock writes (see Permission modes).
2026-09-19 re-verification
A second session (building a private command-code wrapper) measured eight facts on v1.54.2 on 2026-09-19. Each was re-run here the same day before it entered this file, on free models only or with a throwaway HOME and no credential, so the check drew zero credits.
| Finding | Verdict | Evidence here | Consequence for Cyberine |
|---|---|---|---|
| The LongCat free tier is retired | VERIFIED | catalog lists only meituan/LongCat-2.0 (paid); -m meituan/LongCat-2.0:free exits 4 with 403 ... tier has been retired in the result line | The free lane reads the live catalog, so it already skips the id. Exit 4 now classifies as a named permission refusal instead of the generic failure. USAGE.md examples moved to live free ids |
--effort persists into ~/.commandcode/config.json through an atomic config.json.tmp-* | VERIFIED | with a throwaway HOME, --effort high -m deepseek/deepseek-v4-flash wrote {"reasoningEffort":{"deepseek/deepseek-v4-flash":"high"}} although the run then exited 3 (no credential); -m alone wrote nothing | The worker never passes --effort: under its Seatbelt profile (config.json not writable) a network-denied --effort run exits 1 with no result line and empty stderr, where the same run without it reaches exit 6. The smoke now asserts the argv carries neither --effort nor --config. The operator's own reasoningEffort in config.json is read on every call, so a worker inherits it |
First run on a fresh HOME writes config.json ({"installed": true}) | VERIFIED (new) | a print run on a fresh HOME created config.json with that key | Harmless for the worker: under the Seatbelt profile the write is denied, the bundle's markAsInstalled catches it, and the free-model run answered OK with exit 0 and empty stderr. No grant added |
| Billing posts 1.5 to 4 s after the CLI exits | NOT RE-MEASURED (needs a paid run) | the probe would draw credits; left as the other session's measurement | No per-run credit delta is computed anywhere: a run's costUsd is estimated from tokens, and headroom is read only BEFORE a run (commandCodeRunGate, 60 s cache). A read within seconds of another run can miss that run's charge, which the window gate tolerates because it acts only on a closed window, and a 429 closes it regardless |
A write without --yolo produces tool_hook_blocked | DISPUTED | a free-model run asked to write a file emitted tool_queued then tool_denied (no hookOutput), run_end.result.stopReason and the result line's stopReason were permission_denied, subtype stayed success, exit 0, no file. tool_hook_blocked exists in the bundle as the pre-tool-hook block path, so it can appear under a user hook config | None: the worker always passes --yolo. stopReason: "permission_denied" is the machine-readable sign of a refused write if that ever changes |
| SIGTERM exits 130 | VERIFIED | kill -TERM five seconds into a run: exit 130, stderr Terminated., NO result line (stdout ends mid-stream) | Already classified as interrupted with no cooldown; the smoke now covers the no-result-line shape |
The self-updater runs on any call without --no-auto-update | VERIFIED | bundle gate quoted under Install and identity; updates.json mtime unchanged across flagged runs | The worker passes the flag and checkCommandCode reads auth.json without spawning, so nothing in Cyberine triggers the updater. update-status is not in the writable set and needs no grant while the flag is passed |
CLAUDE.md is never loaded | VERIFIED | canary runs: a repo with only CLAUDE.md answered NONE, a repo with only AGENTS.md answered its canary word | The CLI worker gets no repo instructions in a CLAUDE.md-only repo, because Cyberine injects instruction files only into LoopAgentAdapter prompts. Filed as kx3gg rather than fixed here: the same gap applies to every CLI that reads only AGENTS.md |
| The operator's MCP servers and mods DO load in a worker run | VERIFIED (2026-09-21, v1.58.0) | canary in a throwaway HOME: ~/.commandcode/mcp.json declaring a stdio server that touches a marker, and ~/.commandcode/mods/canary.mjs that touches another, with the marker path under /tmp so the sandbox's write policy cannot mask the result. A -p run carrying the worker's exact flags (--skip-onboarding --no-auto-update --no-session --no-skills -t --yolo, free model poolside/laguna-s-2.1-free) started the MCP server AND loaded the mod. Under the worker's generated Seatbelt profile WITHOUT the new deny-read rules (positive control) both still loaded, so the sandbox alone did not close it; with the rules, neither loaded and the run still answered ok at exit 0, which is also the proof auth.json stayed readable | Closed for sandboxed runs (kj3g0): seatbeltProfile.ts now denies READ on mcp.json and mods/ inside every known CLI config dir, emitted AFTER the own-config re-allow so last-match-wins keeps auth.json, sessions and settings readable. --help still offers no switch for either, so an UNSANDBOXED run (HOST_SANDBOX_MODE=off) still loads both -- documented as a Known Limitation in USAGE.md |
--no-skills saves about 2.2k input tokens | VERIFIED | a trivial prompt: 15,991 input tokens with skills, 13,887 with --no-skills (-2,104); inside the worker's generated Seatbelt profile with the real HOME and network allowed, 15,974 against 13,874, so the sandbox does not hide the skills. That run is also the first time the real binary answered a live prompt under the generated profile (free model, exit 0, empty stderr). The CLI discovers ~/.commandcode/skills, ~/.agents/skills and the project's .commandcode/skills / .agents/skills | Adopted: the worker now passes --no-skills, the same isolation from the operator's global config the Claude worker gets from --safe-mode (T492), because the CLI otherwise loads every skill under ~/.agents/skills (64 on this machine, the operator's private set). It also drops the target repo's own .commandcode/skills / .agents/skills; --help offers no switch that keeps project skills alone. The CLI has no flag to skip the operator's MCP servers or mods, so those still load (kj3g0) |
Unsandboxed runs: decided, not overlooked (kdxmp, 2026-09-21)
The MCP-and-mods gap measured above is closed only when a sandbox wraps the worker. Unsandboxed
(HOST_SANDBOX_MODE=none, or a trusted task on a host with no backend) the operator's MCP servers
start and their mods are imported into the worker's process, and there is no flag that stops either.
The decision is to LEAVE that allowed rather than refuse a command-code worker without a sandbox:
HOST_SANDBOX_MODE=noneis the documented full-host-access opt-in every CLI worker shares. Refusing this one worker would change a cross-worker contract in order to close a gap the operator explicitly opted into.- What the gap exposes is the operator's own config, running in the operator's own worker, on the operator's own machine -- a confinement gap, not a path to a third party.
- The claude worker has the same shape:
--safe-modeis flag-level isolation, not a sandbox rule, and nothing refuses it unsandboxed either. - kg7a3's refusal is a different case and stays: it fires only when a sandbox IS wrapping the worker but cannot express the nested carve-out that sandbox needs.
Recorded at the gate site in CliAgentAdapter.ts's command-code setup hook, so the next reader
finds the reasoning where the refusal would have gone. The remaining half of kdxmp -- a smoke
pinning the two deny-read rules and their ordering -- still needs a selftest grant.
Cyberine wiring
- Env:
CMD_API_KEY(enables),CMD_BASE_URL(defaulthttps://api.commandcode.ai/provider/v1),CMD_MODEL(defaultdeepseek/deepseek-v4-flash). The CLI worker addsCYBERINE_COMMANDCODE_MODEL(defaultdeepseek/deepseek-v4-flash),CYBERINE_COMMANDCODE_MAX_TURNS(default60) and passesCOMMAND_CODE_API_KEYthrough when set. The free lane addsCMD_FREE_MODEL(its preference order) andCMD_FREE_FALLBACK(0disables the closed-window fallthrough). - Registry id:
commandcodeinsrc/core/providers.ts; availability flagcommandcodeDirect(key present). This is thecyberine authid forCMD_API_KEYand it stayscommandcode(kv9y5): it names a credential, not a transport. - fleet.json provider keys (kv9y5):
command-codeis the CLI worker (command-code, keyCOMMAND_CODE_API_KEYor~/.commandcode/auth.json),command-code-apiis the Provider API worker (loop-commandcode-build, keyCMD_API_KEY) andcommand-code-api-freeis the zero-credit API lane (loop-commandcode-free-build). The pre-kv9y5 keyscommandcodeandcommandcode-freestill load and resolve to the new ones;cyberine fleet doctorprints one migration warning per old key, and whencommand-code-apiis enabled with noCMD_API_KEYwhile thecommand-codeCLI is installed and logged in, it calls the API provider optional instead of broken. Worker ids did not change. - Build worker:
loop-commandcode-build, a sandbox-pinnedLoopAgentAdapterimplementer. Opt in with--fleet loop-commandcode-build,CYBERINE_BUILD_FLEET, orfleet.json. There is no compare-fleet (-direct) adapter. - Cost model:
subscription. Spend draws on the plan's credit windows, never the daily money cap.src/core/commandCode.tsholds the two id rules: a:free/-freeid recordscostUsd: 0(VERIFIED against the credit balance), and aclaude-*id skips the worker at registration. - Errors:
is not supported on this endpoint,must be called via /provider/v1/messagesandMODEL_NOT_IN_PLANare classified asauth-failureinsrc/store/workerCooldown.ts, so the worker cools down instead of retrying (VERIFIED on an unknown id against the live endpoint). - Headroom (ky8b3,
src/core/commandCodeHeadroom.ts):cyberine routereadsGET /alpha/billing/creditson theCMD_BASE_URLhost and prints remaining credits and both windows with their resets (commandCodeHeadroomin--json). The reading is a GET only, bounded by a 2.5 s timeout, cached for 60 s in$CYBERINE_HOME/commandcode-headroom.jsonunder a hash of host and key, and never made withoutCMD_API_KEY. Dispatch paths refresh it too: the router inresolveBuildFleetRoute,orchestrate()andWorkflowEnginewhen the build fleet names a Command Code worker, andLoopAgentAdapterbefore its first request on a paid model. - Window gate: a window the endpoint reports exceeded (or
used >= cap) drops every paid-model Command Code worker from the candidate set until itsresetAt(ms), with a note, and an explicit build fleet skips it the same way. A free model id is exempt. A 404, a reshaped body or a timeout reads as headroom unknown and changes nothing. - 429 parking: the Command Code adapter's client marks a 429 non-retryable for the SDK (
x-should-retry: false) and rewraps a top-level refusal body undererror.recordCommandCodeRefusalparks the refused worker in the shared cooldown store untilrateLimit.reset * 1000(else the message'sresets attime, else the response'sRetry-Afterheader, else the 30-minute rate-limit default; kg7a3 fixed a body-less 429 ignoringRetry-After) and, for an account window, records a closure every paid Command Code worker on the same key honours. A refusal scoped to one model (rateLimit.model, or the textsfree ... requests for today,today's limit on,pick another model,Upstream model provider is temporarily unavailable) instead cools only the requested model under the cooldown key<worker>::<model>and records no closure (kg7a3):commandCodeRunGateparks a run only when the worker id is parked or every model in its chain is cooling,LoopAgentAdapterdrops cooling models from its chain before the first request, andcommandCodeWorkerParkkeeps a single-model worker whose model is cooling out of the candidate set. A parked adapter returns its park note without a request, so an Orchestrator retry or a later workflow step does not reach the endpoint, and a circuit-breaker trip no longer shortens a longer park (recordCircuitCooldownkeeps an active entry that ends later). VERIFIED against a local fake server in both payload shapes; never provoked live. - CLI worker (kd823):
command-code(makeCommandCodeAdapterinsrc/adapters/CliAgentAdapter.ts), built after the km3ga bake-off measured the harness solving 3 of 3 real tasks at about 0.035 credits each whereloop-commandcode-buildsolved 1 of 3. It spawnscommand-code --print=<prompt> --output-format json --model <CYBERINE_COMMANDCODE_MODEL, default deepseek/deepseek-v4-flash> --max-turns <CYBERINE_COMMANDCODE_MAX_TURNS, default 60> --skip-onboarding --no-auto-update --no-session --no-skills -t --yoloin the task worktree, never-w. Registered inBUILD_FLEET_CLI_BINARIES,cliBinaryForWorker,WORKER_PROFILES(costModel: 'subscription'),WORKER_PROVIDER_MAP(commandcode) andcheckCommandCode(COMMAND_CODE_API_KEY, else a non-emptyapiKeyinauth.json; the value is never read out). Its provider label iscommandcode:<model>, the same prefix as the loop worker, because both draw one pool. - CLI worker sandbox:
--yolobecause print mode refuses writes otherwise (Permission modes above), so the host sandbox is its only confinement.cliConfigDirsFor('command-code')is~/.commandcode, which puts that directory on every worker's read deny-list and re-allows reading it for this worker only;cliWritablePathsFor('command-code')narrows the write grant toprojects/,file-history/,sessions/,updates.json,update.lockandtelemetry-install-id, and a Seatbelt regex denies writingprojects/<slug>/mcp.json,settings.jsonandsettings.local.json. Verified offline with a probe inside the generated profile: those grants allowed, andauth.json,providers.json,mcp.json,mods/, the per-projectmcp.json, another CLI'sauth.jsonand any path outside the worktree denied (EPERM). The real binary ran under that profile with the network denied and wrote onlyprojects/<slug>/session files, with no EPERM. The bubblewrap, container (docker, podman, gvisor) and Windows backends cannot express that nested carve-out, so the worker fails closed there (kg7a3):nestedWriteCarveOutGapinsrc/adapters/hostSandbox.tsdrops it from the candidate set with anunavailable - host sandbox "<mode>" cannot keep ...note, the adapter's setup hook refuses before the run gate or any spawn, andresolveSandboxConfigthrowsHostSandboxErrorfor any other caller whose writable paths reachprojects/<dir>/. A trusted task with no sandbox (HOST_SANDBOX_MODE=none) is not refused: that is the full-host-access opt-in every CLI worker shares. The bind backends that remain for other workers bind writable paths with--bind-try(bubblewrap) or skip a missing one (docker, podman), so an absent optional state file such asupdates.jsonneither fails a bwrap spawn nor makes docker create a root-owned directory in its place. Verified by the generated argv with a fake HOME (bwrap cannot run on macOS). - CLI worker exits: the last
type: "result"line is parsed; usage mapsinputTokens/outputTokensandcacheReadTokenstocacheHitTokens/cacheHitRatio; a non-successsubtype, or exit 0 with no result line, is an error. Exit3records anauth-failurecooldown (never retried),4is a permission refusal naming the model (a retired free tier or a spend cap, 2026-09-19) with the usual cooldown,130(SIGTERM, no result line) is an error with no cooldown,8and9returnpartialwith usage kept,5parks the worker until theResets intime (and, withCMD_API_KEYset, closes that window throughrecordCommandCodeRefusal), except that a per-model limit (today's limit on <model>) cools onlycommand-code::<model>,10and6cool down as out-of-credits and connection failure. A run checkscommandCodeRunGatebefore spawning, so a parked worker returns its park note without starting the CLI.commandCodeWorkerBindingsincludescommand-code, so a closed paid window drops it from routing like the loop worker; a free model is exempt. - Free lane (kp1nc,
src/core/commandCodeFreeLane.ts):loop-commandcode-free-buildis a second implementer bound to a zero-credit model. Its model is never named in code: the dispatch paths that prime headroom also readGET /provider/v1/models(30-minute cache in$CYBERINE_HOME/commandcode-catalog.json, a failed read retried after 60 s, the last good catalog kept), keep the idsisCommandCodeFreeModelaccepts in catalog order, and bind the first as the model and up to three more asLoopAgentAdapterfallbacks.CMD_FREE_MODEL(comma-separated) sets a preference order among free ids the catalog still lists. A 429 or 5xx on one free model moves the run to the next and records a per-model cooldown the resolver skips on the next build (VERIFIED against a local fake server). A per-model refusal on the LAST model in the chain now cools that model too instead of parking the whole worker until that model's reset (kg7a3, VERIFIED against a local fake server: a daily-cap 429 on the last model left the other free model routable and its next run succeeded). The worker is exempt from window parking because every id it can bind is free. - Free lane routing: profile
costModel: 'free',freeLaneKinds: ['qa', 'code-small']. The router picks it as the singleqaworker only when no preferred-pool (subscription) worker is available, before any metered API (the bench graded code, not answers), races it with the preferred pool oncode-small(alone, before any metered API, when no preferred-pool worker exists), and holds it back oncode-largeunless nothing else is available. The kinds come from the bench recorded in.local/research/commandcode/2026-09-17-free-lane-bench.m3max.md: print shape 15/16, 16/16 and 14/14 (two unrun) for the three free models against 16/16 for paiddeepseek/deepseek-v4-flash, write-the-file shape 6/6 (two refused by the daily cap), 8/8 and 8/8 against 8/8, zero credits on every free batch, 0.0488 credits for both paid batches together. Multi-file implementation on a free model is unmeasured, and the daily request caps (below) rule out bulk implementation regardless. - Closed-window fallthrough: when
loop-commandcode-buildis parked (window closed, or an earlier refusal) an explicit build fleet naming it buildsloop-commandcode-free-buildinstead, with a note, unlessCMD_FREE_FALLBACK=0. A mid-run refusal still parks the paid adapter for the rest of that run. - Judge backends (kz13x,
src/judges/judgeBackends.ts):loop-commandcode-free-build(the free lane, every resolved model a fallback) andloop-commandcode-build(CMD_JUDGE_MODEL, elseCMD_MODEL) backllm-judge,adversarial, the researchClaimVerifierandSynthesizerReducerwhen enabled infleet.json, after the direct providers by default or in the orderfleet.jsonrouting.judgesnames. Judge calls use the samecommandCodeFetch(a 429 is not retried) and record refusals throughrecordCommandCodeRefusal, so a judge that spends a free model's daily cap cools that model for the implementers too. VERIFIED 2026-09-17: oneLlmJudgeverdict (two candidates, a strict-JSON answer) oninclusionai/ling-3.0-flash-sante:freetook one request and named the correct candidate with a cited reason. - Not yet wired: a minimum-headroom threshold (only a closed window gates), a measured ranking among free models (catalog order today), and liveness funding evidence for the CLI row (
cyberine doctor --livenessreports itfunding-unknown).
This API-key path is compliant: an official key against a documented endpoint. It is not the subscription-OAuth-to-API pattern tombstoned in T42/T43/T44/ksmpy.
Changelog watch
Command Code is on CHANGELOG-WATCH.md. Its catalog, free-model list and deals rotate within days, and the CLI self-updates, so a stale reading here ships a wrong model id or a wrong flag.