Repository navigation
Description
Summary
When the shared background service (re)starts, opencode injects a synthetic restart notice into every session that was left unfinished (e.g. an in-flight LLM call when the previous service died or hung), and the agent loop auto-continues without any user action. In our case a session that had been suspended for ~5 hours (hung provider call) auto-resumed twice — once per service start — and executed a destructive system task (elevated UAC script that uninstalled software and deleted engine installations) 7 hours after the user's last interaction with that session. It also killed a process that a different, active session was working with.
Environment
- opencode version: 2.2.0 (latest channel at time of filing)
- OS: Windows 11 Pro 10.0.26100 (win32 x64)
- Terminal: Orca (TERM_PROGRAM=Orca, TERM=xterm-256color, COLORTERM=truecolor)
- Shell: PowerShell 7 (pwsh) for opencode shell tool; COMSPEC=cmd.exe
- Install/channel: npm global
@opencode/cli@2.2.0, release - Active plugins: billion-context, opencode-zai-usage, universal-modder
- Provider: z.ai coding plan (glm-5.3-max)
Reproduction
- Start a session and give it a multi-step task with side effects (e.g. "uninstall X completely, don't miss anything").
- While the agent is mid-generation (LLM call in flight), let the provider call hang or kill the shared service process. The session stays in a suspended/unfinished state. In our case one assistant message stayed in-flight for ~4h48m (created 10:06:18, completed 14:56:24 — no timeout fired).
- Hours later, start any opencode TUI (this starts a new shared service).
- The service injects a synthetic user-role message into the suspended session:
{"metadata":{"notice":"restart"},"text":"The server restarted while you were working. Continue from where you left off without repeating completed work.","description":"Continuing after restart"} - The agent auto-continues the task with full destructive context, executing shell commands (including elevation via
Start-Process -Verb RunAs→ UAC) without the user ever touching that session.
Observed twice in one day, for multiple sessions: an orchestrator session and an unrelated stalled research subagent both auto-continued on both service starts, confirming this is systemic behavior on service start, not a one-off.
Expected Behavior
A session the user has not interacted with for hours should never resume executing on its own. Restart recovery should at most mark the session as interrupted and wait for an explicit user "continue", or ask for confirmation before continuing — especially before running shell commands with side effects. Auto-continuation of the current turn immediately after a crash-restart may be desirable UX, but silently finishing an hours-old task is dangerous.
Actual Behavior
Timeline (local time = UTC+3; timestamps from opencode.db session_message rows and log/opencode.log):
- 09:50 — user starts session A (task: fully uninstall Epic Games Launcher / Epic Online Services / Unreal Engine). Agent works 09:51–10:06.
- 10:06:18 — session A's assistant message created; the provider call hangs and the session stays suspended mid-run. The user considers that session long finished and works in other sessions/projects.
- 14:56:19 — shared service start feat: compact and other improvements #1 (previous service had died). Synthetic restart notice injected into session A → agent auto-continues: starts searching disks for engine installations.
- 15:48:40 — shared service start Roadmap & Existing Issues #2 (user launched a TUI in a terminal). Second synthetic restart notice → agent auto-continues again.
- 15:50:00–15:50:25 — session A writes a removal script and launches it elevated (
Start-Process pwsh -Verb RunAs, UAC approved by a user who was mid-context-switch). The script kills Epic/Unreal processes — including an UnrealEditor instance that a different, active session was driving via MCP at that moment — uninstalls Epic Online Services (msiexec /x), deletes engine folders, and scrubs registry entries. - 15:52:55 — session A reports success. The user had not touched session A since 10:06 and did not ask for it to continue.
A stalled research subagent session (no user interaction since 10:08) auto-continued at 14:56:19 and 15:48:40 the same way, spending tokens and running web requests on its own.
Additional Context
- All evidence extracted from
~/.local/share/opencode/opencode.db(tablessession_v2,session_message,session_inbox) andlog/opencode.log(shared-service bootstrap run; shell spawn entries). DB excerpts available on request. - The hung ~4.8h provider call (no timeout, message completed only when the restart notice arrived) may deserve separate investigation.
- Impact was compounded by default permissions (everything allowed). We mitigated locally with
permissionsask-rules for destructive shell patterns, but the resume-without-consent behavior is the root issue. - Workaround found: none (no config flag to disable restart auto-resume). We had to delete the suspended sessions from the DB to prevent recurrence.
- Related issues (same restart-resume family): Background service resumes opencode run --standalone sessions after the run was killed, without its permissions or step limit (runaway: 1,660 steps, ~$24) #55076 (background service resumes killed sessions without permissions or step limit — runaway 1,660 steps), v2: declining a tool call is recorded as shutdown, so the declined turn resumes after a server restart #54180 (declined turn resumes after server restart), Background service resumes sessions still running on another server that shares the database #51213 (service resumes sessions still running on another server that shares the database).
Activity
opencode-agent commentedon Oct 27, 2026
Thanks for the detailed timeline and for tracing this through the database and logs. That's a serious outcome, and the write-up makes it very clear.
I think this is a duplicate of #56032. That issue reports the same thing: when the background service starts, it resumes every suspended session with no user action. It asks for a way to keep those sessions parked until you continue them yourself. I checked the current code, and restart recovery (
packages/core/src/session/execution/restart.ts) resumes every session whose turn didn't finish, each time the service starts. The only limit is how many times one turn may be resumed. There is no age check, no confirmation step and no setting to turn it off. That's why a session left alone for about 5 hours resumed on both service starts.Possible duplicates and related issues, most likely first:
opencode run --standaloneruns).session.prompt, so plugins can't stop or check them.The provider call that hung for about 4.8 hours without timing out is a different problem, and none of these issues cover it. If you can, please open a separate issue for it with the provider and model details and the relevant log lines.
The bot will close this issue as a duplicate of #56032 in 1 day unless you reply explaining how your problem is different.
KonstantinChizhov commentedon Oct 29, 2026
Same issue. Old interrupted task resumes on opencode startup in background. No way to stop it except to kill opencode process. Reproduced in version 2.2.1
YegorMy commentedon Oct 30, 2026
A related case that is a correctness problem, not only a consent one: when two OpenCode servers share one data directory, the service's boot recovery can resume sessions that are still running in the other server, so the same session ends up with two executors.
Setup
We run a small local orchestrator (our own job runner). It starts a dedicated server with
opencode serve --hostname 127.0.0.1 --port <fixed>and drives agent sessions through the HTTP API: it creates sessions, prompts them, and lets them spawn subagents, includingbackground: trueones. On the same machine and user account, the regular CLI/TUI uses the background service (opencode serve --service). Both servers use the default data directory, so they share oneopencode.db.What the 2.2.0 code does
ServerProcess.startrunsSessionRestart.resumeSuspendedSessionsonly for service mode (theonListenpath). A plainopencode servenever runs it.resumeSuspendedSessionsbuilds its target set from:SessionStore.listSuspended(), i.e. sessions withtime_suspended IS NOT NULL AND parent_id IS NULL;job.background/*records withstatus: "running"andrecovery.kind: "subagent".countResume(cap 10), the synthetic "The server restarted while you were working…" notice andresume(...).session_v2.time_suspended) and thejob.background/*records live in the shared DB and carry no owner. A session currently executing in the other server looks exactly like a crashed one. Restarting the background service while the orchestrator's server runs work would resume those live roots a second time.We also had stale entries that recovery would have revived days later. A disk-full (ENOSPC) event stopped several sessions mid-step. Their claims stayed set, and one background-subagent job stayed
status: "running"with no terminal record. The next service boot would have woken those agents as writers in their old working trees.No native way to settle such a session
POST /api/session/:id/interrupton an inactive session is the documented idle no-op. It releases neither the claim nor the background job.listSuspendedand job recovery don't filter ontime_archived.SessionRestartis built with defaults (maxAttempts10).DELETE /api/session/:id. It works, but it destroys the history.Suggestions
Our current workaround is to avoid restarting the background service while the orchestrator's server has work in flight, and to delete the orphaned sessions (after exporting them) when needed. We are also considering a separate data directory for the orchestrator's server, but that also separates provider logins, so per-instance ownership upstream would be the cleaner fix.