> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opper.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenCode

> Run SST's open-source terminal coding agent on any model in the Opper catalog

[OpenCode](https://opencode.ai) is SST's open-source terminal coding agent (MIT, [source](https://github.com/anomalyco/opencode)). It reads a provider block from its config file, so Opper slots in as one more provider.

## Setup

There are three ways in, and they differ in one thing: where the model list comes from.

<Tip>
  **Just a key.** OpenCode ships with the [models.dev](https://models.dev) registry, which already lists Opper, so there is nothing to configure:

  ```bash theme={null}
  export OPPER_API_KEY=your-opper-api-key
  opencode
  ```

  Opper appears in `/model` straight away and no config file is written.
</Tip>

That registry is one global list, identical for everyone, so it cannot carry anything specific to your key. Your [pools](/capabilities/models), your deployed [dynamic routes](/control-plane/route) and your project's [model access rules](/control-plane/rules/model-access) are all invisible to it. The two CLI commands below fetch the catalog scoped to your key instead, and OpenCode merges what they write with the registry rather than replacing it, so you keep both lists.

**Signed in through the CLI**, which suits a single workstation:

```bash theme={null}
npx @opperai/cli login
npx @opperai/cli launch opencode
```

The key is stored by the CLI and passed to OpenCode for you, and the model list is refreshed on every launch.

**With an environment variable** instead, which suits rollouts, CI and shared machines:

```bash theme={null}
export OPPER_API_KEY=your-opper-api-key
npx @opperai/cli editors opencode
opencode
```

`editors opencode` writes the config without launching anything, and refreshes the list whenever you re-run it. The key itself is never written to disk: the config carries `{env:OPPER_API_KEY}`, which OpenCode resolves from the environment each run, so keep it exported.

|                            | models.dev                     | `launch` / `editors`           |
| -------------------------- | ------------------------------ | ------------------------------ |
| Setup                      | export a key                   | one command                    |
| Model list                 | one global list                | the catalog scoped to your key |
| Model access rules applied | no                             | yes                            |
| Pools                      | no                             | yes                            |
| Dynamic routes             | no                             | yes                            |
| Refreshed                  | with OpenCode's registry cache | every run                      |

### What lands in the config

The model list is fetched from `/v3/compat/models` when the command runs, so it is scoped to your API key. You get the concrete models your project's [model access rules](/control-plane/rules/model-access) allow, the [pools](/capabilities/models) that load-balance a bare name across providers, and your deployed [dynamic routes](/control-plane/route) as `dynamic/<name>`.

`launch` refreshes the list on every run and `editors` refreshes it whenever you re-run it, so new models and newly deployed routes appear without editing anything. If no key is available the command still succeeds, falling back to a small built-in list.

### By hand

To wire it manually instead, add an `opper` provider to `~/.config/opencode/opencode.json`. A hand-written block is a fixed list, so pools and dynamic routes will not appear and you maintain the models yourself:

```json theme={null}
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "opper": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Opper",
      "options": {
        "baseURL": "https://api.opper.ai/v3/compat",
        "apiKey": "{env:OPPER_API_KEY}"
      },
      "models": {
        "anthropic/claude-sonnet-4-6": { "name": "Claude Sonnet 4.6" },
        "openai/gpt-5.5": { "name": "GPT-5.5" }
      }
    }
  }
}
```

```bash theme={null}
export OPPER_API_KEY=your-opper-api-key
opencode
```

<Warning>
  If `opencode.json` already exists, merge the `opper` block into it rather than overwriting the file — replacing it wholesale drops any other providers you have configured.
</Warning>

## Choosing a model

Use `/model` inside a session to switch. The picker lists whatever the provider block exposes; model IDs follow the `provider/model` convention from the [catalog](/capabilities/models).

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    `OPPER_API_KEY` has to be exported in the shell that launches OpenCode. Opper keys start with `op-`.
  </Accordion>

  <Accordion title="Opper is missing from the picker entirely">
    OpenCode caches the models.dev registry at `~/.cache/opencode/models.json` and a long-lived install can be holding a copy from before Opper was listed. Refresh it:

    ```bash theme={null}
    curl -sSfo ~/.cache/opencode/models.json https://models.dev/api.json
    ```

    Running `opper launch opencode` also sidesteps the cache, because it writes the provider block itself.
  </Accordion>

  <Accordion title="The provider block disappeared">
    `opper launch opencode` merges its entry alongside your existing providers rather than replacing the file, so re-running it restores the Opper block without touching the rest.
  </Accordion>

  <Accordion title="Only a handful of models are listed">
    The command falls back to a small built-in list when it cannot reach the catalog, which usually means no key was available when it ran. Run `opper login`, or export `OPPER_API_KEY`, then run `opper editors opencode` again.
  </Accordion>

  <Accordion title="Pools and dynamic routes are missing">
    Neither the models.dev registry nor a hand-written provider block can carry them, because both are fixed lists that know nothing about your key. Run `opper editors opencode` to add the catalog scoped to your key, which includes both.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Opper CLI" icon="terminal" href="/developer-tools/cli">
    Every agent the CLI can launch.
  </Card>

  <Card title="All integrations" icon="plug" href="/integrations/overview">
    Every app that runs on Opper.
  </Card>
</CardGroup>
