You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I often run multiple OpenCode sessions as separate panes inside the same tmux window. The current OpenCode/tmux integration is window-oriented, so the window can only expose one name/state even when its panes contain different sessions.
Each label must follow the exact OpenCode session displayed in that pane, and pane labels must be toggleable without destroying their stored titles.
Source check before implementation
Verified against the latest relevant source/config before creating this issue:
Dotfiles default branch is currently master at commit 8175ac0480a98e28151541557646a677b13b7694 (chore(tmux): document status options).
.tmux.conf:
uses prefix C-a
uses base-index 1 and pane-base-index 1
loads janoamaral/tokyo-night-tmux through TPM
does not currently configure pane-border-format
currently sets the outer terminal title from window_name and session_name, not from pane-local OpenCode state
The current Tokyo Night tmux plugin explicitly runs:
tmux set -g pane-border-status off
Therefore this feature must be applied after the theme/TPM initialization, or otherwise integrated in a way that survives the theme loading order.
.config/opencode/opencode.json currently loads @koriit/opencode-tmux-window-status. Before implementing, inspect the exact installed package version/source and determine whether it can be extended or configured for pane-local title data. Do not blindly add a second competing window-renaming plugin.
.config/opencode/tui.json currently contains keybindings only and does not register a TUI plugin.
The current OpenCode TUI plugin specification supports:
Issue Make OpenCode tmux panes restore their exact sessions #8 already defines a pane-aware mechanism for tracking the exact active OpenCode session, including in-TUI session switches. If that implementation lands first, reuse its active-session observation rather than building a second independent source of truth.
Current tmux supports pane border status lines and pane-border-format. tmux 3.6 changed pane-border-format from a window option to a pane option, so implementation and tests must verify the actual installed tmux version and avoid stale scope assumptions.
Every OpenCode pane displays a compact label based on the exact current session title.
Two OpenCode panes in the same tmux window can display two different titles simultaneously.
The label remains attached to the pane where that OpenCode process started, regardless of which pane is currently focused.
Switching sessions inside OpenCode through /sessions or the session picker updates that pane's label immediately, before another prompt has to be sent.
A resumed session displays its existing title promptly.
A new session updates when OpenCode generates or changes its title.
Toggle
Add one ergonomic tmux keybinding to toggle pane-border labels for the current window.
C-a T is a reasonable candidate, but the implementation must check the effective tmux key table after plugins load before choosing it.
First press hides pane labels.
Second press restores them.
Toggling visibility must not delete the pane-local OpenCode title values.
Reloading .tmux.conf must remain idempotent.
Fallback and cleanup
Non-OpenCode panes should show either a small command/path fallback or a deliberately blank/minimal label.
When OpenCode exits normally and the pane returns to a shell, its old OpenCode title must not remain visible as stale state.
Child/subagent sessions must not replace the main pane title.
Long titles must be truncated by tmux formatting rather than creating oversized borders.
Newlines, terminal control sequences, quotes, semicolons, and shell syntax in a session title must be sanitized and passed safely.
Preferred implementation shape
Use pane-local tmux user options rather than renaming the shared window:
If the existing @koriit/opencode-tmux-window-status plugin is replaced or narrowed, preserve useful status behavior deliberately and remove duplicate/conflicting integration.
Test-first requirement
The implementation PR must add the failing tests before the implementation and include evidence that:
the tests fail against the current base commit for the expected reason
the same tests pass after implementation
Tests must use an isolated tmux socket/server, for example tmux -L opencode-pane-title-test-$$, and must never modify or terminate the developer's normal tmux server.
The feature should expose a sourceable tmux fragment or a shared helper if needed so the test exercises the same implementation used by the real keybinding. Do not copy the production toggle logic into the test and then test the duplicate.
Correct real-life tests before implementation
Test 1: two panes retain two independent titles
Setup:
Start an isolated tmux server with one window and two panes.
Capture the two real pane IDs using split-window -P -F '#{pane_id}' / list-panes.
Invoke the production title-writer path with:
left pane -> Fix authentication redirect
right pane -> Repair Mollie webhook reconciliation
Read the pane-local values using show-options -p -v -t <pane-id> @opencode_session_title.
Expected:
left pane option = Fix authentication redirect
right pane option = Repair Mollie webhook reconciliation
Also assert the tmux window name was not changed by the title writer.
Why this is the correct test:
It uses a real tmux server and real pane IDs, not a mocked tmux command.
A window-scoped implementation cannot satisfy both assertions simultaneously.
An implementation that accidentally targets the active pane causes one pane to be overwritten and fails.
The current repo does not have a pane-local title writer, so this test must be red before implementation.
This is the core automated test. If it does not fail for a window-level implementation, the test is incorrect.
Test 2: the effective rendered border uses the target pane's value
Setup:
Use the two-pane server from Test 1.
Load the production pane-border configuration in the same order as the real .tmux.conf.
Confirm the final effective pane-border-status is top or bottom, not off.
Render/evaluate pane-border-format separately for each target pane, using tmux format expansion such as #{E:pane-border-format}.
Expected:
render(left) contains "Fix authentication redirect"
render(left) does not contain "Repair Mollie webhook reconciliation"
render(right) contains "Repair Mollie webhook reconciliation"
render(right) does not contain "Fix authentication redirect"
Why this is the correct test:
Setting a custom pane option is not sufficient. This proves tmux actually resolves the border format in the context of each pane. It also catches a format that accidentally reads the active pane or a shared window option.
The current setup must fail because Tokyo Night leaves pane-border-status off and the dotfiles do not provide an overriding pane title format.
Test 3: full-config/theme ordering does not disable the feature
Setup:
Start a fresh isolated tmux server using the real dotfiles configuration with required plugin paths available, or run this as a local integration test against the installed TPM setup.
Reload .tmux.conf twice.
Query the final effective values after Tokyo Night has loaded.
Expected:
pane-border-status remains enabled.
pane-border-format still references the pane-local OpenCode title.
Reloading twice does not duplicate bindings, format fragments, or shell processes.
Why this is the correct test:
The active Tokyo Night plugin explicitly disables pane-border status. A minimal test that loads only the new lines can pass while the real setup still hides every title. This test prevents that false green.
Test 4: toggle hides and restores labels without losing data
Setup:
Begin with both labels visible and both pane-local title options populated.
Invoke the exact production toggle command used by the keybinding.
Assert pane-border-status becomes off.
Assert both @opencode_session_title values are unchanged.
Invoke the toggle again.
Assert the original configured position (top or bottom) is restored and each pane renders its original title.
Why this is the correct test:
A test that only checks that a key is bound does not prove the toggle works. A test that manually runs different logic from the keybinding can also give a false green. The behavioral test must call the same command path as the real binding.
The current repo has no pane-label toggle, so this test must fail before implementation.
Test 5: switching sessions inside OpenCode updates only that pane
This is a live OpenCode + tmux acceptance test.
Setup:
Create one tmux window with two panes in the same repository.
Left pane opens OpenCode session A with title Fix port 3000 process leak.
Right pane opens OpenCode session B with title Review payment webhook retries.
Verify both labels are visible simultaneously.
In the left OpenCode TUI, use /sessions or the session picker to switch to session C.
Do not send another prompt after switching.
Expected:
left label -> session C title
right label -> remains "Review payment webhook retries"
Why this is the correct test:
A startup-only implementation, or one that waits for the next chat message, can pass simple launch tests but fails the actual session-switch workflow. OpenCode's current TUI route exposes the displayed session ID directly, so immediate route-driven synchronization is the expected behavior.
The current window-level setup cannot display A/B simultaneously and must fail this test.
Test 6: title lifecycle and stale-title cleanup
Setup:
Start a brand-new OpenCode session.
Observe the initial fallback while the title is still generic.
Send a first prompt and wait for OpenCode to update the session title.
Confirm the pane label changes to the new title.
Exit OpenCode normally back to the shell in the same pane.
Expected:
The generated session title appears without restarting tmux.
On normal OpenCode exit, the pane no longer displays the stale OpenCode title.
The pane shows the selected non-OpenCode fallback or no title.
Why this is the correct test:
It verifies the full lifecycle rather than only a pre-existing titled session. It catches plugins that set a title once and never update or clear it.
Test 7: hostile and long titles are safe
Use a title similar to:
Fix $(touch /tmp/opencode-pane-title-pwned); "quoted" auth redirect with a very long explanation
Also test a title containing a newline/control character through the lowest-level title-writer test API.
Expected:
/tmp/opencode-pane-title-pwned is not created.
The tmux option contains sanitized text, not executed shell syntax.
The rendered border is truncated to the configured maximum width.
No raw terminal control sequence is emitted into the pane border.
Why this is the correct test:
Session titles are data. This catches unsafe shell interpolation and format/control-character injection while exercising the real tmux writer.
Test 8: chosen keybinding is actually available after plugins load
Setup:
Load the full tmux configuration and TPM plugins.
Inspect the effective prefix key table with tmux list-keys -T prefix.
Verify the chosen binding invokes the production toggle command.
Verify existing important bindings still work, including pane splits, pane navigation, sync toggle n, and config reload r.
Expected:
There is exactly one binding for the chosen key.
It toggles the feature.
No existing binding is silently replaced without documentation.
Acceptance criteria
Each OpenCode pane stores its title in a pane-local tmux option.
Two OpenCode panes in one window display different session titles simultaneously.
The title writer always targets the originating $TMUX_PANE, not the active pane.
Switching through /sessions updates the label immediately without requiring another prompt.
Resumed and newly titled sessions update correctly.
Child/subagent sessions do not overwrite the main pane label.
Pane labels remain visible after the Tokyo Night plugin loads.
One documented keybinding toggles labels off and back on.
Toggling does not erase pane-local title state.
Normal OpenCode exit clears the stale title or switches to the documented fallback.
Long/hostile titles are sanitized, safely passed, and visually truncated.
Existing tmux bindings and window status behavior remain functional.
Tests demonstrate red on the current base and green after implementation.
Configuration remains idempotent when sourced repeatedly.
Deliverables
pane-aware OpenCode title synchronization
tmux pane-border rendering and toggle binding
automated isolated-tmux integration tests
documented live OpenCode acceptance-test results
concise comments/documentation covering:
chosen keybinding
title source and update lifecycle
interaction with Tokyo Night tmux
interaction with @koriit/opencode-tmux-window-status
Problem
I often run multiple OpenCode sessions as separate panes inside the same tmux window. The current OpenCode/tmux integration is window-oriented, so the window can only expose one name/state even when its panes contain different sessions.
Example:
The desired result is a small pane-border label on each pane:
Each label must follow the exact OpenCode session displayed in that pane, and pane labels must be toggleable without destroying their stored titles.
Source check before implementation
Verified against the latest relevant source/config before creating this issue:
Dotfiles default branch is currently
masterat commit8175ac0480a98e28151541557646a677b13b7694(chore(tmux): document status options)..tmux.conf:C-abase-index 1andpane-base-index 1janoamaral/tokyo-night-tmuxthrough TPMpane-border-formatwindow_nameandsession_name, not from pane-local OpenCode stateThe current Tokyo Night tmux plugin explicitly runs:
tmux set -g pane-border-status offTherefore this feature must be applied after the theme/TPM initialization, or otherwise integrated in a way that survives the theme loading order.
.config/opencode/opencode.jsoncurrently loads@koriit/opencode-tmux-window-status. Before implementing, inspect the exact installed package version/source and determine whether it can be extended or configured for pane-local title data. Do not blindly add a second competing window-renaming plugin..config/opencode/tui.jsoncurrently contains keybindings only and does not register a TUI plugin.The current OpenCode TUI plugin specification supports:
tui.jsonapi.route.current{ name: "session", params: { sessionID } }api.clientapi.event.on(...)Issue Make OpenCode tmux panes restore their exact sessions #8 already defines a pane-aware mechanism for tracking the exact active OpenCode session, including in-TUI session switches. If that implementation lands first, reuse its active-session observation rather than building a second independent source of truth.
Current tmux supports pane border status lines and
pane-border-format. tmux 3.6 changedpane-border-formatfrom a window option to a pane option, so implementation and tests must verify the actual installed tmux version and avoid stale scope assumptions.Relevant source links:
Desired UX
Pane-local title
/sessionsor the session picker updates that pane's label immediately, before another prompt has to be sent.Toggle
C-a Tis a reasonable candidate, but the implementation must check the effective tmux key table after plugins load before choosing it..tmux.confmust remain idempotent.Fallback and cleanup
Preferred implementation shape
Use pane-local tmux user options rather than renaming the shared window:
Likely components:
.config/opencode/tui.json@opencode_session_title.tmux.conf, placed after TPM/theme loadingImplementation constraints:
$TMUX_PANE; never write to whichever pane happens to be active when an asynchronous event arrives.@koriit/opencode-tmux-window-statusplugin is replaced or narrowed, preserve useful status behavior deliberately and remove duplicate/conflicting integration.Test-first requirement
The implementation PR must add the failing tests before the implementation and include evidence that:
Tests must use an isolated tmux socket/server, for example
tmux -L opencode-pane-title-test-$$, and must never modify or terminate the developer's normal tmux server.The feature should expose a sourceable tmux fragment or a shared helper if needed so the test exercises the same implementation used by the real keybinding. Do not copy the production toggle logic into the test and then test the duplicate.
Correct real-life tests before implementation
Test 1: two panes retain two independent titles
Setup:
Start an isolated tmux server with one window and two panes.
Capture the two real pane IDs using
split-window -P -F '#{pane_id}'/list-panes.Invoke the production title-writer path with:
Read the pane-local values using
show-options -p -v -t <pane-id> @opencode_session_title.Expected:
Also assert the tmux window name was not changed by the title writer.
Why this is the correct test:
This is the core automated test. If it does not fail for a window-level implementation, the test is incorrect.
Test 2: the effective rendered border uses the target pane's value
Setup:
.tmux.conf.pane-border-statusistoporbottom, notoff.pane-border-formatseparately for each target pane, using tmux format expansion such as#{E:pane-border-format}.Expected:
Why this is the correct test:
Setting a custom pane option is not sufficient. This proves tmux actually resolves the border format in the context of each pane. It also catches a format that accidentally reads the active pane or a shared window option.
The current setup must fail because Tokyo Night leaves
pane-border-statusoff and the dotfiles do not provide an overriding pane title format.Test 3: full-config/theme ordering does not disable the feature
Setup:
.tmux.conftwice.Expected:
pane-border-statusremains enabled.pane-border-formatstill references the pane-local OpenCode title.Why this is the correct test:
The active Tokyo Night plugin explicitly disables pane-border status. A minimal test that loads only the new lines can pass while the real setup still hides every title. This test prevents that false green.
Test 4: toggle hides and restores labels without losing data
Setup:
pane-border-statusbecomesoff.@opencode_session_titlevalues are unchanged.toporbottom) is restored and each pane renders its original title.Why this is the correct test:
A test that only checks that a key is bound does not prove the toggle works. A test that manually runs different logic from the keybinding can also give a false green. The behavioral test must call the same command path as the real binding.
The current repo has no pane-label toggle, so this test must fail before implementation.
Test 5: switching sessions inside OpenCode updates only that pane
This is a live OpenCode + tmux acceptance test.
Setup:
Fix port 3000 process leak.Review payment webhook retries./sessionsor the session picker to switch to session C.Expected:
Why this is the correct test:
A startup-only implementation, or one that waits for the next chat message, can pass simple launch tests but fails the actual session-switch workflow. OpenCode's current TUI route exposes the displayed session ID directly, so immediate route-driven synchronization is the expected behavior.
The current window-level setup cannot display A/B simultaneously and must fail this test.
Test 6: title lifecycle and stale-title cleanup
Setup:
Expected:
Why this is the correct test:
It verifies the full lifecycle rather than only a pre-existing titled session. It catches plugins that set a title once and never update or clear it.
Test 7: hostile and long titles are safe
Use a title similar to:
Also test a title containing a newline/control character through the lowest-level title-writer test API.
Expected:
/tmp/opencode-pane-title-pwnedis not created.Why this is the correct test:
Session titles are data. This catches unsafe shell interpolation and format/control-character injection while exercising the real tmux writer.
Test 8: chosen keybinding is actually available after plugins load
Setup:
tmux list-keys -T prefix.n, and config reloadr.Expected:
Acceptance criteria
$TMUX_PANE, not the active pane./sessionsupdates the label immediately without requiring another prompt.Deliverables
@koriit/opencode-tmux-window-statusNon-goals