Auto-disable copy-on-select inside terminal multiplexers (Zellij, tmux) #8702

Closed
opened 2026-02-16 18:10:37 -05:00 by yindo · 4 comments
Owner

Originally created by @schickling on GitHub (Feb 6, 2026).

Originally assigned to: @rekram1-node on GitHub.

Problem

When running OpenCode inside a terminal multiplexer like Zellij or tmux, both OpenCode and the multiplexer independently handle clipboard via OSC 52 on mouse selection, causing unreliable clipboard behavior. The two layers race on clipboard writes — sometimes the clipboard ends up empty, has stale content, or the wrong tool "wins."

Each tool works fine in isolation:

  • Standalone OpenCode: copy-on-select via OSC 52 works great
  • Standalone Zellij/tmux: copy_on_select + OSC 52 works great
  • Nested (OpenCode inside Zellij/tmux): unreliable — both layers fire independently

This is a common setup, especially over SSH where OSC 52 is the only clipboard method available and Zellij is used to manage sessions.

Current Workaround

Setting OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT=true conditionally when inside a multiplexer:

# fish shell config
if set -q ZELLIJ
  set -gx OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT true
end

This works but has downsides:

  • The experimental flag reportedly also affects selection visibility (#10490)
  • Users have to discover and wire this up themselves
  • It doesn't generalize to tmux ($TMUX) without additional config

Proposed Solution

OpenCode should automatically detect multiplexer environments and adjust clipboard behavior accordingly. The multiplexer is the better owner of clipboard in a nested scenario because:

  1. It already handles OSC 52 forwarding to the outer terminal
  2. It has pane-aware selection (respects pane boundaries)
  3. It's the outermost layer the user interacts with

Concretely:

  1. Auto-detect: Check for $ZELLIJ, $TMUX, $STY (screen) environment variables
  2. When inside a multiplexer: Disable copy-on-select by default, letting the multiplexer own clipboard. OpenCode should still use OSC 52 for programmatic copies (e.g., /share URL).
  3. Make it configurable: A tui.copy_on_select config option (as proposed in #10490) with three modes:
    • true — always on (current behavior)
    • false — always off
    • "auto" (default) — on when standalone, off when inside a multiplexer

Related Issues

  • #10490 — Feature request for tui.copy_on_select config option
  • #2845 — Request to disable text selection and clipboard overrides
  • #10128 — Clipboard fails in WSL + tmux (same root cause)
  • #5046 — Copy failures in deeply nested terminal sessions
  • #8237 — Clipboard in devcontainers (related OSC 52 handling)

Environment

  • OpenCode inside Zellij (both macOS and Linux over SSH)
  • Terminals: Ghostty, various Linux terminals
  • Both tools use OSC 52 for clipboard
Originally created by @schickling on GitHub (Feb 6, 2026). Originally assigned to: @rekram1-node on GitHub. ## Problem When running OpenCode inside a terminal multiplexer like Zellij or tmux, **both OpenCode and the multiplexer independently handle clipboard via OSC 52 on mouse selection**, causing unreliable clipboard behavior. The two layers race on clipboard writes — sometimes the clipboard ends up empty, has stale content, or the wrong tool "wins." Each tool works fine in isolation: - **Standalone OpenCode**: copy-on-select via OSC 52 works great - **Standalone Zellij/tmux**: `copy_on_select` + OSC 52 works great - **Nested (OpenCode inside Zellij/tmux)**: unreliable — both layers fire independently This is a common setup, especially over SSH where OSC 52 is the only clipboard method available and Zellij is used to manage sessions. ## Current Workaround Setting `OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT=true` conditionally when inside a multiplexer: ```fish # fish shell config if set -q ZELLIJ set -gx OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT true end ``` This works but has downsides: - The experimental flag reportedly also affects selection visibility (#10490) - Users have to discover and wire this up themselves - It doesn't generalize to tmux (`$TMUX`) without additional config ## Proposed Solution OpenCode should **automatically detect multiplexer environments** and adjust clipboard behavior accordingly. The multiplexer is the better owner of clipboard in a nested scenario because: 1. It already handles OSC 52 forwarding to the outer terminal 2. It has pane-aware selection (respects pane boundaries) 3. It's the outermost layer the user interacts with Concretely: 1. **Auto-detect**: Check for `$ZELLIJ`, `$TMUX`, `$STY` (screen) environment variables 2. **When inside a multiplexer**: Disable copy-on-select by default, letting the multiplexer own clipboard. OpenCode should still use OSC 52 for programmatic copies (e.g., `/share` URL). 3. **Make it configurable**: A `tui.copy_on_select` config option (as proposed in #10490) with three modes: - `true` — always on (current behavior) - `false` — always off - `"auto"` (default) — on when standalone, off when inside a multiplexer ## Related Issues - #10490 — Feature request for `tui.copy_on_select` config option - #2845 — Request to disable text selection and clipboard overrides - #10128 — Clipboard fails in WSL + tmux (same root cause) - #5046 — Copy failures in deeply nested terminal sessions - #8237 — Clipboard in devcontainers (related OSC 52 handling) ## Environment - OpenCode inside Zellij (both macOS and Linux over SSH) - Terminals: Ghostty, various Linux terminals - Both tools use OSC 52 for clipboard
yindo added the opentui label 2026-02-16 18:10:37 -05:00
yindo closed this issue 2026-02-16 18:10:37 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Feb 6, 2026):

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

  • #12082: Clipboard copy fails in Zellij and other multiplexers (OSC52 written to stdout instead of /dev/tty) - addresses the same root cause of clipboard failures in multiplexers
  • #10490: Add config option to disable copy-on-select behavior - your proposed solution explicitly references this feature request
  • #10128: WSL + tmux opencode cannot copy text - same environment and copy-on-select problem
  • #2845: How to disable text selection and clipboard overrides? - related request to disable copy-on-select

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

@github-actions[bot] commented on GitHub (Feb 6, 2026): This issue might be a duplicate of existing issues. Please check: - #12082: Clipboard copy fails in Zellij and other multiplexers (OSC52 written to stdout instead of /dev/tty) - addresses the same root cause of clipboard failures in multiplexers - #10490: Add config option to disable copy-on-select behavior - your proposed solution explicitly references this feature request - #10128: WSL + tmux opencode cannot copy text - same environment and copy-on-select problem - #2845: How to disable text selection and clipboard overrides? - related request to disable copy-on-select Feel free to ignore if none of these address your specific case.
Author
Owner

@schickling commented on GitHub (Feb 6, 2026):

Thanks for the cross-references. Here's how these relate:

#12082 is closely related but distinct. It identifies that OpenCode writes OSC 52 to process.stdout, which multiplexers intercept without forwarding to the outer terminal. The proposed fix (write to /dev/tty instead) would fix programmatic clipboard operations inside multiplexers.

However, this issue (#12455) would remain even after #12082 is fixed: when both OpenCode and the multiplexer have copy-on-select enabled, both layers fire independent clipboard writes on mouse release — one via OpenCode's OSC 52 and one via the multiplexer's own clipboard handling. The /dev/tty fix would make both writes actually succeed, but the race between them would still cause unreliable behavior (wrong content in clipboard depending on timing).

The proposal here is specifically about OpenCode auto-detecting multiplexer environments and deferring copy-on-select to the multiplexer, which is orthogonal to how the OSC 52 sequence is delivered.

#10490 is referenced in the proposal — a stable tui.copy_on_select config option is a prerequisite, and this issue proposes extending it with an "auto" mode that detects $ZELLIJ/$TMUX/$STY.

#10128 and #2845 are symptoms of the same underlying problem and are already referenced in the issue body.

@schickling commented on GitHub (Feb 6, 2026): Thanks for the cross-references. Here's how these relate: **#12082 is closely related but distinct.** It identifies that OpenCode writes OSC 52 to `process.stdout`, which multiplexers intercept without forwarding to the outer terminal. The proposed fix (write to `/dev/tty` instead) would fix *programmatic* clipboard operations inside multiplexers. However, **this issue (#12455) would remain even after #12082 is fixed**: when both OpenCode and the multiplexer have copy-on-select enabled, both layers fire independent clipboard writes on mouse release — one via OpenCode's OSC 52 and one via the multiplexer's own clipboard handling. The `/dev/tty` fix would make both writes actually succeed, but the race between them would still cause unreliable behavior (wrong content in clipboard depending on timing). The proposal here is specifically about **OpenCode auto-detecting multiplexer environments and deferring copy-on-select to the multiplexer**, which is orthogonal to how the OSC 52 sequence is delivered. **#10490** is referenced in the proposal — a stable `tui.copy_on_select` config option is a prerequisite, and this issue proposes extending it with an `"auto"` mode that detects `$ZELLIJ`/`$TMUX`/`$STY`. **#10128 and #2845** are symptoms of the same underlying problem and are already referenced in the issue body.
Author
Owner

@schickling commented on GitHub (Feb 6, 2026):

After further analysis, I believe #12082 would categorically fix this problem, making this issue unnecessary.

The key insight: when OpenCode has mouse capture enabled (via Bubbletea), Zellij forwards mouse events to OpenCode and does NOT do its own text selection. When OpenCode does not have mouse capture, Zellij handles mouse events and OpenCode never sees them. Only one layer handles mouse events at a time — there is no actual race.

The real problem was always that OpenCode's OSC 52 (written to stdout) gets intercepted by the multiplexer and never reaches the terminal. The clipboard write silently fails, making it appear like both tools are fighting. Once #12082 lands (OSC 52 via /dev/tty), both layers should coexist without conflict.

I'll keep this issue open as a reference but it can likely be closed once #12082 ships.

@schickling commented on GitHub (Feb 6, 2026): After further analysis, I believe **#12082 would categorically fix this problem**, making this issue unnecessary. The key insight: when OpenCode has mouse capture enabled (via Bubbletea), Zellij forwards mouse events to OpenCode and does NOT do its own text selection. When OpenCode does not have mouse capture, Zellij handles mouse events and OpenCode never sees them. **Only one layer handles mouse events at a time** — there is no actual race. The real problem was always that OpenCode's OSC 52 (written to stdout) gets intercepted by the multiplexer and never reaches the terminal. The clipboard write silently fails, making it *appear* like both tools are fighting. Once #12082 lands (OSC 52 via `/dev/tty`), both layers should coexist without conflict. I'll keep this issue open as a reference but it can likely be closed once #12082 ships.
Author
Owner

@arabcoders commented on GitHub (Feb 13, 2026):

After further analysis, I believe #12082 would categorically fix this problem, making this issue unnecessary.

The key insight: when OpenCode has mouse capture enabled (via Bubbletea), Zellij forwards mouse events to OpenCode and does NOT do its own text selection. When OpenCode does not have mouse capture, Zellij handles mouse events and OpenCode never sees them. Only one layer handles mouse events at a time — there is no actual race.

The real problem was always that OpenCode's OSC 52 (written to stdout) gets intercepted by the multiplexer and never reaches the terminal. The clipboard write silently fails, making it appear like both tools are fighting. Once #12082 lands (OSC 52 via /dev/tty), both layers should coexist without conflict.

I'll keep this issue open as a reference but it can likely be closed once #12082 ships.

@schickling Can you confirm this is fixed if you connect to ssh and tmux session running opencode?

Currently it doesnt work at least in 1.1.65.

Tested with ssh+tmux+nvim (copy works) - ssh+tmux+opencode(copy doesnt work)

@arabcoders commented on GitHub (Feb 13, 2026): > After further analysis, I believe **[#12082](https://github.com/anomalyco/opencode/issues/12082) would categorically fix this problem**, making this issue unnecessary. > > The key insight: when OpenCode has mouse capture enabled (via Bubbletea), Zellij forwards mouse events to OpenCode and does NOT do its own text selection. When OpenCode does not have mouse capture, Zellij handles mouse events and OpenCode never sees them. **Only one layer handles mouse events at a time** — there is no actual race. > > The real problem was always that OpenCode's OSC 52 (written to stdout) gets intercepted by the multiplexer and never reaches the terminal. The clipboard write silently fails, making it _appear_ like both tools are fighting. Once [#12082](https://github.com/anomalyco/opencode/issues/12082) lands (OSC 52 via `/dev/tty`), both layers should coexist without conflict. > > I'll keep this issue open as a reference but it can likely be closed once [#12082](https://github.com/anomalyco/opencode/issues/12082) ships. @schickling Can you confirm this is fixed if you connect to ssh and tmux session running opencode? Currently it doesnt work at least in `1.1.65`. Tested with ssh+tmux+nvim (copy works) - ssh+tmux+opencode(copy doesnt work)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8702