>thevibeworks/deepseek-cli

For agents

Built to be driven by other programs. The contract below is stable and tested; the same text ships in the repo as AGENTS.md and as a drop-in agent skill.

The output contract

--json is not wrapped

--json prints the API's response byte-for-byte: no envelope, no injected fields. jq recipes written against the OpenAI or Anthropic APIs keep working unchanged.

ds chat "..." --json | jq -r '.choices[0].message.content'
ds chat "..." --jq '.usage'
ds models --json | jq -r '.data[].id'

Cost deliberately does not appear there — it would have meant wrapping the response. It goes to stderr and to the ledger instead.

Response shapes

From the API, so they are the documented DeepSeek shapes:

chat       {"id","object","created","model",
            "choices":[{"message":{"content","reasoning_content","tool_calls"},
                        "finish_reason"}],"usage":{...}}
anthropic  {"id","type","role","model","content":[{"type","text"}],
            "stop_reason","usage":{...}}
respond    {"id","object","status","model",
            "output":[{"type","content":[{"type","text"}]}],"usage":{...}}
fim        {"id","object","model","choices":[{"text","finish_reason"}],"usage":{...}}
models     {"object":"list","data":[{"id","object","owned_by"}]}
balance    {"is_available","balance_infos":[{"currency","total_balance",...}]}

Computed locally, not from the API:

usage      {"since","total":{...},"by_model":{...},"by_api":{...}}
check      {"base_url","key_set","ok",
            "probes":[{"name","path","ok","detail","error","ms"}]}
session ls [{"name","model","turns","updated","bytes"}]

Note that usage field names differ per format, exactly as the API sends them. See the token-accounting trap.

Exit codes carry meaning

0   success
1   error            read stderr
2   auth             key missing or rejected  → do not retry
3   no balance       top up                   → do not retry
4   rate limited     back off, then retry
130 interrupted

Transport failures and 429/5xx are already retried internally with exponential backoff, honouring Retry-After. A non-zero exit means your own retry loop probably will not help either. Requests that reached the model are never retried — a second call would be billed twice.

Preflight

ds check --json
# {"base_url":"...","key_set":true,"probes":[...],"ok":true}

One command, six endpoints, a fraction of a cent. If ok is false, read probes[].error.

Errors say what to do

$ ds chat hi
Error: Insufficient Balance (HTTP 402)
  out of balance: deepseek balance — top up at https://platform.deepseek.com/top_up

Quiet mode

ds chat "..." --no-stats --no-ledger --json

Use both when the usage line would pollute captured output, or when a batch run should not land in the ledger.

As an agent skill

skill/SKILL.md ships in every release archive. It carries the same contract as an operational procedure, with the rules that matter for autonomous use: