Repository navigation
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## bump-min-tmux-000 #780 +/- ##
=====================================================
+ Coverage 54.24% 55.56% +1.31%
=====================================================
Files 30 30
Lines 3969 4136 +167
Branches 767 803 +36
=====================================================
+ Hits 2153 2298 +145
- Misses 1519 1534 +15
- Partials 297 304 +7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 08:43
93eab73 to
54b277b
Compare
This was referenced Oct 17, 2026
Check literal commands and complete batches before effects. Require 3.4 for named-buffer identity and 3.5 for captured shell-job stdout. Refuse defective native 3.4 percentages and exact 3.7 raw breaks; retain portable typed percentages and explicit-name break repair. Select operational flags from the daemon and expose the backend policy contract.
Require stable daemon 3.7 before starting control mode. Own a private socket hard link, verify daemon identity through it and keep it until client cleanup. Retry short same-filesystem carriers for long paths and cross-device temp roots. Retain baseline fixtures and test native refusals, replacement, option aliases and cleanup.
Document each daemon requirement, native 3.7 name rejection, partial break repair and the optional-policy backend marker. State the Linux/WSL carrier evidence and continuing readiness obligations.
Keep 3.3a and patched releases in the full matrix; add exact 3.7 so native name rejection and break-pane refusal/repair retain coverage.
Record the optional requirements independently of the 3.3a core minimum.
tmux 3.3a through 3.5 completes the sole-pane break path before printing -P, leaving the wrapper to index an empty result after the operation. Refresh the actual pane context on successful empty output and retain nonzero-exit refusal. Native regression cases cover named and unnamed calls with both current and externally moved pane contexts. The focused feature suite passes on 3.3a, 3.4, 3.5, exact 3.7 and 3.7d; exact 3.7 unnamed refusal remains in force.
Note that a successful single-pane Pane.break_pane() returns its actual window on tmux 3.3a through 3.5, whose native relink path prints no ID. Keep the release note separate from runtime changes.
why: tmux 3.3a can terminate its daemon when select-layout reaches an invalid header. A raw batch must refuse that operand before its prefix commands execute. what: - Keep unique presets and standard serialized headers on 3.3a - Preserve native cycling, spread and undo argument handling - Carry canonical, alias and prefix calls through whole-batch validation - Advance the backend policy contract to version 2 - Record the native client pairing limit independently of the core floor
ControlMode read the daemon's version, pid, start time and socket path with display-message -p, which fires a user's after-display-message hook before the pin or the 3.7 eligibility check could refuse anything. Read the same fields with `-N run-shell -C`, whose failed parse reports the expanded text without running an after-* or command-error hook. The expanded text is parsed as a tmux command, so the fields are comma separated and the socket path, which may hold any character, is single-quoted with embedded quotes re-opened. A report spanning several lines is refused so a newline in the path cannot truncate it. Tests: a native test sets after-display-message and command-error hooks, acquires and releases a control client, then fires a control display-message and a failing command; each sentinel holding exactly one letter shows the pin fired none. A second test reads a socket path holding quotes, a semicolon, braces, a hash, a dollar sign and a comma. The Popen trackers ignore the probe's own -C. The mocked probes in test_optional_features.py answer in the run-shell format. Verification: restoring display-message fails the hook test. The control, version check and optional-feature modules pass on 3.7d; ruff and mypy are clean.
Note that control acquisition runs no user hooks before it validates the endpoint. Keep the release note separate from runtime changes.
On 3.3a an invalid select-layout string was refused with a bare ValueError, while 3.4 and newer failed the same call with a LibTmuxException, so callers that catch the library's base class (tmuxp's builder, MCP tool error mapping) saw a different type only on the floor release. Add InvalidLayout, which is a LibTmuxException and still a ValueError for existing handlers, and raise it from the guard. Test: the 3.3a refusal tests expect InvalidLayout, and a hierarchy test pins both bases. Restoring the bare ValueError fails the 3.3a refusal cases. The optional-feature module passes on 3.3a.
Backend consumers identified the optional-feature contract by an integer, libtmux.common.TMUX_OPTIONAL_FEATURE_POLICY_VERSION, and called the private _require_commands. Publish version check.require_commands(version, argv, repaired_break=False) and drop the marker: a consumer that needs the policy imports the function, and an older libtmux without it fails the import rather than passing a number check. Test: the 3.3a refusals for named-buffer deletion and layouts, the 3.4 control, paste-and-delete staying available, and the exact 3.7 break-pane refusal and its explicit-name repair. Replacing the function body with a no-op fails the new test. The version check module and its doctest pass on 3.7d.
Replace the policy-version paragraph: programs that run their own tmux subprocesses apply the optional-feature checks through libtmux._internal.support.require_commands.
Note InvalidLayout, the public command policy and the return-type change of Server.run_shell(target_pane=...) from an empty list to None. Keep the release note separate from runtime changes.
tony
force-pushed
the
bump-min-tmux-000
branch
from
October 17, 2026 12:25
6d1be63 to
73f82c7
Compare
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 12:25
54b277b to
309fdfe
Compare
This was referenced Oct 17, 2026
ControlMode refused `3.8-rc2` and `next-3.8` because it required a stable
`X.Y[a-z]` report on top of the ranked comparison. Check anything that ranks at
or above 3.7 final under the same strict ordering as version check, and refuse
`next-3.7` and `3.7-rc*`, which rank below it.
Registration also asked `list-clients` for the control client's name, a
command a user can hook. tmux names a client with no tty `client-<pid>`, so
set that name from the spawned process and wait for registration with the
hook-free `run-shell -C '<marker>#{L:#{client_pid},}'` instead.
Tests: a table checks 3.7, 3.7a, 3.7d, 3.8, 3.8-rc, 3.8-rc2, next-3.8 and
next-3.9 and refuses 3.6b, 3.7-rc, 3.7-rc3, next-3.7, 3.3a, master and the
empty string; a live client's name equals tmux's own; the hook test now also
arms after-list-clients, after-list-panes, after-list-sessions and
after-refresh-client and asserts none fired. Restoring the stable-only check
fails four version check cases; restoring the list-clients poll fails the hook
test. The control module passes on 3.7d (27 passed, 1 skipped).
tmux 3.7 rejects `:` and `.` in window and session names; 3.7a reverted it. libtmux checked only session names, on every release, and left window names to tmux's own error after the command had started. Check `new-window -n`, `new-session -s/-n`, `rename-window` and `rename-session` (including aliases, prefixes and `;`-joined items) before dispatch when the daemon is exactly 3.7, in the same command policy that guards named buffers and break-pane, so typed methods, raw commands, batches and the libtmux-mcp/tmuxp paths that call the policy inherit it. The refusal is a VersionTooLow naming the name. Tests: nine name commands are refused on 3.7, pass on 3.3a, 3.6b, 3.7a, 3.8 and 3.8-rc2, and targets or formats holding delimiters stay allowed. The native window and session tests pass on a real exact-3.7 build. Removing the check fails all nine refusal cases.
The options and hooks page, the filtering comparison and the format-field docstrings still named tmux 3.2 or 3.2a as the project minimum. State 3.3a, the supported floor; the 3.3 entries in the format table are always met.
Note the strict control eligibility ranking, local client naming and the window and session name refusal on tmux 3.7. Keep the release note separate from runtime changes.
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 16:16
309fdfe to
8907eeb
Compare
tony
force-pushed
the
bump-min-tmux-000
branch
2 times, most recently
from
October 17, 2026 17:39
71f1bb5 to
f6e4630
Compare
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 17:40
8907eeb to
5df9cb3
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Keep ordinary subprocess operations on tmux 3.3a and qualify optional features separately. This PR stacks on the core minimum change.
paste-buffer -b NAME -dselect-layouton 3.3abreak-panebefore 3.6break-paneon exact 3.7split-window -pon 3.4-l N%:or.on exact 3.7Control acquisition validates the actual daemon, reading its version, pid, start time and socket path with the hook-free
run-shell -Cprobe so no user hook runs before the 3.7 check, creates a private hard link to its Unix socket, and checks identity through that link before starting-C. A replaced public socket cannot redirect initialization to an older daemon. The alias remains owned through client registration and is cleaned up with the client resources. A short temporary carrier and same-filesystem peer fallback retain valid long endpoints and cross-device temporary roots. Unsupported socket-link filesystems refuse acquisition. Local native evidence covers Linux/WSL; macOS remains CI qualification.Literal argv command items and flat batches receive the relevant feature checks before any requested command runs. Exact aliases retain their native meanings, including
setfor options. Opaque shell/tmux programs and configured alias bodies retain native semantics. Library-owned metadata and guard commands must retain native built-in semantics. Raw client output does not promise captured nested shell-job stdout.Operational format and flag decisions use the connected daemon rather than the executable's diagnostic version. Readiness checks, output buffering, polling and wire decoding remain necessary. On exact 3.7 a later rename failure can leave the pane moved; the error describes that partial effect. Older supported releases retain ordinary break-pane naming.
Validation:
IndexError. Ruff/mypy pass and an independent review verifies the final four-file delta.display-message, now usesrun-shell -Cwith comma-separated fields and a single-quoted socket path. A native test shows acquiring a control client fires neitherafter-display-messagenorcommand-error, and fails whendisplay-messageis restored; a second reads a socket path holding quotes, a semicolon, braces, a hash, a dollar sign and a comma. The control, version check and optional-feature modules pass on 3.3a, 3.4, 3.6b, 3.7d, 3.8 and master (control cases skip below 3.7).libtmux._internal.support.require_commandslets other engines apply this enforcement contract before handing off work; it replaces the integer policy marker, so a consumer imports a function and an older libtmux fails the import. On 3.3a the layout guard raisesInvalidLayout, aLibTmuxExceptionthat is still aValueError, instead of a bareValueError, so callers that catch the library's base class see one type on every release. The final layout follow-up passes the whole native feature file on all five releases (42, 41, 41, 43 and 41 passes respectively, with feature-specific skips) and strict Sphinx, with exact source bytes unchanged. The prior implementation fails all three canonical/alias/prefix refusal regressions. Independent review checks the native option and serialized-header semantics. Native clients 3.3a, 3.4 and 3.5 cannot register control with an exact-3.7 daemon; the same daemon stays alive and a newer compatible client registers. This pairing limit does not raise ordinary support. Hosted CI passes on tmux 3.3a, 3.4, 3.5, 3.6, 3.7, 3.7a, 3.7b and master, and on the 3.2a/3.3 rejection job, at revision309fdfed(run); the native results above qualify the local Linux/WSL environment.The CHANGES entry records that
Server.run_shell(target_pane=...)now returnsNone, as its signature documents, instead of an empty list.Merge and release order: #779 and this PR land first and libtmux 0.63.0 is released from them; libtmux-mcp (#139, #140) and tmuxp (#1092, #1093) require 0.63.0 and merge only after that release. Nothing here tags or releases.
Closes #778.