Skip to content

feat(terminal): per-connection grouped sessions for externally-discovered sessions#168

Draft
0x79H wants to merge 3 commits into
gbasin:masterfrom
0x79H:feat/external-session-grouped-focus
Draft

feat(terminal): per-connection grouped sessions for externally-discovered sessions#168
0x79H wants to merge 3 commits into
gbasin:masterfrom
0x79H:feat/external-session-grouped-focus

Conversation

@0x79H

@0x79H 0x79H commented Jul 22, 2026

Copy link
Copy Markdown

Reference implementation for #163 — opened as a draft on purpose: if you prefer a different approach, close this freely and keep the pitfall list in the issue; it applies to any solution in this space.

Stacked on #165 and #166 — until those land, only the last commit here is new material (the client-evacuation logic relies on #165's reliable identity readout). Once they merge I'll rebase and this diff shrinks to the grouped-session change alone. Suggested review/merge order: #165#166 → this one; #167 is independent.

What

On first switch into an externally-discovered session S, create agentboard-ws-<conn>-x-<S> grouped with S (new-session -d -t =S) and switch the client into that. Windows stay shared; focus and per-window sizing become independent of the user's own attached clients, and copy-mode entered from the user's terminal no longer swallows browser keystrokes.

Robustness

Each of these guards a failure hit during adversarial testing on tmux 3.4:

  • Staleness is validated by window-set membership (list-windows -F '#{window_id}' contains the requested @id), not #{session_group} equality — group names are keyed by name and lie once ghost members survive a kill/recreate of S. Window ids are server-global and never reused, so membership is a sound invariant.
  • Every -t uses = exact matching, and new-session is preceded by a has-session guard (new-session -t =missing silently creates an unrelated group literally named =missing instead of failing).
  • Before discarding a stale derived session, our own client is evacuated to the ws session — with the default detach-on-destroy, killing the session under the client would take the whole proxy down.
  • Derived sessions are destroyed on every switch-away and on dispose; the startup prune covers crash leftovers. A recreation that lands in a ghost group degrades to attaching S directly (shared focus, but functional) rather than erroring or looping.
  • A disposed flag blocks a lost-race in-flight attach from resurrecting the proxy after dispose and leaking sessions.

Known trade-offs (accepted for our deployment, maintainer call for upstream)

  • While the viewed session's derived session exists, kill-session on S does not kill its windows until the viewer switches away.
  • tmux ls shows the per-connection derived sessions.
  • Brief session churn per attach while a ghost group persists.

Verification

0x79H added 3 commits July 22, 2026 10:18
…isplay-message -c

- display-message -p -c expands formats against the most recently
  active client's session, not the -c client (verified on tmux 3.4
  and 3.5a), causing false ERR_TMUX_SWITCH_FAILED whenever another
  tmux client on the server was more recently active
- resolve the identity from list-clients -F filtered by client_tty,
  the same approach discoverClientTty already uses
- teach the spawn harness to answer list-clients per requested
  format like real tmux (its display-message -c mock implemented
  the semantics the code assumed, which is how this survived the
  unit tests), and add a regression test where a foreign client is
  the most recently active one
- paste() targeted the grouped ws session unconditionally; after
  switching into an externally-discovered session the buffer landed
  in the ws session's bootstrap window and the paste was lost
- track lastEffectiveSession from the verified switch identity and
  paste into that session's active pane, falling back to the ws
  session before the first switch
…ered sessions

- joining an external session directly shares its current-window
  pointer and window size with the user's own attached clients:
  switching in the browser flips the user's terminal and vice versa,
  and copy-mode entered locally swallows browser keystrokes
- create agentboard-ws-<conn>-x-<session> grouped with the raw
  session on first switch and keep focus independent
- validate staleness by window-set membership, not session_group
  equality (group names lie once ghost members survive a raw-session
  kill/recreate); use = exact matching plus has-session guards for
  every tmux -t; evacuate our own client before killing a stale
  derived session (detach-on-destroy would kill the proxy)
- destroy derived sessions on switch-away and dispose; degrade to
  attaching the raw session directly when recreation lands in a
  ghost group; block resurrection after dispose via a disposed flag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant