# Droid (Factory) Setup

> **Last verified**: 2026-09-18 · 📄 Per official docs (Droid CLI v0.222.0 released 2026-09-18; frequent releases — trust `droid --version`)

## At a glance

| Item | Details |
|---|---|
| Models you can use | Claude ✅ (`provider: "anthropic"`) · GPT ✅ · Chinese models ✅ (`provider: "generic-chat-completion-api"`) · Gemini ❌ (no such provider upstream) |
| Protocol & Base URL | Anthropic: `https://api.qcode.cc/api` · OpenAI Chat: `https://api.qcode.cc/openai/v1` |
| Where to configure | `~/.factory/settings.json` (auto-created on first `droid` run) |
| Official docs | [BYOK](https://docs.factory.ai/model-independence/byok) · [settings](https://docs.factory.ai/droid-cli/settings)
[Droid](https://docs.factory.ai/droid-cli/overview) is Factory's terminal AI coding agent. It supports **BYOK custom models**, so QCode.cc can be its upstream.

## Which protocol

Droid selects the protocol through the `provider` field. **For Claude, use `anthropic`** — QCode's OpenAI endpoint does not accept Claude models (see [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths)).

| Model you want | `provider` | `baseUrl` |
|---|---|---|
| Claude | `anthropic` | `https://api.qcode.cc/api` |
| GPT / the four Chinese families | `generic-chat-completion-api` (Chat-Completions-compatible) | `https://api.qcode.cc/openai/v1` |

> 🔴 Do **not** write `"provider": "openai"` — upstream reserves it for the **OpenAI Responses API** (“Use provider: `"generic-chat-completion-api"` unless you are calling OpenAI's or Anthropic's official API”, [BYOK docs](https://docs.factory.ai/model-independence/byok)). GPT / Chinese models on QCode speak Chat Completions, so use `generic-chat-completion-api`.

## Install

```bash
curl -fsSL https://app.factory.ai/cli | sh
```

It installs to `~/.local/bin/droid`. If the installer reports that PATH is not configured, add the line it prints to `~/.zshrc` / `~/.bashrc`.

Verify (**trust the actual output**):

```bash
droid --version
```

## Configure

Edit `~/.factory/settings.json` (**it is auto-created on the first `droid` run**; a project-level `.factory/settings.local.json` also works — it merges on top, remember to gitignore it):

```json
{
  "customModels": [
    {
      "model": "claude-sonnet-5",
      "displayName": "QCode Sonnet 5",
      "baseUrl": "https://api.qcode.cc/api",
      "apiKey": "${QCODE_KEY}",
      "provider": "anthropic",
      "maxOutputTokens": 8192
    },
    {
      "model": "claude-haiku-4-5",
      "displayName": "QCode Haiku 4.5",
      "baseUrl": "https://api.qcode.cc/api",
      "apiKey": "${QCODE_KEY}",
      "provider": "anthropic",
      "maxOutputTokens": 4096
    }
  ]
}
```

Inject the key through the environment:

```bash
export QCODE_KEY="cr_your_qcode_key"
```

| Field | Meaning |
|-------|---------|
| `model` | The model id sent to the API; must match [qcode.cc/models](https://qcode.cc/models) exactly |
| `displayName` | Label in the model picker; free-form |
| `baseUrl` | Stop at `/api`; Droid appends `/v1/messages` itself |
| `apiKey` | Supports `${VAR}` environment references |
| `provider` | `anthropic` for Claude |
| `maxOutputTokens` | Output cap per reply |

> Per Factory's docs, **API keys stay local and are not uploaded to Factory servers**.
> From mainland China, swap the host for `https://asia.qcode.cc/api` (Asia node, nearest of Korea / Taiwan / Hong Kong).

## Verify

```bash
droid exec --model "claude-sonnet-5" "reply with exactly: OK"
```

`OK` means you are connected.

**Negative control** (proving the config actually took effect): temporarily point `baseUrl` at a path that does not exist and run again — it should fail. A success alone does not prove your leg was used.

## Everyday usage

```bash
# interactive
droid

# non-interactive
droid exec "run the tests and fix the failures"

# specific working directory
droid --cwd /path/to/project

# run inside a git worktree (isolated changes)
droid -w feature-x

# autonomy level
droid --auto medium
```

## Troubleshooting

### `model_not_available_on_endpoint`

`provider` is an OpenAI-compatible value while the model is a Claude one. Set `"provider": "anthropic"` with `baseUrl` = `https://api.qcode.cc/api`.

### 401 / auth failure

`${QCODE_KEY}` was not expanded (the variable is not exported), or the key has stray whitespace. Check that `echo $QCODE_KEY` starts with `cr_`.
Another trap: putting the config into the **legacy** `~/.factory/config.json` (snake_case fields) — officially the legacy file does **not** expand `apiKey` environment references, so `${QCODE_KEY}` would be sent verbatim as the key. Use `settings.json`.

### The model is missing from the picker

Only models listed in `customModels[]` appear. Add an entry and restart.

## Related

- [Endpoints & API Paths](/docs/getting-started/endpoints-and-api-paths) — protocol × model-family table
- [Crush Setup](/docs/ide/crush) — another terminal agent
- [Chinese Models](/docs/usage/cn-models) — GLM / Kimi / DeepSeek / Qwen