Skip to content

feat!: migrate to tmux-lib 0.7 - #147

Merged
graelo merged 8 commits into
mainfrom
feat/tmux-lib-0.7
Oct 11, 2026
Merged

graelo merged 8 commits into
mainfrom
feat/tmux-lib-0.7

Conversation

@graelo

@graelo graelo commented Oct 11, 2026

Copy link
Copy Markdown
Owner

Pull request

Summary

Moves tmux-backup to tmux-lib 0.7: the synchronous Tmux handle, then the
control-mode transport.

  • Breaking: no async runtime. save, autosave, restore and the
    Catalog methods are plain functions; smol, async-fs and futures are
    gone, taking 33 crates out of the build. Panes are still captured, and
    sessions still restored, in parallel, on threads.
  • tmux-backup spawns no tmux process of its own: naming the current client,
    listing clients and messaging a chosen client are tmux-lib operations.
  • save and autosave run over one tmux control connection, and fall back to
    forking when no control client can attach. Breaking: save takes the
    client to record, resolved before attaching, because tmux may name an
    attached control client as the current one.
  • Autosave reports now reach the selected client (display-message -c, not
    -t), and autosave no longer fails reading that client.
  • Restoring a backup taken outside a tmux client suggests tmux attach
    instead of tmux attach -t with an empty name.
  • tmux 3.4 or later is required, as tmux-lib 0.7 requires it; the README now
    says so.
  • The CHANGELOG notes that a backup taken on tmux 3.8 cannot be restored on an
    earlier tmux, whose select-layout rejects the 3.8 layout format.

Test plan

  • make check-all passes (tests, Clippy, dependencies, commits, Markdown,
    workflow scans)
  • Saves over the control connection compared with saves over forked
    clients on the same sessions: archives are byte-identical
  • 125 panes × 3000 lines, forked clients vs. control connection: a save
    went from 2.05 s ± 0.31 to 0.51 s ± 0.01 (hyperfine), peak memory from
    23 MiB to 12.7 MiB
  • tmux 3.8: a floating pane is restored with its geometry, floating flag
    and content
  • Autosave from outside tmux picks the most recently active client in
    either attach order, and reports only to it; from inside a pane it records
    that client; with no client attached it fails with exit code 1

tmux-lib 0.6.0 replaces its async free functions with methods on a `Tmux`
handle. The handle is created once per run and cloned into the tasks that need
it; blocking calls cross into the async runtime through `smol::unblock`.

Two places change shape rather than just spelling. Pane captures keep one
spawned tmux per pane — tmux-lib measured a single control connection against
that fan-out and kept the fan-out — so each capture is its own `unblock`.
Restoring one session is a long sequence of blocking calls, so the whole
sequence moves off the executor once instead of task-hopping between calls,
which preserves the per-session parallelism it always had.

This crate no longer invokes tmux itself. Naming the current client, listing
clients to pick the most recently active one, and displaying a message to a
chosen client are tmux-lib operations now, which fixes two bugs:

- The autosave client was read through a hand-written `-F` format that no
  longer matched what tmux-lib parses, so autosave failed outside tmux.
- Autosave reports were addressed with `display-message -t <client>`. `-t` is
  a target *pane*; with a second client attached, tmux delivered the message
  to the other one. Selecting a client is `-c`.

The client-selection tests move to tmux-lib along with the logic.

Verified end to end against an isolated tmux server: save, restore and
autosave all round-trip, including a session named with non-ASCII characters
and captured pane content, with the autosave report landing on the intended
client.
They already did blocking file and zstd I/O inside async functions. The
per-archive metadata reads of `catalog list --details` now run on scoped
threads instead of async tasks.
Every tmux call was already blocking and bridged with smol::unblock. The
metadata query now overlaps with the pane captures on a scoped thread,
each pane is captured on its own scoped thread, and each session is
restored on its own. Archives are byte-identical to before.
save, autosave, restore and the Catalog methods are plain functions, and
the binary no longer starts a runtime. The smol, async-fs and futures
dependencies are gone.
save and autosave run on one control connection instead of forking a
tmux client per command and per pane, and fall back to forking when no
control client can attach.

save now takes the client to record. tmux may name an attached control
client as the current one, so the binary resolves the client on a
spawning handle before attaching, and reports to tmux only once the
control client has detached.
A backup taken outside a tmux client records no client, and the restore
hint then read `tmux attach -t ` with nothing after it.
tmux-lib 0.7 requires tmux 3.4 or later, now stated in the README.
@graelo
graelo merged commit abd0a1a into main Oct 11, 2026
@graelo
graelo deleted the feat/tmux-lib-0.7 branch October 11, 2026 19:19
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