anomalyco / anomalyco/opencode

opencode serve from source silently serves the production web UI instead of local code

Open
#45,788 0 comments 0 reactions 1 assignee View on GitHub

@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):

  1. 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.
  2. 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.
  3. Document in the web/dev docs that source-run serve proxies the production UI unless a local packages/app/dist is served separately (e.g. via vite dev / vite preview), so contributors know to test frontend changes against the local frontend, not the serve URL.

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.