anomalyco / anomalyco/opencode

macOS: exit/cleanup path broadcasts SIGTERM to ALL user processes (kill -1) — kills Ghostty, Terminal, Chrome, entire session (1.18.24 & 1.18.25)

Open
#45,938 2 comments 0 reactions 1 assignee View on GitHub

@nexxeln is already working on this.

Since Aug 28, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

On macOS, opencode's exit/cleanup path broadcasts SIGTERM to every process the user owns — the equivalent of kill(-1, SIGTERM). Quitting opencode (or killing a stuck one) took down my entire session every time: Ghostty, Terminal.app, Google Chrome, and every user-level agent, all at once. There are no crash reports for the killed apps because they die from signal 15.

This happened repeatedly today on two exit paths:

  1. Normal exit / SIGTERM to a running opencode run process → immediate broadcast.
  2. Orphaned children: SIGKILL the main opencode process and a surviving child process (also named opencode) fires the same broadcast ~1 minute later.

Confirmed on both 1.18.24 and 1.18.25 (downgrading did not help), installed via the official install script.

Environment

  • macOS 26.5.2 (25F84), Apple Silicon (Mac15,7)
  • opencode 1.18.24 and 1.18.25, ~/.opencode/bin/opencode via https://opencode.ai/install

Evidence

The kernel's sandbox logs the broadcast when it denies the protected (system) targets. Unprotected user processes (terminals, browser) are killed successfully. From log show, at the moment an opencode process exited:

kernel (Sandbox) System Policy: opencode(37536) deny(1) signal initproc signum:15
kernel (Sandbox) System Policy: opencode(37536) deny(1) signal same-sandbox [xprotectd(389)] signum:15
kernel (Sandbox) System Policy: opencode(37536) deny(1) signal others [systemstatusd(448)] signum:15
kernel (Sandbox) System Policy: opencode(37536) deny(1) signal same-sandbox [suhelperd(576)] signum:15

signal initproc = it attempted to signal launchd (pid 1), which only happens with a kill-everything call. Three separate incidents logged today (08:21, 08:32, 09:06 local), the last one from 1.18.24.

To isolate it, I ran opencode inside a sandbox-exec profile that denies signals outside its own process tree, then sent it a plain SIGTERM. The kernel then logged opencode attempting to SIGTERM every process on the system, one by one:

kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [AirPlayXPCHelper(419)] signum:15
kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [KernelEventAgent(411)] signum:15
kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [mds(378)] signum:15
kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [powerd(363)] signum:15
kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [thermalmonitord(387)] signum:15
kernel (Sandbox) Sandbox: opencode-real(65034) deny(1) signal others [bluetoothd(415)] signum:15
... (continues for every pid on the box)

A canary process with a TERM trap, running outside the sandbox, received nothing — confirming the sandbox was the only thing standing between opencode's exit and the rest of the session.

Steps to reproduce

  1. macOS: opencode run "reply with exactly: OK" (or open the TUI).
  2. Send the process SIGTERM (or just let it exit), with other apps open.
  3. Watch every user-owned process receive SIGTERM. To observe it non-destructively, wrap opencode in a sandbox-exec profile ((version 1)(allow default)(deny signal)(allow signal (target same-sandbox))) and watch the kernel denials in log show.

Expected behavior

On exit, opencode should signal only its own children / process group — never -1. This looks like a cleanup call of the form process.kill(-pid, 'SIGTERM') where pid ends up as 1 (e.g. using getppid() after the parent died and the child was reparented to launchd), or an equivalent kill(-1).

Possibly related (terminal dies on exit, Windows): #35327, #22003, #36671.

Workaround

Rename the real binary and front it with a signal-guard wrapper:

  • macOS: sandbox-exec -f guard.sb ~/.opencode/bin/opencode-real "$@" with the profile above.
  • Linux: bwrap --dev-bind / / --proc /proc --unshare-pid --die-with-parent ~/.opencode/bin/opencode-real "$@".

With the guard in place opencode works normally, and its exit broadcast hits nothing outside its own tree.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.