Skip to content

[FEATURE] Native tmux integration for true session persistence, collaboration, and scrollback #617

@DL6ER

Description

@DL6ER

Title

Native tmux integration for true session persistence, collaboration, and scrollback

Platform

Web-app

Is it related to an issue?

First off - I've been a happy Termix user for quite some time now, and the recent 2.0 release with remote desktop support is just awesome. The whole project has come an incredibly long way. Thank you for all the work you and the contributors are putting into this.

That said, there's one area where I keep running into limitations, and I think addressing it would make Termix significantly more robust - especially for users on the go or on unreliable connections. I explicitly offer to do the implementation work on this, but I wanted to open the discussion first to see if it's something the project would accept in the end and to get feedback on the approach. I'm going to write the code anyway (because I need it), but I'd greatly appreciate it being part of the official project rather than a personal fork. I'm very open to feedback, alternative approaches, and scope adjustments but also please keep in mind that this is something I commit myself to invest in, nothing I come and ask for someone else (like you) to do. You can research my GitHub profile to see that I have a long history of open source contributions, so this is not an empty promise. I have seen that this proposal got a lot longer than I initially expected, but I wanted to be as thorough as possible in laying out the problem, the real-world scenario, and the proposed solution. I hope it provides a clear picture of what I'm aiming for and why I think it's valuable.

The problem

Termix's current session persistence is a great feature - when I close a browser tab or lose WiFi for a few minutes, I can reconnect and pick up where I left off. But this persistence has hard boundaries, unfortunately, too hard for me (and I suspect many others):

  1. The Termix server is a single point of failure. Sessions live in-memory on the Node.js process. If the Termix server restarts (Docker update, OOM, crash), every active session is gone - and with it, any process running on the remote host. There is no way to recover.

  2. SSH connection drops kill the remote shell. If the network between Termix and the remote host hiccups - even briefly - the ssh2 stream closes and the session is destroyed. Any long-running build, deployment script, or interactive process on the remote host dies unrecoverably.

  3. The 30-minute detach timeout is a hard ceiling. If you're offline longer than the configured timeout (airplane, sleep, bad mobile coverage), the session is irreversibly destroyed and the remote process with it.

  4. No smooth cross-device handoff. Termix allows up to 3 concurrent WebSocket connections per user, so you can be connected from multiple devices at once. But each connection gets its own session. If you try to attach a second device to an existing session, the first device gets kicked off - it is a takeover, not a handoff. There is no way to smoothly continue a session on another device without the original connection being disrupted, and it still depends on the server being up and the SSH connection being alive.

  5. Scrollback is client-side only. The xterm.js buffer holds 10,000 lines, and the server-side replay buffer is capped at 512 KB. When reattaching a session, you only get that limited replay - you can't scroll back further into history from before the disconnection.

Mobile work and switching between devices throughout the day is not a niche anymore - it is how many work now. Managing servers from a phone on the commute (not ideal but sometimes necessary when having to debug, e.g., hardware failures instantly), from a tablet on the couch, from a laptop on hotel WiFi, expecting continuity across all of them - that is the standard, not the exception. These limitations are a real problem for me, and I suspect for many others too. You end up having to SSH in manually and run tmux attach anyway, which defeats much of the convenience Termix provides.

The real-world scenario

Here's what I want to be able to do - and what I think many Termix users would love, too:

I'm working on a remote server from my desktop at home. I have a long build running, logs tailing, an editor open. Then I need to leave. I pull out my phone, open Termix mobile, and I'm right back in the same session - same output, same running processes, full scrollback. Later I board a train from Cologne to Munich (> 4 hours), the connection drops and reconnects dozens of times through tunnels and dead zones. None of that should really matter - every time the connection comes back, I'm exactly where I left off. When I arrive and open my laptop, I pick up the session there. One continuous workflow across three devices, zero manual intervention, nothing lost. Full continuity, full persistence, full freedom to work from wherever I am without worrying about the how.

This is the promise of Termix's multi-platform story - desktop, mobile, web, PWA, all connected to the same self-hosted server. The missing piece is that the remote sessions don't follow you across those transitions. Today, the session is tied to a single Termix-to-host SSH connection. If that connection breaks for any reason, the session is gone. With tmux on the remote host as the persistence layer, the session lives independently of any particular connection to it. Termix becomes the seamless window into it from whatever device you happen to be on.

Working with tmux inside Termix is possible today and actually what I am doing right now to mitigate the limitations but it doesn't feel nice, and it requires manual setup every time. You have to SSH in, start a tmux session, and then remember to reattach to it on every new connection. And there is no scrollback without using tmux cumbersome (expecially on mobile) own method of <Ctrl>+B + >[ - you can image how easy this is on mobile (escpecially ) It's a workaround, not a solution. The ideal is for Termix to handle this automatically - detect if tmux is available, create sessions in tmux, and reattach seamlessly whenever you connect.

The Solution

The idea is to give users an opt-in setting (e.g., "Enable tmux integration") that wraps remote shells in tmux sessions on the target host. This would mean:

  • True persistence: processes on the remote host survive regardless of what happens to the browser, the Termix server, or the network in between. The tmux session lives on the remote host independently.
  • Cross-device continuity: since the session lives on the remote host, any Termix client (desktop, mobile, laptop, PWA) connecting to that host can pick up the same session. Start work on your desktop, continue on your phone, finish on your laptop - one session, zero friction.
  • Seamless reattachment: when reconnecting to a host, Termix detects existing tmux sessions it previously created and reattaches automatically - no manual tmux attach needed. Network drops, device switches, even Termix server restarts become invisible.
  • Deep scrollback: tmux maintains its own history buffer on the remote host. Termix could fetch it on demand (via tmux capture-pane), giving users access to far more history than the current client-side buffer allows.
  • Collaborative sessions: tmux natively supports multiple clients attached to the same session simultaneously. Two engineers could connect to the same tmux session through Termix and see the same terminal in real time - pair debugging, incident response, onboarding, all without screen sharing or third-party tools. This is a killer feature in many devops workflows - especially for teams working primarily remote - and comes essentially for free once tmux integration is in place.

Complete sketch of a possible implementation

I've already gone through the codebase and think my porposal is straightforward to implement. I have something similar running as test, it is not polished yet and everything it, of course, still open for discussion. I tried to follow existing patterns.

Where it fits in the codebase

Termix already has a per-host TerminalConfig (types/index.ts) with precedent for exactly this kind of feature: autoMosh and moshCommand auto-execute a mosh command on the SSH stream after connection. The tmux integration would follow the same pattern for configuration - a per-host opt-in, not a global toggle - so users can enable it selectively for hosts where they want persistence.

However, tmux integration needs to go deeper than mosh. The existing autoMosh is stateless and one-directional: the frontend sends a single command to the stream after connecting and never looks back. It doesn't inspect the remote host, doesn't track what it started, and doesn't help with reconnection - if the connection drops, mosh on the remote side may keep running but Termix has no way to find or reattach to it.

Tmux integration is inherently stateful. The backend needs to check whether a tmux session already exists on the remote host, decide whether to create a new one or reattach to an existing one, and communicate this back to the frontend. This means the core logic belongs in terminal.ts on the backend, not in the frontend Terminal.tsx.

Phase 1 - Tmux-aware connection (foundation + reattach)

New per-host config fields in TerminalConfig:

autoTmux: boolean          // enable tmux wrapping for this host
tmuxSessionPrefix: string  // default: "termix", used for naming sessions

After the SSH shell is created in handleConnectToHost (terminal.ts, the conn.shell() callback), the backend would:

  1. Check if tmux is available: command -v tmux >/dev/null 2>&1 && echo TMUX_OK || echo TMUX_MISSING
  2. If available, list existing Termix-managed sessions: tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^termix-"
  3. Based on the result:
    • No existing session: create one with tmux new-session -s termix-<hostId>-<shortId>
    • Existing session(s) found: send a new tmux_sessions_available message to the frontend with the list, let the user pick one (or auto-attach if there's exactly one match - most common case), then issue tmux attach -t <name>
  4. Track the tmux session name as part of TerminalSession (new field: tmuxSessionName)
  5. Send connected to the frontend only after the tmux session is attached

The naming convention (termix-<hostId>-<shortId>) ensures Termix only touches sessions it created, leaving user-managed tmux sessions alone.

The tricky part here is parsing the output of detection commands from the SSH stream, since everything goes through the same PTY. Two possible approaches:

  • Marker-based parsing: wrap commands in unique markers (e.g., echo "---TERMIX_BEGIN---"; command; echo "---TERMIX_END---") and parse the stream on the backend before forwarding to the frontend. This is what I'd start with.
  • Exec channel: use conn.exec() instead of the shell stream for the detection commands. Cleaner separation, but adds a second channel. To me, this seems the cleaner approach and would completely avoid polluting the terminal output.

I'd appreciate feedback on which approach you'd prefer.

Phase 2 - Cross-device continuity

With Phase 1 in place, cross-device handoff comes almost for free:

  1. User connects to a host from device B
  2. Backend detects existing termix-* session on the remote host (created earlier from device A)
  3. Backend offers reattachment, user confirms (or it auto-attaches)
  4. tmux (optionally!) detaches from the old connection (if still alive) and attaches to the new one
  5. User is exactly where they left off - full screen state, running processes, everything

The key insight: the persistence layer moves from the Termix server (in-memory, fragile) to the remote host (tmux, robust). The Termix server becomes stateless with respect to session continuity - it just brokers the SSH connection and tmux handles the rest.

The user may opt-in to have tmux automatically detach from old connections when a new one attaches, or they can choose to keep multiple devices attached simultaneously (tmux supports this natively). This gives users flexibility in how they want to manage their sessions across devices and whether they may want to have multiple clients attached at the same time (e.g., desktop + mobile) or even different users sharing a session for collaboration.

Phase 3 - Deeper scrollback

This is the most complex part and probably warrants its own separate PR after Phase 1+2 are stable. The basic idea I have right now is (no code written for this as of yet, just brainstorming):

  1. Configure tmux sessions with a large history-limit (e.g., tmux set-option -t <session> history-limit 50000)
  2. On reattach, tmux naturally replays the visible screen state
  3. For deeper history access, introduce a new message pair (scrollback_request / scrollback_data) where the backend runs tmux capture-pane -t <session> -p -S -<N> and sends the result to the frontend
  4. The frontend could display this in a separate scrollback overlay or viewer, since prepending into the live xterm.js buffer is a known hard problem

I'd explicitly defer this to a follow-up to keep the initial PR focused and reviewable.

What would NOT change

  • Users who don't enable autoTmux on a host get exactly the current behavior - full opt-in, preserving the existing experience
  • Termix's existing session persistence continues to work as-is for non-tmux sessions
  • No dependency on tmux being installed on the remote host; the feature degrades gracefully if tmux isn't found on the target system

Additional Context

TL;DR

If either the Termix server process or the SSH connection to any host breaks, the remote shell and everything running in it is lost. Seamlessly switching devices or concurrent work with two devices at the same time is not possible either. There is no practical way to move a session from desktop to phone to laptop. This makes it hard to work across devices or on unreliable connections without manually falling back to a tool specifically desgined for this: tmux (terminal multilexer):

tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.

Proposal: add an opt-in "tmux integration" setting that automatically wraps remote shells in named tmux sessions on the target host. Termix would detect existing sessions on connect and reattach transparently. This gives true persistence (processes survive any disconnection), cross-device continuity (pick up the same session from any Termix client), and deeper scrollback (fetched from tmux on demand). The feature degrades gracefully if tmux is not installed on the remote host.

I need this feature, so I will do the implementation work. I am not asking for someone else to do it, but would use this to contribute back to a project I love.

Offer

Repeating what I said above: I'm happy to do the implementation work on this. I've already gone through the code and did some tests myself.

Before writing code, I wanted to open this discussion to:

  1. Check if this is something the project would be willing to accept - I think it would be a great addition
  2. Get feedback on the approach - especially the exec channel vs. marker-based detection, and maybe other architectural considerations I haven't thought of
  3. Align on scope - I'd propose Phase 1+2 as the initial PR and Phase 3 (scrollback) as a follow-up

Looking forward to your thoughts!

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions