Use build-variants.sh to build all variants:
./build-variants.shBuild selected variants:
./build-variants.sh base devOverride the image name:
IMAGE_NAME=ghcr.io/datbird/opencode-plus ./build-variants.shThe script tags:
<image>:base<image>:dev<image>:full<image>:latestasdev
docker build --target base -t datbird/opencode-plus:base .
docker build --target dev -t datbird/opencode-plus:dev -t datbird/opencode-plus:latest .
docker build --target full -t datbird/opencode-plus:full .The OpenCode Plus gateway source lives in:
bridge/opencode-cf-auth-proxy/
This includes the Cloudflare Access bridge, /__opencode-plus/* endpoints, HTML UI injection, and embedded drawer assets. Docker builds compile this Go source in an auth-proxy-builder stage; do not edit or vendor a standalone proxy binary as the source of truth.
Run gateway checks locally with:
cd bridge/opencode-cf-auth-proxy
go test ./...
node --check ui/drawer.jsThe provider quota/status bridge lives in:
bridge/opencode-plus-quota/
It serves GET /health and GET /quota on port 18765 by default. The gateway proxies /__opencode-plus/quota to this bridge through OPENCODE_PLUS_QUOTA_URL.
Run syntax checks with:
node --check bridge/opencode-plus-quota/server.mjsOpenAI usage is collected natively from OpenCode OAuth state in ~/.local/share/opencode/auth.json and https://chatgpt.com/backend-api/wham/usage. OpenRouter, Gemini, Anthropic Admin/API status, and other provider status modules are native collectors. Claude subscription-window quota is not reported.
For live UI iteration, set OPENCODE_PLUS_UI_ASSET_DIR to a writable persistent directory and edit drawer.js / drawer.css there. Once the UI is approved, copy those files back into bridge/opencode-cf-auth-proxy/ui/ so the next image build embeds them.
The statusline layout is locked. Read docs/STATUSLINE-LAYOUT-LOCK.md before changing bridge/opencode-cf-auth-proxy/ui/statusline.css, chip DOM structure, row detection, transforms, margins, or wrap reserve constants.
Approximate local image sizes from the first multi-variant build:
base: 1.05 GBdev/latest: 7.89 GBfull: 9.71 GB
Base:
docker run --rm --entrypoint bash datbird/opencode-plus:base -lc 'opencode --version; git --version; docker --version; gh --version | sed -n "1p"'Dev:
docker run --rm --entrypoint bash datbird/opencode-plus:dev -lc 'opencode --version; gcc --version | sed -n "1p"; devcontainer --version; ruff --version; hx --version'Full:
docker run --rm --entrypoint bash datbird/opencode-plus:full -lc 'identify --version | sed -n "1p"; ffmpeg -version | sed -n "1p"; qpdf --version | sed -n "1p"; tesseract --version | sed -n "1p"; mmdc --version'Container images have not been published yet. Recommended GHCR flow:
IMAGE_NAME=ghcr.io/datbird/opencode-plus ./build-variants.sh
docker push ghcr.io/datbird/opencode-plus:base
docker push ghcr.io/datbird/opencode-plus:dev
docker push ghcr.io/datbird/opencode-plus:full
docker push ghcr.io/datbird/opencode-plus:latestBefore publishing, decide whether latest should remain dev.
Runtime Plus behavior is feature-gated behind:
OPENCODE_PLUS_ENHANCEMENT_MODE=false
The default remains true for existing OpenCode Plus deployments. Set it to false to smoke-test plain OpenCode mode.