anomalyco / anomalyco/opencode
[FEATURE] Desktop: persist sidecar server URL/credentials to disk (XDG_STATE_HOME) so companion tools can auto-discover
@Hona is already working on this.
Since Sep 4, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
The Desktop app's embedded server (sidecar) is only reachable by the app's own renderer. Companion tools running on the same machine (status-bar widgets, CLI wrappers, IDE extensions, automation scripts) cannot discover or authenticate to it, because the server URL/credentials are generated in memory and never persisted.
Currently the only working "API" for external tools is scraping main.log for the URL:
[info] server ready { url: 'http://127.0.0.1:62057' }
…but the log never contains the password, so discovery always ends in HTTP 401.
Current behavior (v1.18.26, macOS)
-
out/main/index.js:const password = randomUUID();— a fresh password per launch, passed to the sidecar viapostMessage, never written to disk. -
out/main/sidecar.js→prepareSidecarEnv()unconditionally overwrites the environment:Object.assign(process.env, { OPENCODE_SERVER_USERNAME: "opencode", OPENCODE_SERVER_PASSWORD: password, // always the IPC-provided value ... })so externally fixing the password (e.g.
launchctl setenv OPENCODE_SERVER_PASSWORD ...) has no effect. -
The password is only visible inside processes the server itself spawns (session tool processes). Tools outside that process tree cannot read it:
ps -Eshows the kernel-initial env, and the runtime-injected value is not there.
Result: every desktop restart rotates port + password, and each external tool has to implement a hack — e.g. running a "bridge" script inside an opencode session that dumps its own env to a well-known file — which only works after a session has started, and silently breaks again on the next restart.
Proposal
After server ready, persist the endpoint once, atomically, with 0600 perms, e.g.:
// $XDG_STATE_HOME/opencode/server.json (sidecar already sets XDG_STATE_HOME)
{
"url": "http://127.0.0.1:62057",
"username": "opencode",
"password": "<uuid>",
"pid": 52431,
"writtenAt": 1788490335685
}
- Rewrite it on every (re)start; remove or invalidate it on clean shutdown.
- Loopback-only listener + same-user-readable file puts it in the same trust domain as the existing env-var mechanism used by the CLI (
OPENCODE_SERVER_PASSWORD), so no new attack surface.
(Alternative, also fine: let the desktop honor an externally provided OPENCODE_SERVER_PASSWORD instead of always generating one. Then tools can pin credentials via launchctl setenv and discover the port from main.log/lsof as they already do.)
Precedent inside the same codebase
The v2 CLI background-service path already treats credentials as externally retrievable:
const url = await run(binary, ["service", "start"], ...)
const password = await run(binary, ["service", "get", "password"], ...)
The desktop sidecar is currently the only server mode whose credentials are unreachable from outside the process tree.
Alternatives considered (and why they don't work today)
- A plugin that writes credentials on startup — natural place for it, but desktop plugin loading is broken/limited on 1.18.x (see #41033, #38604, #44367), so it can't be relied on.
- Scraping
ps -EforOPENCODE_SERVER_PASSWORD— the value is injected at runtime, so it only appears in short-lived session tool processes; not a stable discovery channel.
Persisting the endpoint (or honoring an external password) would let the growing ecosystem of companion tools connect zero-touch, instead of every tool shipping its own rebridge hack.
Environment
- OpenCode Desktop 1.18.26, macOS 15 (arm64)
- Reproduction: start desktop →
curl -u opencode:anything http://127.0.0.1:<sidecar-port>/global/health→ 401, with no supported way to learn the real password from outside the app.
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.