You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
V2: after a hard crash, --standalone / opencode serve never settle the interrupted shell tool, so the TUI spins forever #58386
If the server dies hard (SIGKILL, OOM, machine or WSL shutdown) while a shell tool is running, the tool part stays running in the database. The background service (serve --service) cleans this up on start: it marks the tool Tool execution interrupted: shell and resumes the turn. A private server started by opencode --standalone, or plain opencode serve, does not. When the session is reopened:
The TUI shows ⠸ echo hello && sleep 600 with an animated spinner and Press ctrl+b to move running work to the background, but no process is running and GET /api/session/active returns {}.
The spinner redraws about 12 times a second indefinitely. Idle, that is about 11 KB of terminal output every 10s and ~2.3% of a core in the TUI, compared with ~0.5% and 0 bytes once the tool is settled.
A graceful stop is fine in every mode: POST /api/session/{id}/interrupt, SIGTERM, a model error partway through a reply, or killing only the TUI (the stdio server gets EOF and settles the tool).
This is the hard-crash case from #35642. That issue was closed on 2026-07-09 with a request to open a focused issue if it still reproduces. It reproduces on 2.1.2 outside the background service.
Two smaller things seen along the way:
The TUI decides to show a tool spinner from state.status === "running" || "streaming" alone. It never checks whether the session is actually running, so any stale part keeps animating. "animations": false stops it.
opencode session export leaves out the unfinished assistant message entirely.
None. Clean config and data dirs (isolated XDG_* directories).
OpenCode version
2.1.2
Steps to reproduce
I used a local OpenAI-compatible mock model that calls the shell tool with echo hello && sleep 600. Any real model running a long command behaves the same way.
opencode --standalone -s <id> --prompt "run the demo". Wait until sleep 600 is running.
Kill the TUI and its serve --stdio child together with kill -9, which is what a machine or WSL shutdown does.
opencode --standalone -s <id>. The command is still shown as running with a spinner and the ctrl+b hint.
You get the same result by running opencode serve, prompting through the HTTP API, then kill -9 the server and restart it. Doing the same with opencode serve --service recovers correctly.
Screenshot
┃ rundemo
+ Thought · 7ms
┃ ⠸ echo hello && sleep 600
Press ctrl+b to move running work to the background
Operating System
Ubuntu 24.04 (Linux 7.0, x86_64). First noticed on WSL.
Terminal
Measured in a pty harness (xterm-256color, 57x226).
Thanks for the detailed report. I could reproduce this on 2.1.2 with a plain opencode serve and a mock OpenAI-compatible model that calls shell with echo hello && sleep 600:
Prompt over the HTTP API and wait until the command is running. The session shows as running in /api/session/active.
kill -9 the server, then start opencode serve again on the same data directory.
/api/session/active now returns {}, but the shell tool part in /api/session/{id}/message is still status: "running" and never gets settled. The TUI spinner is drawn from that state.
It still happens on the latest dev (4d30794). The code matches what you describe: the startup cleanup in packages/server/src/process.ts (installRestartContinuity / resumeSuspendedSessions) only runs for the background service (serve --service), so a plain serve or the private --standalone server never cleans up the interrupted tool.
The script below reproduces it automatically. I checked this through the API only and didn't make a TUI recording: the test harness always starts its server with --service, which recovers correctly.
Activity
opencode-agent commentedon Oct 23, 2026
Thanks for the detailed report. I could reproduce this on 2.1.2 with a plain
opencode serveand a mock OpenAI-compatible model that callsshellwithecho hello && sleep 600:runningin/api/session/active.kill -9the server, then startopencode serveagain on the same data directory./api/session/activenow returns{}, but the shell tool part in/api/session/{id}/messageis stillstatus: "running"and never gets settled. The TUI spinner is drawn from that state.It still happens on the latest
dev(4d30794). The code matches what you describe: the startup cleanup inpackages/server/src/process.ts(installRestartContinuity/resumeSuspendedSessions) only runs for the background service (serve --service), so a plainserveor the private--standaloneserver never cleans up the interrupted tool.The script below reproduces it automatically. I checked this through the API only and didn't make a TUI recording: the test harness always starts its server with
--service, which recovers correctly.Reproduction script (repro.sh)
Run it:
bash repro.sh