# Command Code Backend

Vendored byte-for-byte from [`pi-commandcode-provider`](https://github.com/patlux/pi-commandcode-provider)
v0.4.3 (MIT), then hardened with upstream knowledge cross-checked against
OmniRoute's `commandCode` executor and Command Code's own docs.

## Endpoint & auth

- Chat: `POST https://api.commandcode.ai/alpha/generate` (custom SSE protocol)
- Models: `GET https://api.commandcode.ai/provider/v1/models` (fetched live,
  cached at `<agent-dir>/commandcode-models.json`, versioned + atomic writes)
- Auth: `Authorization: Bearer <key>` — resolved from the host key, the
  `COMMANDCODE_API_KEY` env var, or the auth files
  (`~/.commandcode/auth.json`, `~/.pi/agent/auth.json`, `~/.omp/agent/auth.json`)
- Browser login via `/login` (local callback server on 127.0.0.1, CSRF state,
  fallback to manual key paste)

## Request headers

```text
Authorization: Bearer <key>
x-command-code-version: 0.29.0
x-cli-environment: external        # third-party caller (not the official CLI)
x-project-slug: <slug from cwd>
x-taste-learning: false            # privacy opt-out
x-co-flag: false
```

`x-taste-learning: false` opts out of upstream taste-learning; OmniRoute sends
the same value.

## Request body

```jsonc
{
  "config": {
    "workingDir": "<cwd>",
    "date": "YYYY-MM-DD",
    "environment": "external",
    "structure": [], "isGitRepo": false,
    "currentBranch": "", "mainBranch": "", "gitStatus": "", "recentCommits": []
  },
  "memory": "", "taste": "", "skills": "",     // empty strings, not null
  "permissionMode": "standard",
  "params": {
    "model": "<id>",
    "messages": [...], "tools": [...], "system": "...",
    "temperature": 0.3,
    "stream": true,
    // max_tokens ONLY when pi explicitly sets one, clamped to 200_000:
    "max_tokens": 150000,
    // from options.reasoningEffort when pi passes it:
    "reasoning_effort": "high"
  },
  "threadId": "<options.sessionId or fresh uuid>"
}
```

### Key policies (aligned with OmniRoute)

- **`max_tokens` is never fabricated.** The old behavior always sent 64k,
  which is wrong for models with different ceilings and caused 400
  `Too big: expected number to be <=200000` rejections. Now the field is
  omitted unless pi sets `options.maxTokens`, and any value is clamped to the
  hard 200k ceiling.
- **Passthrough params.** `reasoning_effort`, `reasoning`, `thinking`,
  `effort`, `output_config`, `extra_body` are forwarded from the (possibly
  host-rewritten) body into `params`, so payload-rule overrides are not
  silently dropped.
- **Stable `threadId`.** `options.sessionId` (pi's per-conversation id) is used
  as the thread id, falling back to a fresh uuid. A stable thread lets Command
  Code cache the conversation prefix across turns → **cache-hit savings**
  (`cacheRead` rates are ~5× cheaper than fresh input).

## Response handling

- SSE lines: `text-delta` → text, `reasoning-delta` → thinking,
  `tool-call` → tool calls, `finish` → usage, `error` → error event
- Usage parsing: `cacheReadTokens` / `cacheWriteTokens` are extracted from
  `totalUsage.inputTokenDetails` and reported separately to pi, so costs are
  computed at the discounted cache rates
- Orphaned tool calls (missing results) are filtered out before sending
- Retry: 429/5xx with `Retry-After` + exponential backoff + jitter;
  never retries after visible output has been emitted
- Abort propagates: per-attempt timeout + outer abort signal → upstream
  `AbortController`, reader cancelled, locks released

## Pricing

Static `COMMANDCODE_MODEL_COSTS` table (per-million USD, including
`cacheRead` / `cacheWrite`). Models missing from the table display $0 — check
[Command Code pricing](https://commandcode.ai/docs/resources/pricing-limits).

## Known differences vs OmniRoute's commandCode executor

| Aspect           | pi-other-provider                            | OmniRoute                               |
| ---------------- | -------------------------------------------- | --------------------------------------- |
| Model catalog    | live fetch (52+)                             | static (18)                             |
| `threadId`       | stable per conversation (cache-friendly)     | not sent; random `x-session-id` header  |
| Usage            | `cacheRead`/`cacheWrite` reported separately | folded into `prompt_tokens`             |
| Vision           | text-only (`input: ["text"]`)                | full image conversion for vision models |
| `x-project-slug` | slug from real cwd                           | hardcoded `"pi-cc"`                     |
