Repository navigation
Description
opencode serve accepts requests while plugin npm install is still blocking
OpenCode's HTTP server starts listening and emits server.connected on the SSE stream before plugin npm reify finishes. During the reify window the event loop is blocked, so any API call hangs and eventually fetch faileds with no useful error. We've measured this window at 5+ minutes on CI runners.
There is no way for a caller to know the server is ready to process requests.
Related: #19197 (OpenCode 1.3.2 has ~75 seconds startup delay). Same root cause, more severe in CI environments.
Repro
# Start a server with a fresh cache (no warm npm cache) and a plugin in config
rm -rf ~/.cache/opencode/packages/oh-my-openagent
opencode serve --port 4096 &
# Immediately try to make any API call
sleep 1
curl --max-time 10 -sS http://localhost:4096/session/list
# → curl: (28) Operation timed out after 10001 milliseconds with 0 bytes receivedThe server is bound and the SSE server.connected event has already been emitted, but /session/list never gets a response until npm reify completes.
Observed timeline (production CI)
| Time | Event |
|---|---|
| 00:00 | opencode serve spawned |
| 00:01 | Server bound, SSE emits server.connected |
| 00:01 | Client (@opencode-ai/sdk) sends POST /session |
| 00:01 | npm reify starts for @fro.bot/systematic, oh-my-openagent |
| 04:58 | npm reify completes (298s) |
| 04:59 | Server starts processing the queued /session request — too late, client already aborted with fetch failed |
Sample log from a CI run: 298s blocking window
What we'd like upstream
One of:
- Block server bind until plugin reify completes. Simplest model — clients can rely on "if I can connect, you're ready".
- Emit a
server.readyevent on the SSE stream after reify. Lets clients distinguish "connected" (TCP bound) from "ready" (event loop free). Backwards-compatible — existing clients that connect-and-go don't break, new clients can wait forready. /healthendpoint that returns 503 during reify, 200 once ready. Most ergonomic for HTTP clients, no SSE knowledge needed.
Option 2 is the smallest semantic change. Option 3 is the most conventional. Either works for our use case.
Mitigation we've applied downstream
fro-bot/agent#492 — exponential retry backoff (5s → 15s → 30s → 60s) with ~/.cache/opencode/packages/ cached in CI. Reify still happens; the cache just makes it faster. Backoff covers the cold-cache window.
This works but is not a substitute for a real readiness signal — if reify exceeds 110s total wall clock, the client gives up.
Repro environment
- OpenCode 1.14.41 (also reproduces on 1.14.48, 1.15.0, 1.15.1)
- Plugins:
@fro.bot/systematic,oh-my-openagent - Ubuntu 24.04 GitHub Actions runner (cold cache)
Happy to provide additional logs or test against a candidate fix.
Activity
github-actions commentedon Jul 17, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.