feat: migrate to OpenCode 2
PR Checks / hadolint (pull_request) Successful in 12s
PR Checks / build-test (pull_request) Successful in 3m14s

OpenCode 2 publishes its CLI as @opencode/cli (opencode-ai stops at
1.19.x), so install that package and pin it to 2.0.32.

Also fix what the v2 migration invalidates:
- renovate.json: track @opencode/cli instead of opencode-ai, otherwise
  the pin is never bumped.
- opencode-attach: `opencode attach` no longer exists in v2. Point the
  client at the server with `--server <url>` instead (appended after a
  subcommand when one is given); auth still comes from
  OPENCODE_SERVER_PASSWORD / OPENCODE_PASSWORD.
- README/AGENTS: v2 package name, entrypoint, serve defaults, API
  surface (/global/health is gone, everything lives under authenticated
  /api/*), and removal of OPENCODE_SERVER_USERNAME (the username is
  always `opencode` in v2).

The entrypoint stays ["opencode"] on purpose: existing deployments pass
`serve ...` at runtime, and OpenCode 2 is invoked the same way.
This commit is contained in:
OpenCode Cabillot committed 2026-10-17 19:28:14 +00:00
1 parent 82cfa4af95
commit c2c0a81547
5 files changed
+65 -37

No files matched your search

+22 -12
View File
@@ -2,7 +2,7 @@
## Project overview
This repository builds and publishes a Docker image for [OpenCode](https://opencode.ai), the open source AI coding agent. The image runs OpenCode in headless server mode (`opencode serve`) and is automatically rebuilt and pushed to Docker Hub (`jcabillot/opencode`) every night by a Gitea Actions pipeline.
This repository builds and publishes a Docker image for [OpenCode](https://opencode.ai), the open source AI coding agent. The image ships OpenCode 2, runs it in headless server mode (`opencode serve`), and is automatically rebuilt and pushed to Docker Hub (`jcabillot/opencode`) every night by a Gitea Actions pipeline.
## Repository structure
@@ -17,18 +17,25 @@ This repository builds and publishes a Docker image for [OpenCode](https://openc
## Dependency management
- **Always pin versions** in the Dockerfile `npm install` command (e.g. `opencode-ai@1.16.2 n2-soul@9.0.9`). Never leave packages unpinned.
- **Always pin versions** in the Dockerfile `npm install` command (e.g. `@opencode/cli@2.0.32 n2-soul@9.0.9`). Never leave packages unpinned.
- **Update renovate customManagers** when adding, removing, or renaming a dependency tracked in the Dockerfile. Each pinned package must have a corresponding `customManager` entry in `renovate.json` with a regex `matchStrings` pattern that captures the version. If a dependency is added without a renovate entry, Renovatebot will not open automated PRs for it.
- **apt packages** (apt-get install lines in Dockerfile) and **COPY --from** image references are not currently tracked by Renovate. Pinning these manually is acceptable for now but adding renovate managers for them is encouraged.
## Dockerfile conventions
- **Base image**: `node:24` — Debian-based Node.js image (not Alpine, needed for apt packages).
- **Install**: `npm i -g opencode-ai@<version> n2-soul@<version>` — installs OpenCode and Soul globally, both pinned.
- **Base image**: `node:26-trixie` — Debian-based Node.js image (not Alpine) so that downstream images can still use `apt-get` and Node-based MCP servers keep working.
- **Install**: `npm i -g @opencode/cli@<version> n2-soul@<version>` — installs OpenCode 2 and Soul globally, both pinned. `@opencode/cli` replaced `opencode-ai` as the published package in OpenCode 2; `--allow-scripts=@opencode/cli` is required for its `postinstall` to select the native binary.
- **Version check**: `RUN opencode --version` after install to validate the build and record the installed version in build logs.
- **Dedicated user**: a non-root `opencode` user and group are created with `groupadd`/`useradd` (UID/GID 1000). All runtime steps run as this user.
- **Cluster tooling**: `kubectl` is copied from the official `registry.k8s.io/kubectl` image (multi-stage COPY).
- **Entrypoint**: `["opencode"]` — arguments are passed at runtime (e.g. `serve`).
- **Entrypoint**: `["opencode"]` — arguments are passed at runtime; `serve` starts the headless server. Bare `opencode` opens the TUI, so the server is always invoked explicitly.
## OpenCode 2 notes
- The npm package is `@opencode/cli` (bins `opencode` and `opencode2`); `opencode-ai` stops at 1.19.x and must not come back.
- `opencode attach` no longer exists: point a client at a server with `opencode --server <url>` (after the subcommand when one is given). `opencode-attach` wraps this.
- The server always authenticates: username is fixed to `opencode`, password comes from `OPENCODE_SERVER_PASSWORD` or `OPENCODE_PASSWORD`, and a random one is generated and logged when neither is set.
- The v1 REST API was replaced (`/global/health` is gone, every route now lives under `/api/*` and requires auth). Any client calling the v1 API — e.g. `perso/opencode-dispatch` — must be migrated separately.
## CI/CD conventions (Gitea Actions)
@@ -44,17 +51,17 @@ This repository builds and publishes a Docker image for [OpenCode](https://openc
docker build -t opencode .
# Run the server on all interfaces
docker run -it -p 4096:4096 opencode --hostname 0.0.0.0
docker run -it -p 4096:4096 opencode serve --hostname 0.0.0.0
# Run with a project mounted
docker run -it -p 4096:4096 \
-v $(pwd):/home/opencode/project \
opencode --hostname 0.0.0.0
opencode serve --hostname 0.0.0.0
# Protect with a password
docker run -it -p 4096:4096 \
-e OPENCODE_SERVER_PASSWORD=secret \
opencode --hostname 0.0.0.0
opencode serve --hostname 0.0.0.0
```
## opencode serve options
@@ -63,12 +70,15 @@ docker run -it -p 4096:4096 \
|------|---------|-------------|
| `--port` | `4096` | Port to listen on |
| `--hostname` | `127.0.0.1` | Hostname to bind |
| `--mdns` | `false` | Enable mDNS discovery |
| `--cors` | `[]` | Additional allowed browser origins |
| `--cors` | `[]` | Additional allowed browser origins (repeatable) |
| `--service` | `false` | Run as the shared background service |
| `--stdio` | `false` | Serve over stdio for editor integrations |
## Environment variables
| Variable | Description |
|----------|-------------|
| `OPENCODE_SERVER_PASSWORD` | Enables HTTP basic auth |
| `OPENCODE_SERVER_USERNAME` | Overrides the default username (`opencode`) |
| `OPENCODE_SERVER_PASSWORD` | Server password (HTTP basic auth, username `opencode`) |
| `OPENCODE_PASSWORD` | Same, takes precedence over `OPENCODE_SERVER_PASSWORD` |
`OPENCODE_SERVER_USERNAME` existed in OpenCode 1 and is no longer read: the username is always `opencode`.