Skip to content

Provide a way to stop all running scripts when OpenCode is interrupted #3057

Closed

Description

@wbruntra

Summary
Currently, when OpenCode determines it should run a script and begins execution, pressing Ctrl-C only interrupts OpenCode itself. Any script or process started by OpenCode continues running in the background, requiring manual intervention to locate and terminate it.

After reviewing related issues, it appears that pressing the Escape key might stop the script, but this behavior wasn't clear in the moment. When I pressed Ctrl-C, I was expecting all processes—including the child script—to stop, especially since Ctrl-C is a common panic escape. Instead, only OpenCode was interrupted and the script continued running in the background.

Steps to reproduce

  1. Use OpenCode to initiate a fix that results in running a script.
  2. Interrupt OpenCode with Ctrl-C while the script is running.
  3. Observe that the script continues running independently (unless Escape is used, which may stop it, but this isn't obvious).

Expected behavior
Interrupting OpenCode with Ctrl-C should terminate any scripts or processes it has spawned, or there should be an easy way for users to stop all related processes. This should be the default behavior for Ctrl-C since it's the familiar way to kill a running process during a panic.

Actual behavior
Only OpenCode itself is stopped; scripts or processes it started continue to run in the background.

Suggested improvement
Make Ctrl-C terminate both OpenCode and any child processes/scripts it started by default. If Escape is an alternative, clarify its behavior in the documentation or UI, but Ctrl-C should be the reliable panic escape that kills everything.

Activity

  1. github-actions commented on Oct 9, 2025

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  2. rekram1-node commented on Oct 9, 2025

    @rekram1-node
    Collaborator

    ah nice catch we should definitely fix thx

  3. self-assigned this
    on Oct 9, 2025
  4. anntnzrb commented on Dec 21, 2025

    @anntnzrb
    Contributor

    LSP processes have the same problem

    The shell cleanup in shell/shell.ts already has proper SIGKILL escalation:

    process.kill(-pid, "SIGTERM")
    await Bun.sleep(200)
    if (!opts?.exited?.()) {
      process.kill(-pid, "SIGKILL")
    }

    However, LSP processes in lsp/client.ts lack this:

    async shutdown() {
      connection.end()
      connection.dispose()
      input.server.process.kill()  // Just SIGTERM, no escalation
    }

    Missing from LSP cleanup:

    1. No SIGKILL escalation — If the process ignores SIGTERM, it lives forever
    2. No process group kill — Uses process.kill() not process.kill(-pid), so child processes (e.g., tsserver spawned by typescript-language-server) survive
    3. No exit verification — Doesn't confirm the process actually terminated

    Reproduction

    When using git worktrees with parallel operations, each worktree spawns its own LSP set. After the session ends, orphaned tsserver processes remain:

    $ ps aux | grep tsserver
    annt  57149  0.1  0.5  ...  tsserver.js ...
    annt  57195  0.1  0.5  ...  tsserver.js ...
    annt  57275  0.0  0.5  ...  tsserver.js ...
    # ... 7+ processes from different worktrees
    

    Suggested fix

    Apply the same cleanup pattern from shell/shell.ts to lsp/client.ts:

    async shutdown() {
      connection.end()
      connection.dispose()
      const proc = input.server.process
      const pid = proc.pid
      try {
        process.kill(-pid, "SIGTERM")
        await Bun.sleep(200)
        // Check if still running, then SIGKILL
        process.kill(-pid, "SIGKILL")
      } catch {
        proc.kill("SIGKILL")
      }
    }

    Related: #5525 (same root cause, Windows-specific report)

  5. anntnzrb commented on Dec 21, 2025

    @anntnzrb
    Contributor

    Opened PRs to address part of this issue:

    These ensure child processes are properly killed when LSP/PTY sessions are disposed. The bash tool abort race condition (where void kill() is fire-and-forget) is a separate issue that will need a follow-up PR.

  6. gkp1 commented on Jan 31, 2026

    @gkp1

    I am having to manually kill processes that opencode 'forgets' running forever, and they remain consuming my cpu for no reason processing something that I don't know what might be, even if I have used+closed opencode hours ago. I suspect it's those times that opencode runs a task in a sub agent (not sure what its called) and it hangs, and then I close opencode and that's probably what leaves those processes there without being killed.

    Today I used tools @general @explore and chrome web devtools mcp, not sure if any are related. Also not sure if it's the main opencode process or sub processes that remain running in background. Probably sub processes that opencode spawns. I always close opencode by closing the terminal or ctrl c then close terminal. On mint ubuntu 24

    (on screenshot below I had 3 opencode processes (killed 1) running, but I didn't have any opencode terminal open, closed hours ago)

    Image
  7. github-actions commented on Apr 1, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 90 days of no activity. If the issue is still relevant please open a new one.

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

Metadata

Metadata

Assignees

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