Repository navigation
[Bug]: OpenCode panes that share a directory attribute every session to the first pane that started the shared server #22838
Description
Operating system
macOS (the code involved is platform-neutral; the same path runs on Linux and Windows)
Orca version
1.4.210, and still reproducible on main at 7a4f080086
Details
Symptoms
- Two panes show a spinning "working" icon for one running task.
- The pane that actually owns the task shows grey/idle while it works.
These two appear together, which is the tell: one session's status is landing on the wrong pane.
Before / after as the user sees it
Open two OpenCode agents in panes that share a directory — split panes inside one worktree, or two sibling folder-workspace panes, which are backed by the same folder. Whichever pane happened to start OpenCode's background service reports all of the work: it spins while the other pane's task runs, and the pane that really owns the task never lights up.
Expected: each pane reports only its own session.
Relationship to previous attempts
This is the residual case of #21359, which reported this same symptom and was closed as fixed by #21577. The reporter there identified the exact root cause this issue covers: "both panes here share one project directory, so even the directory cannot tell them apart."
#21577 introduced the rebinding mechanism — the session→pane registry, the correlator and the binder round all land in 646fa3645f. But the correlator only emits an owner when exactly one pane qualifies, and a shared directory makes two qualify, so the case #21359 actually described stayed unbound. That limitation is deliberate and locked in by that PR's own test:
it('stays unbound when both same-directory panes evidence a client', ... expect(results).toEqual([])
So this is neither a new bug nor a regression — it is the tie the first fix consciously declined to guess at, now given evidence that can break it.
Other attempts adjacent to this symptom, for anyone landing here first: #22764 / #22768 cover a different cause of grey panes (the plugin failing to load at all, because the OPENCODE_CONFIG_DIR copy is never regenerated), and #11210 was flagged on #21359 as possibly this same single-slot projection, seen by remote clients — unverified here.
Mechanism
Plain opencode (without --standalone) runs one shared background service for every pane, so the status plugin runs inside that service and the ORCA_PANE_KEY stamped on each post is frozen to whichever pane started it. #21577 fixed this by rebinding the pane after the fact, keyed on session id.
The rebinding only happens when the binder has a binding, and correlateOpenCodeSessionOwners produces one only when exactly one pane qualifies as the session's creator. Qualification needs a pane whose directory contains the session and a live OpenCode client that brackets the session's creation — and clientCouldCreate deliberately accepts any client that started before and was seen alive after, so a TUI left open for days counts.
With two panes sharing a directory, both qualify, the tie is unresolvable, and the session stays unbound. Its posts then keep the frozen stamp forever. The existing test stays unbound when both same-directory panes evidence a client locks this behavior in.
This is the common case, not a corner:
- split panes in one worktree share
worktreeId, hence one directory; - folder projects back several workspaces with a single directory by design (
FOLDER_WORKSPACE_INSTANCE_SUFFIXis stripped before containment comparison).
Fix
Two signals, in order, each required to produce an unambiguous in-window leader:
- Launch recency — the pane whose OpenCode client booted within 20s of the session row appearing. This has to run first because Orca launches agents with
--prompt, so the pane that created the session never writes a keystroke of its own; on input alone that session would be handed to whichever sibling pane had recently been typed into. - Input recency — the last interactive write against each pane's PTY, taken at the point of dispatch and excluding terminal query replies, inside a 60-second window ending at creation and never after it.
Anything short of that stays unbound rather than guessed, because a wrong owner reproduces the reported bug rather than softening it.
Not covered by this issue / the fix
- Grey panes caused by the plugin never loading at all: that is [Bug]: stale opencode-hooks/shared status plugin copy is never regenerated, so OPENCODE_CONFIG_DIR keeps loading a pre-setup() template (Orca 1.4.210, Linux) #22764, with a fix in flight as fix(opencode): regenerate shared status plugin for OPENCODE_CONFIG_DIR #22768.
- "The icon stops spinning too early": not yet root-caused. The leading candidate is that the shared plugin aggregates to a single session per update —
publishAggregateStatusinstatus-plugin-ownership-source.tsposts onesessionID, so with two sessions busy across panes only one of them is ever spoken for.STALE_WORKING_TITLE_TIMEOUT_MSis the other candidate. - A launch that takes over 20s to mint its session falls outside the launch-recency window and is then decided on input, where a sibling pane typed into during that minute could still win. Narrowed from "every flag launch" to "very slow boots".
- Only well-formed terminal query replies are filtered out of the input signal. Full user-input provenance stops in the renderer —
wasUserInputis consumed by the replay guard and never reaches the transport — so an automatic write that is not a recognisable reply can still stamp a pane.
Activity
AmethystLiang commentedon Sep 25, 2026
thanks for reporting. looking into it.
werlang commentedon Sep 26, 2026
Thanks — a fix is already in flight as #22847, which this issue is the
Fixestarget for.Two things that may save you time investigating:
opencode(unlikeopencode2) runs OpenCode's shared background service, so every status post carries the starter pane's frozenORCA_PANE_KEY. fix(opencode): attribute shared-server sessions to their panes #21577 added the session→pane rebinding that corrects that, but it only binds when exactly one pane in the session's directory qualifies — and split panes in one worktree, or sibling folder workspaces, share a directory, so both qualify and the session stayed unbound. fix(opencode): bind same-directory sessions to the pane that submitted the prompt #22847 adds the evidence that breaks that specific tie.OPENCODE_CONFIG_DIRthat OpenCode refuses to load, with a fix claimed in fix(opencode): regenerate shared status plugin for OPENCODE_CONFIG_DIR #22768. The symptom looks identical, so it is worth separating before diagnosing.opencodeshared vsopencode2 --standalone) is tracked separately in [Tech debt]: opencode and opencode2 run the same OpenCode build in two different server topologies, split only for pane identity #22855.fix(opencode): keep shared-session TUI activity with its owning pane (#…
fix(sidebar): remember whether the left sidebar is open across restar…