# OpenCode

> Cordium documentation. Canonical page: <https://octelium.com/docs/cordium/latest/examples/ai/opencode>.

[OpenCode](https://opencode.ai/docs) is an open source coding agent that works with many LLM providers. This example sets up a *Template* in which OpenCode can use both Anthropic's models and a self-hosted open model served by vLLM in a private network, through Octelium `LLM` *Services*. Developers use it interactively from their terminals, and the same *Template* runs one-shot tasks via `opencode run`.

Since the models are reached through Octelium, the *Workspaces* need neither API keys nor any network route to the private network that hosts the vLLM server. Octelium also lets you decide, per *User*, *Group*, *Space* or *Template*, which models can be used, and audits every inference request (read more [here](https://octelium.com/docs/cordium/latest/examples/ai/secretless-llm.md)).

## The Octelium Services

In addition to the `anthropic` *Service* (read more [here](https://octelium.com/docs/cordium/latest/examples/ai/secretless-llm.md)), a *Cluster* administrator exposes the vLLM server as an `LLM` *Service* in the `ai-platform` *Namespace*. Since vLLM exposes an OpenAI-compatible API, the *Service* uses the `OPENAI` protocol. The vLLM server can run anywhere, including behind a NAT, by serving the *Service* from a connected Octelium client (read more [here](https://octelium.com/docs/octelium/latest/management/core/service/overview.md#remotely-via-a-connected-user)):

```yaml
kind: Service
metadata:
  name: qwen.ai-platform
spec:
  mode: LLM
  config:
    upstream:
      url: http://vllm.gpu-cluster.internal:8000
    llm:
      protocol: OPENAI
```

## The Template

The following *Template* installs OpenCode and configures two providers: the built-in `anthropic` provider pointed at the `anthropic` *Service*, and an `internal` OpenAI-compatible provider pointed at the `qwen.ai-platform` *Service*:

```yaml
spec:
  image:
    registry:
      url: golang:1.26-bookworm
  repository:
    url: https://github.com/acme-corp/payments-api
  gitProvider: github.payments.cordium
  runtime:
    tasks:
      - name: install-opencode
        type: ON_CREATE
        runAsRoot: true
        onFailure: ON_FAILURE_ABORT
        run: |
          apt-get update
          apt-get install -y --no-install-recommends nodejs npm
          npm install -g opencode-ai
      - name: configure-opencode
        type: ON_CREATE
        workingDir: /workspace
        onFailure: ON_FAILURE_ABORT
        run: |
          mkdir -p "$HOME/.config/opencode"
          cat > "$HOME/.config/opencode/opencode.json" <<'EOF'
          {
            "$schema": "https://opencode.ai/config.json",
            "model": "anthropic/claude-opus-5-5",
            "small_model": "anthropic/claude-haiku-5-5",
            "provider": {
              "anthropic": {
                "options": {
                  "baseURL": "http://anthropic/v1",
                  "apiKey": "injected-by-octelium"
                }
              },
              "internal": {
                "npm": "@ai-sdk/openai-compatible",
                "name": "Internal models",
                "options": {
                  "baseURL": "http://qwen.ai-platform/v1"
                },
                "models": {
                  "qwen3-coder": {
                    "name": "Qwen3 Coder (self-hosted)"
                  }
                }
              }
            },
            "permission": {
              "edit": "allow",
              "bash": "allow"
            }
          }
          EOF
  limit:
    cpu:
      millicores: 4000
    memory:
      megabytes: 8192
```

The `apiKey` value is a placeholder: Octelium injects the real API key and never forwards the one sent by the client. Since the *Template* uses the `github` *GitProvider* of the `payments` *Space*, each developer signs in to GitHub from the web portal, and the repository is cloned and pushed with their own GitHub account (read more [here](https://octelium.com/docs/cordium/latest/workspaces/secrets.md#gitproviders)).

```bash
cordium create template opencode.payments.cordium --file opencode.yaml
```

> **Note:**
>
> This *Template* is not pre-built, since pre-builds do not use the *GitProvider* credentials of the *Users* and therefore cannot clone a private repository on their behalf. Each *Workspace* installs OpenCode once on its first run, and keeps it afterwards since it is persistent.

## Interactive Use

Create a persistent *Workspace*, sign in to GitHub from its page in the web portal, start it, and run `opencode` from a browser terminal or over SSH:

```bash
cordium create ws --template opencode.payments.cordium
# Sign in to the Git provider from the Workspace's page in the web portal, then:
cordium start <WORKSPACE>
cordium ssh <WORKSPACE>
```

```bash
cd /workspace/repo
opencode
```

From the OpenCode TUI, you can switch between `anthropic/claude-opus-5-5` and `internal/qwen3-coder` at any time. Since the *Workspace* is persistent, your OpenCode sessions, the repository and any installed tool survive across restarts.

## One-Shot Tasks

`opencode run` runs a single task non-interactively, which is useful for scripted maintenance work. Here is an example that uses the self-hosted model to upgrade the Go dependencies of the repository in a running *Workspace*:

```bash
cordium exec --no-stdin -w /workspace/repo <WORKSPACE> -- sh -c \
  'opencode run --model internal/qwen3-coder "Upgrade all the Go dependencies to their latest minor versions, run go test ./..., and fix any breaking change." < /dev/null'
```

You can also restrict which models a *Template*'s *Workspaces* are allowed to use via Octelium *Policies*, for example to keep the *Workspaces* that work on sensitive code on the self-hosted model only (read more [here](https://octelium.com/docs/cordium/latest/examples/ai/secretless-llm.md#restricting-models)).
