anomalyco / anomalyco/opencode
opencode serve from source silently serves the production web UI instead of local code
@neriousy is already working on this.
Since Aug 28, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
The problem
When running the web server from source (bun run --cwd packages/opencode src/index.ts serve), the server silently serves the production https://app.opencode.ai frontend instead of any locally-built code. There is no log, no banner, and no response header indicating that the UI being served is the upstream production build rather than local code.
This makes it very easy to draw wrong conclusions when testing frontend changes: the backend runs your local code, but the entire web UI (which is where all client-side behavior lives) is the published production bundle.
Root cause
embeddedUI() in packages/opencode/src/server/shared/ui.ts does:
import("opencode-web-ui.gen.ts").then((m) => m.default).catch(() => null)
opencode-web-ui.gen.ts is only generated by script/build.ts when compiling a release binary (it inlines packages/app/dist into the binary via Bun.build files). When running from source, the file does not exist, the import rejects, the .catch(() => null) swallows it, and serveUIEffect falls through to proxying UI_UPSTREAM (https://app.opencode.ai) — silently.
Concrete impact (real case)
While testing the Safari IME fix in #44826, I ran opencode serve from a checkout of the PR branch and opened the web UI. Every keystroke in the prompt input still hit the unpatched production editor, because the IME handling is entirely client-side and the served UI was app.opencode.ai. I confirmed this by matching the served bundle hash byte-for-byte with production (index-Ca69RsoK.js). This produced a misleading "the fix doesn't work" result until I served the locally-built packages/app/dist via vite preview and the fix worked.
Anyone testing a frontend fix via opencode serve alone is liable to hit the same trap.
Suggestion
Any of these would prevent the confusion (they are not mutually exclusive):
- Log at startup / on first UI request when falling back to the upstream proxy, e.g.
web UI: no embedded bundle found, proxying https://app.opencode.ai. A single stderr line would have caught this immediately. - Mark the served HTML when proxying (a response header like
x-opencode-ui-source: upstream, or an injected meta tag), so it's inspectable from the browser. - Document in the web/dev docs that source-run
serveproxies the production UI unless a localpackages/app/distis served separately (e.g. viavite dev/vite preview), so contributors know to test frontend changes against the local frontend, not theserveURL.
Environment
- opencode: source checkout on
dev(observed while testing #44826) - OS: macOS 26.6
- Browser: Safari 26.6 (the served-UI source is browser-independent, though)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.