opencode-cloud / README.md
polats's picture
Run as a GitHub Codespace
930c3ef
|
Raw
History Blame Contribute Delete
8.47 kB
---
title: OpenCode Cloud
emoji: πŸ€–
colorFrom: gray
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# opencode-cloud
Run [opencode](https://opencode.ai) β€” an open source AI coding agent β€” as a hosted
server you reach from a browser, from the desktop app, or from a local build of the
web app. One Dockerfile, deployable to **Hugging Face Spaces** or **Railway**.
`opencode serve` is not just an API: the server also serves the web UI on its
catch-all route, so opening the deployment URL gives you the full app, same-origin.
---
## Deploy on Hugging Face Spaces
1. **Create a Space** β†’ SDK **Docker**, blank template. Push this repo to it
(or duplicate an existing Space built from it).
2. **Settings β†’ Variables and secrets** and add:
| Secret | Required | Notes |
|---|---|---|
| `OPENCODE_SERVER_PASSWORD` | **yes** | The container refuses to start without it. This is the only thing protecting a shell. |
| `OPENCODE_SERVER_USERNAME` | no | Defaults to `opencode`. |
| `OPENCODE_API_KEY` | pick β‰₯1 | [opencode zen](https://opencode.ai/zen) curated models |
| `ANTHROPIC_API_KEY` | pick β‰₯1 | https://console.anthropic.com |
| `OPENAI_API_KEY` | pick β‰₯1 | https://platform.openai.com/api-keys |
| `GEMINI_API_KEY` | pick β‰₯1 | https://aistudio.google.com/apikey |
3. Open the Space URL and log in with `opencode` + your password.
Provider keys work as plain env vars β€” opencode registers any provider whose
models.dev env var is present, no login step needed.
### Persistence
Free Spaces are **ephemeral** and are stopped after ~48h idle. Sessions, provider
logins and any uncommitted code are lost on restart. Two options:
- **Free:** `git clone` your repo into the workspace and push before you walk away.
- **Paid:** enable persistent storage (Settings β†’ Storage). It mounts at `/data`,
which `entrypoint.sh` detects and uses for the XDG dirs *and* the workspace, so
state survives restarts. Watch the boot log β€” it prints which mode it picked.
### Public or private Space?
A **private** Space adds your HF login in front of everything, which is the safer
default for browser use. The catch: HF authenticates private Spaces with an
`Authorization: Bearer hf_…` header, and opencode wants `Authorization: Basic …` β€”
one header, two claimants. So a private Space works in a browser (HF session
cookie) but a **desktop-app or local-app connection to a private Space will fight
over that header**. Keep the Space public with a long password if you want those.
---
## Deploy on Railway
```bash
railway init # or point a service at this GitHub repo
railway variables --set OPENCODE_SERVER_PASSWORD=...
railway up
```
Railway injects `$PORT`, which `entrypoint.sh` uses automatically. Attach a volume
with mount path `/data` for persistence. Details and caveats: [docs/RAILWAY.md](docs/RAILWAY.md).
---
## Run as a GitHub Codespace
```
Code -> Codespaces -> Create codespace on main
```
Set `OPENCODE_SERVER_PASSWORD` first, as a **Codespaces** secret β€” repository secrets
and Actions secrets are separate and are not visible here:
```bash
gh secret set OPENCODE_SERVER_PASSWORD --app codespaces --repo OWNER/REPO
```
`.devcontainer/devcontainer.json` builds the same Dockerfile, forwards 7860 publicly and
starts the server on `postStartCommand`. Public is safe only because `entrypoint.sh` refuses
to start without a password; without the secret the codespace comes up with no server and the
reason is in `/tmp/opencode.log`.
Unlike a Space or a Railway service, a codespace **stops after 30 minutes idle** (240 maximum).
It keeps its disk and restarts under the same name and URL, and `postStartCommand` boots the
server again β€” but it is not always-on, and GitHub deletes a stopped codespace after the
retention period, up to 30 days. State lives under `/workspaces/.opencode-state`, so it
survives a stop and is lost only with the codespace itself.
A personal Free account includes 120 core-hours a month, which is roughly 60 hours of wall
clock on a 2-core machine; the idle timeout is what keeps that from draining.
---
## Keeping the Space in sync with GitHub
`.github/workflows/sync-to-hf-space.yml` builds the image, boots it, checks that
it refuses to start unauthenticated and that it serves an authenticated API and
the web UI β€” and only then force-pushes `main` to the Space and waits for it to
report `RUNNING`. A broken Dockerfile fails on the runner instead of leaving the
Space stuck in `BUILD_ERROR`.
Configure it under **Settings β†’ Secrets and variables β†’ Actions**:
| Name | Kind | Notes |
|---|---|---|
| `HF_TOKEN` | **secret** | A Hugging Face **write** token. The HF username is derived from it, so it is the only secret needed. |
| `HF_SPACE` | variable | `owner/space-name`. Optional β€” defaults to this GitHub repo's `owner/name`. A public Space id isn't sensitive, so a variable keeps it readable in logs; a secret of the same name also works. |
GitHub is the source of truth: the sync **force-pushes**, so a commit made only
in the Space's web UI will be discarded. Edit here, not there.
---
## Connecting the desktop app or a local web app
You don't have to use the in-browser UI. In the app, **Settings β†’ Servers β†’ Add**
and enter the deployment URL plus the username/password. The server's CORS
allowlist already covers `localhost`, `*.opencode.ai` and the desktop app's
`oc://renderer` origin, so no extra flags are needed. Only a frontend you host on
your own domain needs `OPENCODE_CORS_ORIGINS=https://your.domain`.
---
## Giving the agent Hugging Face access
Set `HF_TOKEN` as a Space secret (or Railway variable) and the agent can create
and manage Hugging Face repos: the official `hf` CLI is installed in the image,
it picks the token up from the environment with no login step, and `entrypoint.sh`
installs [`agents/hf-spaces.md`](agents/hf-spaces.md) as opencode's global
`AGENTS.md` so the agent knows the recipes. With no `HF_TOKEN` set, that file is
removed and nothing advertises the capability.
> **This hands your HF account to whoever can reach the server.** A standard HF
> write token covers every repo the account can write to β€” including org repos β€”
> so the blast radius is much larger than "a shell in a container". Two things
> make it meaningfully safer:
>
> - Use a **fine-grained token** scoped to just the permissions you need (write
> access to Spaces, say) rather than an account-wide write token.
> - Remember the agent reads untrusted content β€” repos, web pages, issue text.
> Anything it reads can try to talk it into using the token. The instructions
> tell it never to print the token, but that is a speed bump, not a boundary.
---
## Read this before you deploy
- **This is a remote shell.** Every route allows command execution and file
read/write in the container. Basic auth over HTTPS is the entire security model,
so use a long random password, and think twice about what credentials you put in
the container alongside it.
- **Provider OAuth "login with browser" flows don't work on a remote server.**
They bind a `http://localhost:<port>/auth/callback` listener *inside* the
container, so your browser is redirected to your own machine instead. Use API
keys.
- **CPU only, and modest.** Fine for the agent; you can't run local models.
- **Check the host's terms.** A general-purpose remote shell is not the ML-demo
use case Spaces are described for; a public one with a weak password is the way
to get flagged.
---
## Environment variables
| Variable | Default | Purpose |
|---|---|---|
| `OPENCODE_SERVER_PASSWORD` | β€” | **Required.** Basic auth password. |
| `OPENCODE_SERVER_USERNAME` | `opencode` | Basic auth username. |
| `PORT` | `7860` | Listen port. Railway sets this; HF must match `app_port`. |
| `OPENCODE_STATE_ROOT` | `/data` | Where to look for a writable volume. Codespaces sets `/workspaces/.opencode-state`. |
| `OPENCODE_WORKSPACE` | `$STATE_ROOT/workspace` or `$HOME/workspace` | Directory to serve. |
| `OPENCODE_CORS_ORIGINS` | β€” | Comma-separated extra CORS origins. |
| `HF_TOKEN` | β€” | Optional. A Hugging Face token, which lets the agent create and manage HF repos with the bundled `hf` CLI. See the warning below. |
Build arg `OPENCODE_VERSION` pins a release (default: latest).
---
MIT. opencode itself is Β© Anomaly Innovations; this repo is deployment wrapper code.