Skip to content

server: non-service startup skips restart continuity for suspended sessions #56313

Open

Description

@HeZ2z

Description

OpenCode's restart continuity sweep is only installed when the server is started through the managed --service path. A long-lived server started without that lifecycle path can leave suspended Sessions and in-flight background subagent jobs permanently stranded after a process restart: the child is not resumed, its completion is not delivered, and the parent remains silent.

This is distinct from the parent/child watcher reconstruction tracked in #36349. The issue here is that no restart sweep is installed at all for non-service startup.

Steps to reproduce

  1. Start OpenCode using a non-service server/TUI process (without --service).
  2. Start a background subagent and keep it in flight while the server process is terminated.
  3. Start the same server again against the same persistent data directory.
  4. Observe that the suspended child is not resumed and the parent receives no completion.
  5. Repeat through opencode service start / --service and compare: the managed restart continuity path is installed there.

The relevant code path is installRestartContinuity, which is guarded by the presence of the lifecycle/service options.

Expected behavior

Every supported long-lived server startup should either install restart continuity or clearly document and surface that suspended Sessions and background jobs will not be recovered.

Actual behavior

Non-service startup has no restart sweep, so persisted in-flight work can remain indefinitely without a consumer.

Evidence

This was identified while investigating oh-my-opencode-slim issue #1560. In an isolated persistent-data instance, managed service restart recovery worked end to end; the missing lifecycle path is the deterministic difference for this failure mode.

Related: #36349, #35646

OpenCode version

2.0.30 (isolated reproduction)

Plugins

Reproduced conceptually with and without oh-my-opencode-slim; the missing sweep is host-side.

Operating System

macOS (isolated local instance)

Activity

  1. opencode-agent commented on Oct 17, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up, @HeZ2z!

    You're asking for restart continuity (resuming suspended Sessions and in-flight background subagents) on long-lived servers started without --service, or failing that, for docs and a warning that they don't recover this work.

    The code backs up what you describe: in packages/server/src/process.ts, installRestartContinuity runs only for the managed service. That looks deliberate, though. The code comment says the managed server owns restart continuity, and recent work has been narrowing automatic recovery for non-service processes, not widening it, because unexpected resumes caused problems. So I've filed this as a feature or design request rather than a bug. Maintainers will consider it, but I can't promise anything.

    Related issues:

  2. Dante-dan commented on Oct 20, 2026

    @Dante-dan
    Contributor

    I propose making restart continuity an explicit server capability, with the existing managed-service behavior preserved, rather than enabling the sweep for every Node startup.

    There is an important entry-point distinction at current dev (6e9c853):

    For a bounded first change, I suggest exposing the startup recovery capability from the server (enabled for the managed path, disabled for non-service Node startup), then surfacing the disabled state in the long-lived foreground server/TUI flow with a concise explanation that restart alone will not resume interrupted work. stdio must retain its machine-readable startup protocol. Document the separate fetch-embedder responsibility alongside this, without changing its execution behavior. This addresses the issue's requested visible explanation without automatically taking over persisted work or promising that parent/child delivery is solved.

    Broader non-service automatic recovery should be a separate opt-in design: it needs durable recovery eligibility plus cross-process owner-liveness/ownership semantics, and a decision about which execution environment is safe to restore. Merely removing if (lifecycle) or using a port/registration lock would not establish those guarantees for every writer of a shared database. I would coordinate that part with the existing ownership/eligibility work rather than duplicate it. #36349 remains a separate completion-delivery concern.

    Could a maintainer approve the bounded capability/foreground explanation approach, or specify that non-service recovery itself should be the first implementation? Acceptance would cover the service/default/stdio/fetch boundary, unchanged recovery invocation counts, unchanged stdio output, and no persisted-state mutation from the explanation path. This is based on source inspection; I have not reproduced the original macOS scenario or run runtime tests for this proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions