Description
I run one opencode serve and attach several TUIs to it, each in a different directory. Two things go wrong.
The branch in the bottom right of the sidebar sometimes shows a branch belonging to a different project. The directory stays correct, only the branch is wrong, and it changes on its own when I switch branches in one of the other checkouts. The second one is that a session switch driven from the server navigates the wrong TUI, or more than one at a time.
Both come from the same place. The TUI subscribes to /global/event. That route is registered on RootHttpApi without the directory middleware, so the ?directory= the SDK sends is ignored and every instance's events reach every connected client. On the client side the handlers only compare workspace, and that is undefined on both the event and the store unless experimental workspaces are enabled, so undefined === undefined passes and each TUI applies the other TUIs' events. packages/tui/src/context/event.ts receives directory in the metadata but never filters on it.
Where it shows up:
vcs.branch.updated in packages/tui/src/context/sync.tsx writes any directory's branch into every TUI's store. The sidebar guard at packages/tui/src/feature-plugins/sidebar/footer.tsx:23 compares directories, not branches, so it renders my own directory next to another project's branch. packages/tui/src/context/directory.ts:14 has no guard at all.
tui.session.select in packages/tui/src/app.tsx navigates every attached TUI instead of the one it was aimed at. Same for tui.toast.show, tui.command.execute and tui.prompt.append.
packages/app already partitions this same stream by directory in src/context/server-sync.tsx, the TUI does not.
Worth flagging that #31469 is the same line with the opposite symptom. Its analysis says the event is "already scoped to the correct project by event.ts:19", which is not the case, event.ts only forwards the metadata. Removing the workspace guard as suggested there would make this leak worse unless directory scoping lands first.
I have a fix and will open a PR against this.
Plugins
opencode-forge. It triggers the session switch symptom because it is the only thing calling tui.selectSession programmatically, but the fan-out itself is not plugin specific.
OpenCode version
1.18.5
Steps to reproduce
- start a server with
opencode serve
- attach a TUI in repo A, on branch
main
- attach a second TUI in repo B
- in repo B run
git checkout -b feature
- repo A's sidebar now reads
~/repo-a:feature
Screenshot and/or share link
Not included.
Operating System
macOS 26.5.2
Terminal
Ghostty
Description
I run one
opencode serveand attach several TUIs to it, each in a different directory. Two things go wrong.The branch in the bottom right of the sidebar sometimes shows a branch belonging to a different project. The directory stays correct, only the branch is wrong, and it changes on its own when I switch branches in one of the other checkouts. The second one is that a session switch driven from the server navigates the wrong TUI, or more than one at a time.
Both come from the same place. The TUI subscribes to
/global/event. That route is registered onRootHttpApiwithout the directory middleware, so the?directory=the SDK sends is ignored and every instance's events reach every connected client. On the client side the handlers only compareworkspace, and that isundefinedon both the event and the store unless experimental workspaces are enabled, soundefined === undefinedpasses and each TUI applies the other TUIs' events.packages/tui/src/context/event.tsreceivesdirectoryin the metadata but never filters on it.Where it shows up:
vcs.branch.updatedinpackages/tui/src/context/sync.tsxwrites any directory's branch into every TUI's store. The sidebar guard atpackages/tui/src/feature-plugins/sidebar/footer.tsx:23compares directories, not branches, so it renders my own directory next to another project's branch.packages/tui/src/context/directory.ts:14has no guard at all.tui.session.selectinpackages/tui/src/app.tsxnavigates every attached TUI instead of the one it was aimed at. Same fortui.toast.show,tui.command.executeandtui.prompt.append.packages/appalready partitions this same stream by directory insrc/context/server-sync.tsx, the TUI does not.Worth flagging that #31469 is the same line with the opposite symptom. Its analysis says the event is "already scoped to the correct project by event.ts:19", which is not the case, event.ts only forwards the metadata. Removing the workspace guard as suggested there would make this leak worse unless directory scoping lands first.
I have a fix and will open a PR against this.
Plugins
opencode-forge. It triggers the session switch symptom because it is the only thing calling
tui.selectSessionprogrammatically, but the fan-out itself is not plugin specific.OpenCode version
1.18.5
Steps to reproduce
opencode servemaingit checkout -b feature~/repo-a:featureScreenshot and/or share link
Not included.
Operating System
macOS 26.5.2
Terminal
Ghostty