Motivation
When used as a mobile client, the bot often runs 24/7 on a low-spec machine (small VPS, home server, laptop that stays on). The heavy resource consumer is the spawned opencode serve process and its model workers (hundreds of MB–GB). For users who work in short, sporadic bursts from a phone, keeping the server alive around the clock wastes memory for no benefit.
The project already manages the local server lifecycle in a few places:
- manual start/stop (
/opencode_start, /opencode_stop)
- optional health-checked auto-restart (
OPENCODE_AUTO_RESTART_ENABLED)
The missing piece is the inverse of auto-restart: stop the server when idle, start it again on demand. This proposal adds that as an optional, opt-in mode that mirrors the existing process-management design.
Proposed behavior
- Stop on idle. While the bot is running and
opencode serve is active, track "last activity" (the last dispatched prompt / last active run). If the server stays idle for OPENCODE_IDLE_SHUTDOWN_SEC, shut it down gracefully and release all bot-side runtime state, exactly like /opencode_stop does.
- Start on demand. When the server is down and a prompt (text/voice/photo/attachment) or a command that needs OpenCode arrives, start the local server and wait for it to become ready before dispatching — the same flow as
/opencode_start. The readiness lifecycle (opencodeReadyLifecycle) then re-attaches to the last session and re-subscribes to SSE, so the resumed session and notifications keep working.
Configuration
New env flags (all off by default, matching the existing convention):
# Seconds of inactivity before the local server is stopped (0 = disabled)
OPENCODE_IDLE_SHUTDOWN_SEC=0
# Wait for the server on demand instead of erroring when it is down (default: false)
OPENCODE_START_ON_DEMAND=true
OPENCODE_START_ON_DEMAND is implicitly enabled when OPENCODE_IDLE_SHUTDOWN_SEC > 0.
Important interaction: mutual exclusion with auto-restart
OPENCODE_AUTO_RESTART_ENABLED restarts the server as soon as it sees it unhealthy (src/opencode/auto-restart.ts). That would undo an idle shutdown. The two modes must be mutually exclusive:
- If auto-restart is enabled, idle-shutdown should be ignored (or rejected) with a clear log message.
- Committing to health-monitor restart only makes sense for "should always be up"; idle-shutdown is for "should be up only while in use."
Why state is safe across restarts
Sessions and projects are persisted on disk by OpenCode. On server ready, opencodeReadyLifecycle.onReady (src/bot/index.ts) already restores the followed session and re-subscribes to events, so resuming after an idle stop is functionally identical to the existing manual /opencode_start path.
Suggested implementation (self-contained, mirrors existing code)
- Stop path: reuse
findServerPid + killServerProcess (src/opencode/process.ts) and the state-release logic in releaseLocalStateAfterServerStop (src/bot/commands/opencode-stop-command.ts). Add an idle timer that tracks last prompt dispatch time — natural sources are foregroundSessionState and assistantRunState.
- Start path: reuse
startLocalOpencodeServer + the waitForServerReady/health-check block from opencode-start-command.ts, triggered from processUserPrompt (src/bot/handlers/prompt.ts) and the OpenCode-dependent commands before they fail.
- Orchestration: a small sibling to
OpencodeAutoRestartService (e.g. OpencodeIdleShutdownService) so the health/ready notifications stay centralized in ready-lifecycle.ts.
Tradeoffs
- Cold start latency: the first prompt after an idle period waits for server startup + model load (a few seconds). Acceptable in exchange for RAM savings, but worth flagging in the response text.
- Scope: this is an ops/resource optimization, not a UX change, and stays strictly within the "single OpenCode CLI window" concept.
Open questions for the maintainer
- Should idle-shutdown also consider a dedicated
/opencode_stop//opencode_start command rather than pure auto behavior? (Commands already exist; this proposal keeps them.)
- Preferred inactivity unit/limits and whether to expose a per-user setting via
/settings or keep it env-only.
Motivation
When used as a mobile client, the bot often runs 24/7 on a low-spec machine (small VPS, home server, laptop that stays on). The heavy resource consumer is the spawned
opencode serveprocess and its model workers (hundreds of MB–GB). For users who work in short, sporadic bursts from a phone, keeping the server alive around the clock wastes memory for no benefit.The project already manages the local server lifecycle in a few places:
/opencode_start,/opencode_stop)OPENCODE_AUTO_RESTART_ENABLED)The missing piece is the inverse of auto-restart: stop the server when idle, start it again on demand. This proposal adds that as an optional, opt-in mode that mirrors the existing process-management design.
Proposed behavior
opencode serveis active, track "last activity" (the last dispatched prompt / last active run). If the server stays idle forOPENCODE_IDLE_SHUTDOWN_SEC, shut it down gracefully and release all bot-side runtime state, exactly like/opencode_stopdoes./opencode_start. The readiness lifecycle (opencodeReadyLifecycle) then re-attaches to the last session and re-subscribes to SSE, so the resumed session and notifications keep working.Configuration
New env flags (all off by default, matching the existing convention):
OPENCODE_START_ON_DEMANDis implicitly enabled whenOPENCODE_IDLE_SHUTDOWN_SEC > 0.Important interaction: mutual exclusion with auto-restart
OPENCODE_AUTO_RESTART_ENABLEDrestarts the server as soon as it sees it unhealthy (src/opencode/auto-restart.ts). That would undo an idle shutdown. The two modes must be mutually exclusive:Why state is safe across restarts
Sessions and projects are persisted on disk by OpenCode. On server ready,
opencodeReadyLifecycle.onReady(src/bot/index.ts) already restores the followed session and re-subscribes to events, so resuming after an idle stop is functionally identical to the existing manual/opencode_startpath.Suggested implementation (self-contained, mirrors existing code)
findServerPid+killServerProcess(src/opencode/process.ts) and the state-release logic inreleaseLocalStateAfterServerStop(src/bot/commands/opencode-stop-command.ts). Add an idle timer that tracks last prompt dispatch time — natural sources areforegroundSessionStateandassistantRunState.startLocalOpencodeServer+ thewaitForServerReady/health-check block fromopencode-start-command.ts, triggered fromprocessUserPrompt(src/bot/handlers/prompt.ts) and the OpenCode-dependent commands before they fail.OpencodeAutoRestartService(e.g.OpencodeIdleShutdownService) so the health/ready notifications stay centralized inready-lifecycle.ts.Tradeoffs
Open questions for the maintainer
/opencode_stop//opencode_startcommand rather than pure auto behavior? (Commands already exist; this proposal keeps them.)/settingsor keep it env-only.