Repository navigation
Description
Description
When multiple OpenCode TUI instances are running, a notification event from one session appears to be handled by every running TUI instance, resulting in duplicate desktop notifications.
This appears related to #20371, but I can reproduce it with the TUI rather than Electron.
dbus-monitor "interface='org.freedesktop.Notifications',member='Notify'"For a single Permission needs input event, I receive two separate Notify calls from different D-Bus senders at essentially the exact same time:
method call time=1790213981.317990 sender=:1.261 -> destination=org.freedesktop.Notifications serial=120 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
string "kitty"
uint32 0
string "/usr/lib/kitty/logo/kitty.png"
string "OpenCode"
string "Permission needs input"
array [
string "default"
string " "
]
array [
dict entry(
string "urgency"
variant byte 1
)
]
int32 -1
method call time=1790213981.318016 sender=:1.285 -> destination=org.freedesktop.Notifications serial=63 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
string "kitty"
uint32 0
string "/usr/lib/kitty/logo/kitty.png"
string "[project] Refactor"
string "Permission needs input"
array [
string "default"
string " "
]
array [
dict entry(
string "urgency"
variant byte 1
)
]
int32 -1
The calls are from two distinct D-Bus senders (:1.261 and :1.285), so the duplication occurs before the notification daemon receives them. What's odd is only one has the recognized window title while the other is generic "OpenCode", even though a titled sesion is open in that window.
Additionally, invoking the default action on each duplicate notification focuses a different OpenCode/kitty TUI instance. This suggests each running TUI is independently handling the same session event and creating its own notification/action.
This seems consistent with the behavior described in #20371, including the potential shared event-listener cause identified there.
Expected behavior
Only the TUI associated with the session/event should emit the desktop notification.
Plugins
none
OpenCode version
v2.0.14
Steps to reproduce
- Run two OpenCode TUI instances in separate terminal windows (I'm using kitty).
- Have a session in one instance reach an event that generates a notification (e.g. permission input or session completion).
- Observe two desktop notifications.
- Monitor the notification calls with:
Screenshot and/or share link
No response
Operating System
Arch Linux
Terminal
Kitty
Activity
kirin-xiao commentedon Oct 9, 2026
Confirmed on v2.0.26; Same root cause as #53203
dylanrussellmd commentedon Oct 17, 2026
Still reproducible on v2.0.29 (Linux 6.18, kitty 0.49.2, niri/Wayland, one shared background service, five TUI instances in separate kitty windows).
With
dbus-monitor "interface='org.freedesktop.Notifications',member='Notify'"running, one main session finishing produced four identicalNotifycalls ("Session done", same session title) within 0.4 ms: one from every TUI that was unfocused and had loadedattention.notifications: true. Only the TUI being looked at stayed quiet.Cause (from reading the bundled
opencode.notificationsCLI plugin): its handlers forsession.execution.succeeded/interrupted/failed,form.createdandpermission.askedcallattention.notify(...)for whateversessionIDthe event carries. Nothing checks whether that session belongs to the current TUI, and the event stream is server-wide (#36441 / #36443), so every connected TUI alerts for every session. This is the same root cause as #53203.Suggested fix: in the notifications plugin, skip events for sessions this TUI doesn't own, e.g. only alert when
data.session.root(sessionID)is the session on screen (ui.router.current()) or is inui.tabs.list(). Subagent sessions are then covered through their root session.Workaround that works: disable the built-in plugin in
cli.json("plugins": ["-opencode.notifications"]) and load a small replacement CLI plugin with the same handlers plus that ownership check. After switching, a 2-hourdbus-monitorcapture showed exactly oneNotifyper session completion, sent only by the TUI that has the session open.MaxGB23 commentedon Oct 19, 2026
Also hit this on v2.0.32 (Windows, several TUIs against one shared server). Tried the ownership-check route first; had to drop it.
ui.router.current()/ui.tabs.list()) works while a session is in a tab. Withtabs.mode: "off"and the TUI sitting on the home screen, no window owns the session, so nothing fires — the echo is fixed but the notifications are gone too.fs.writeFileSync(file, pid, { flag: "wx" })(O_EXCL is atomic between processes) elects exactly one TUI per event. Key it bysessionID, not event id — a failed execution and its later retry carry different ids, so keying by event lets one TUI fire "done" right after another TUI's "error". Clear thedone:claim onsession.execution.startedso the next turn can sound again, and TTL the claims (~30s) so a crashed TUI doesn't hold one forever."plugins": ["-opencode.notifications"]) plus a replacement plugin — there's no API to deactivate another TUI plugin at runtime.Recommendation: don't ship the plain ownership check as-is; it silently drops notifications for anyone on the home screen. Scoping the event stream (#36441 / #36443) would make all of this unnecessary, and that's the fix worth having.
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report and the
dbus-monitorcapture. I reproduced this on v2.0.14, and it still happens on the latestdev(fa1260d).What I did:
opencodeTUIs in separate kitty-like terminals, both connected to the same background server, withattention.notificationsturned on.The script below reproduces it without a real provider. It starts a mock model and prints the notification escape sequences each TUI sent. In my run both notifications used the session title. The "OpenCode" title you saw is most likely the other TUI not having the session's details, which would be the same cause.
The likely cause is that the built-in notifications handler reacts to permission, question and session-finished events for every session on the shared server, not just the ones that TUI is showing. This matches what you described and is related to #20371 (the same problem in the desktop app).
Reproduction script (harness.py)
Run it:
python3 harness.pyevgenyzh commentedon Oct 30, 2026
Same problem on v2.2.1 (Linux): with several TUI clients attached to one shared server, a single session completion produces one
Session donenotification per unfocused TUI (5-6 in my case). The focused TUI stays quiet. Following this issue for updates.