Skip to content

Use grouped tmux sessions for independent window navigation#21

Merged
flipbit03 merged 13 commits intomainfrom
feat/20-use-grouped-tmux-sessions-for-independen
Mar 29, 2026
Merged

Use grouped tmux sessions for independent window navigation#21
flipbit03 merged 13 commits intomainfrom
feat/20-use-grouped-tmux-sessions-for-independen

Conversation

@flipbit03
Copy link
Copy Markdown
Owner

@flipbit03 flipbit03 commented Mar 20, 2026

Summary

  • Replace tmux attach-session with grouped sessions (tmux new-session -t) so each terminal can independently navigate tmux windows
  • Each subsequent terminal creates a PID-named grouped session linked to the original, avoiding shared active-window cursors
  • Use a client-attached hook to defer setting destroy-unattached, since setting it on a detached session destroys it immediately
  • Grouped sessions auto-cleanup on disconnect; the original session persists as the anchor

Closes #20

Test plan

  • Open forestui in terminal A — creates the original tmux session
  • Open forestui in terminal B — creates a grouped session (verify with tmux list-sessions)
  • Switch tmux windows in terminal B — terminal A stays on its current window
  • Open terminal C — also gets its own independent grouped session
  • Close terminal B — grouped session is destroyed, original and C persist
  • Detach from terminal A — original session persists, can reattach

Replace `tmux attach-session` with `tmux new-session -t` when
reattaching to an existing session. This creates a grouped session
that shares windows but allows each terminal to independently select
the active window. The `destroy-unattached` option ensures grouped
sessions are cleaned up when the terminal disconnects.
The semicolon command separator in os.execvp doesn't work reliably with
tmux. Instead, create the grouped session detached with a PID-based
unique name, set destroy-unattached on it, then attach.
Setting destroy-unattached on a detached session causes tmux to destroy
it immediately. Use a client-attached hook instead so the option is set
only after the client connects, avoiding the race condition.
Use tmux display-message to get the session ID of the process's own
session instead of picking the first attached one. In grouped session
setups, multiple sessions are attached simultaneously, and the old
approach would always find the original session, causing window
operations (open editor, terminal, claude) to switch the active window
in the wrong terminal.
The forestui process runs in the original session's pane, so
display-message always returned the original session ID regardless of
which grouped session the user is viewing from. Instead, use
list-clients sorted by client_activity to find the most recently active
client's session — that's the terminal the user just interacted with.

Remove session caching since the active client can change between
grouped sessions at any time.
Override status-left on grouped sessions to show the base session name
(e.g. forestui-forest) instead of the internal PID-suffixed name
(e.g. forestui-forest-23116). The grouped session is an implementation
detail that should be transparent to the user.
1. Fix shell injection via unquoted forest_path (shlex.quote)
2. Replace select-window existence check with read-only list-windows
   to avoid switching the active window in the original session
3. Scope list-clients to our session_group so unrelated tmux sessions
   don't cause forestui to resolve to the wrong session
4. Use destroy-unattached keep-last instead of on, preventing the
   last session in the group from being destroyed
5. Use show-options -gv for status-left to get just the value without
   option name prefix or quoting
6. Add error handling for grouped session creation with fallback to
   direct attach
The existence check used exact match on "forestui", missing dev mode
windows named "forestui-dev-HHMM". This caused a second terminal to
spawn a duplicate forestui process instead of just attaching.
strip() was removing a trailing space that's part of the tmux
status-left template, causing the separator between the session name
and the first window tab to disappear. Use rstrip('\n') to only
remove the subprocess newline.
Provides a skill that lets Claude launch forestui in headless virtual
terminals via tu, visually verify UI behavior, and interact with the
running app. Supports multi-terminal testing with isolated tmux servers
for verifying grouped session behavior.
The user is likely running their own tmux/forestui session. Without
TMUX_TMPDIR isolation the agent would interfere with their live session.
tmux's -t flag does prefix matching by default, so
has-session -t forestui-forest would match orphaned grouped sessions
like forestui-forest-12345. The = prefix forces exact match on all
session targets: has-session, list-windows, new-window, new-session.
Plain text screenshots lose colors and highlighting, making it
impossible to tell which tmux window is active. PNG mode captures
the full terminal with color for accurate visual verification.
@flipbit03 flipbit03 merged commit e6c908d into main Mar 29, 2026
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.

Use grouped tmux sessions for independent window navigation across terminals

1 participant