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.
4.9 KiB
4.9 KiB
AGENTS.md
Project overview
This repository builds and publishes a Docker image for OpenCode, 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
.
├── Dockerfile # Image definition
├── .gitea/workflows/docker-build.yaml # CI/CD pipeline (Gitea Actions)
├── renovate.json # Dependency update automation (Renovatebot)
├── opencode-attach # Helper script for attaching to a running server
└── README.md # Usage documentation
Dependency management
- Always pin versions in the Dockerfile
npm installcommand (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
customManagerentry inrenovate.jsonwith a regexmatchStringspattern 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:26-trixie— Debian-based Node.js image (not Alpine) so that downstream images can still useapt-getand 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/clireplacedopencode-aias the published package in OpenCode 2;--allow-scripts=@opencode/cliis required for itspostinstallto select the native binary. - Version check:
RUN opencode --versionafter install to validate the build and record the installed version in build logs. - Dedicated user: a non-root
opencodeuser and group are created withgroupadd/useradd(UID/GID 1000). All runtime steps run as this user. - Cluster tooling:
kubectlis copied from the officialregistry.k8s.io/kubectlimage (multi-stage COPY). - Entrypoint:
["opencode"]— arguments are passed at runtime;servestarts the headless server. Bareopencodeopens the TUI, so the server is always invoked explicitly.
OpenCode 2 notes
- The npm package is
@opencode/cli(binsopencodeandopencode2);opencode-aistops at 1.19.x and must not come back. opencode attachno longer exists: point a client at a server withopencode --server <url>(after the subcommand when one is given).opencode-attachwraps this.- The server always authenticates: username is fixed to
opencode, password comes fromOPENCODE_SERVER_PASSWORDorOPENCODE_PASSWORD, and a random one is generated and logged when neither is set. - The v1 REST API was replaced (
/global/healthis 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)
- Pipeline triggers on push to
main, PRs targetingmain, and a nightly cron (cron: '0 0 * * *'). - Image is pushed to Docker Hub only on non-PR events (main branch pushes and cron runs).
- Docker Hub credentials are stored in Gitea Actions secrets (
DOCKERHUB_USERNAME,DOCKERHUB_TOKEN). - The image is published as
jcabillot/opencode:latestwith digest and branch tags.
Useful commands
# Build the image locally
docker build -t opencode .
# Run the server on all interfaces
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 serve --hostname 0.0.0.0
# Protect with a password
docker run -it -p 4096:4096 \
-e OPENCODE_SERVER_PASSWORD=secret \
opencode serve --hostname 0.0.0.0
opencode serve options
| Flag | Default | Description |
|---|---|---|
--port |
4096 |
Port to listen on |
--hostname |
127.0.0.1 |
Hostname to bind |
--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 |
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.