Repository navigation
Conversation
why: Task completion can publish before the virtual worker stops. what: - Join the owned fixture worker before asserting its cleanup.
why: macOS resolves fixture socket paths through /private/tmp while tmux preserves the original /tmp spelling in its command arguments. what: - Match sockets by their resolved paths during ownership checks. - Cover ancestor-link aliases and control-process ownership.
why: Captured values can outlive a client, while capture I/O must finish within the server's resource scope. what: - Add an executable lazy traversal and eager capture example. - Check the capture count in the documentation test.
why: Cancellation publishes the terminal outcome asynchronously. what: - Observe the cancelled task before resubmission - Remove the JDK 25 admission timing race
why: Fixture scanning conflated a tmux client with its daemon. what: - Read the authenticated daemon PID from tmux - Cover concurrent client ownership
why: Client operations need live evidence that preserves the captured target. what: - Attach an owned control client in the Clojure integration fixture - Assert switch and detach through refreshed client observations
why: Closing a runtime could test completion-executor quiescence before its queued callback cancellations ran. what: - Snapshot callback stages and await their scheduled cancellation - Keep the wait within the runtime's existing cleanup deadline - Record the caller-visible close behavior in the changelog
why: A labeled matrix cannot establish Clojure compatibility unless the selected runtime and tmux binary are verified by the process under test. what: - Add four Clojure/JDK check and package cells - Add forty Linux and eight macOS Clojure real-tmux cells - Assert the Clojure runtime selected for each integration run
why: A newer client can reach an older daemon, and the socket can change after a version probe. Refuse unsupported ordinary Server operations before requested effects while retaining existing incarnation and ownership fences. what: - Check the daemon's complete patch-aware version; consult a fresh executable report only on an unused endpoint. Preserve standalone -V and -h diagnostics. - Prepend a native version guard without rewriting raw argv, batches, existing guards or stdin. Use -N after a live version check and on absent non-starting paths. - Share bounded request execution with carrier probes without exposing a remote-carrier ProcessTransport instance. Retain request budgets, borrowed ownership and dispatch certainty. - Remove detached-size and prompt-inventory adaptations made obsolete by the 3.3a floor. Keep compatibility still needed inside the supported range. - Add version check, replacement, disappearance, malformed-version and carrier regressions. Update recording fixtures without weakening data batching, input cohort or native PID guard checks. - Regenerate the operations reference and Kotlin ABI for call-time compatibility preflight. Preserve JDK process-argument inspection with an ASCII-space native no-op.
why: Python builders and shells execute outside the Java dispatcher. A Java preflight alone cannot enforce the core floor through an obsolete installed Python libtmux backend. what: - Check the selected daemon, or the executable only when absent, before external builder and shell entry. - Require the Python backend's declared core floor to be at least 3.3a before loading builder or shell code. Repeat the handshake in every child process. - Report the selected interpreter and compatible backend requirement without inventing a release pin. The coordinated Python core change is PR779. - Remove the CLI's obsolete retry without detached session dimensions. - Cover old-client refusal, obsolete backend refusal before effects, qualified backend success and real tmuxp 1.74.0 extensions using the coordinated Python source.
why: Facade transports must distinguish the version check from requested work so their lifecycle, cancellation and cohort assertions keep measuring the operation under test. what: - Answer exact daemon-version probes in Kotlin, Cats and workspace fixtures without counting them as application effects. - Inspect original commands after the separate native guard in MCP and fixture recording transports. - Retain the native wait-process readiness and cancellation assertions, staging-session cleanup and PID incarnation checks.
why: The supported matrix and user-facing requirements must agree with the core version check. The extra version probe also changes process-count guidance. what: - Remove 3.2a and unpatched 3.3 from required CI and local matrix lanes; keep the remaining supported and preview lanes. - Update JVM facade, example, workspace CLI and contributor requirements to 3.3a. - Describe version-probe reports and the extra process before ordinary command groups, captures and filtered reads. - Update benchmark generator explanations while leaving historical generated measurements at their recorded commit.
why: Users must upgrade the running daemon as well as the client, and external Python backends need their own command-level version checks. what: - Describe daemon-first refusal, unused endpoints, diagnostics and full version-token handling. - Document call-time compatibility preflight and the bounded control- startup check without claiming endpoint pinning. - Link the unreleased Python core PR and distinguish its dispatcher guarantee from Java preflight. - State the requirement that configured command aliases preserve the native built-ins used for the version check.
why: The raised daemon minimum changes which installations and Python backends can run JVM products. what: - Record the core 3.3a requirement under Unreleased, reference issue 67 and link the migration instructions.
why: tmux 3.3a prints its executable basename before the version. A renamed or symlinked supported binary must still pass the cold version check. what: - Accept the exact configured basename or canonical tmux banner - Keep full version-token checks and bare daemon reports unchanged - Cover mismatched names, malformed releases and daemon authority
why: A delivered marker can cross terminal rows and disappear from a literal substring assertion even though both intended panes received it. what: - Join soft-wrapped rows in the shared typing capture helper - Reproduce wrapping with ready cat consumers at a fixed pane width - Retain effective-recipient and disabled-pane assertions
why: Released tmuxp pins Python libtmux before the core version check, so the Python bridge correctly refuses the existing CI installation. what: - Install released tmuxp normally and overlay reviewed Python source - Pin the source commit and assert its import path and 3.3a floor - Apply the same qualification to JDK and supported tmux lanes
why: The cold version check and delivered-text assertions depend on native behavior that differs from a simple version or substring assumption. what: - Record renamed tmux 3.3a version banners from copies and symlinks - Record soft-wrap capture results on native 3.3a and 3.7d
why: The reviewed source overlay qualifies the command version check without claiming a released or coherently installed tmuxp and libtmux pair. what: - Link the exact Python source used by the CI overlay - State the import-path check and pending tmuxp dependency update
why: A user may configure a renamed or symlinked tmux 3.3a executable when creating the first session on an unused endpoint. what: - Clarify that the cold version check accepts configured executable names
why: A wrapped completion marker or output arriving before a wait's entry capture made JDK checks fail for unrelated fixture timing. what: - Join soft-wrapped completion capture and force that regression. - Release shell output after the real wait entry capture. - Preserve cold and warm echo assertions without a fixed delay.
why: The version check asked the daemon for `display-message -p '#{version}'`.
display-message fires a user's `after-display-message` hook on every
tmux release, so the probe itself had effects before a refusal could
stop anything.
what:
- Probe with `run-shell -C '<marker>#{version}'`, marker
`libtmux-version-<random hex>-`. The daemon expands the format and
fails to parse the result as a command, so the version is read from
`unknown command: <marker><version>` on stderr. run-shell has no
after-hook, and a parse failure inside its -C callback never reaches
command-error. The live endpoint still gets -N.
- Another request's marker, a plain success, or any other stderr is not
an answer: absent-endpoint wording still means an unused endpoint,
anything else is a rejected probe.
- Test doubles (core, MCP, workspace, junit5, integration, Kotlin and
Cats fake binaries) answer the new probe through VersionProbes;
FakeTmux answers it for fixtures and carriers.
- VersionCheckHooksIntegrationTest arms after-display-message and, on
3.5+, command-error hooks, runs checked calls and requires neither
to fire, with a control that fires each hook the ordinary way.
- Unit cases pin the probe shape, a foreign marker, `master` and other
unknown suffixes, and `next-3.9`.
Verified: VersionCheckHooksIntegrationTest passes on 3.3a (command-error
case skipped, no such hook), 3.5, 3.6b and master (next-3.9). Restoring
display-message as the probe fails the after-display-message case on 3.3a
and 3.5 ("the version check ran the user's after-display-message hook").
:libtmux, :libtmux-junit5, :libtmux-workspace and :libtmux-scala-cats
test tasks pass.
why: The operations guide said the version check emits a display-message probe report, which is no longer the command sent. what: - Name run-shell and state that the version check fires none of a user's after-* or command-error hooks.
why: JDK 25/27 and the 3.5 and master lanes failed four WaitingForTextTest cases with PRESENT_AT_ENTRY. Keys sent to a shell that is still starting are echoed by the terminal and the shell draws its prompt straight after that echo on the same row, so the echo is glued to the prompt and no longer stands apart as a typed line. That is not the case these tests pin. The previous follow-up replaced the fixtures with a capture-gated release that still sent keys into the starting shell and failed the same way. what: - Restore the trunk fixtures of WaitingForTextTest. - Wait for the pane to show something and hold still for half a second before typeAndSubmit and send write to it. Verified with 20 busy loops on a 10-core host, bash with a long prompt, tmux 3.5 lane. The trunk fixtures fail sendThenWaitDoesNotMatchTheEchoedCommandLine (PRESENT_AT_ENTRY) and the previous follow-up fails four cases with the same outcome; with the wait, RunningCommandsTest, TypingTest and WaitingForTextTest pass under the same load. Trunk's libtmux-mcp:test is restored FROM-CACHE in CI, so its own run never exercised these cases.
Records that the version check reads the daemon version with run-shell -C and fires none of a user's hooks.
Applies the project formatter to the capture call added by the settle wait; no behaviour change.
why: The stalled-control fixture wrapped tmux and blocked on a FIFO for
any argument equal to `-C`. The version probe is now
`run-shell -C '<marker>#{version}'`, so the wrapper blocked the probe
and Server.cmd timed out before the control attach was ever reached
("cancelling control ends promptly and kills the stalled process"
failed with DispatchException$TimedOut). The process scan matched the
transient probe process the same way.
what:
- Block on `attach-session`, which only the control attach carries.
- Look for the stalled client by `-C` together with `attach-session`.
Verified: the case failed on this branch before the change and passes
after it (`:libtmux-kotlin:test --tests '*WaitsTest*'`).
why: The workspace CLI hands builders, plugins and shell code to a Python libtmux. The core version check (3.3a) alone does not tell the CLI that interpreter also refuses the optional operations Java refuses, so a backend with only the floor could run an unsafe literal command. what: - The runtime prelude requires the integer TMUX_OPTIONAL_FEATURE_POLICY_VERSION >= 2 next to the 3.3a floor, in the runtime probe and again in the child, before external code runs. - Cases cover a missing, 0, 1, boolean, string and float marker, and a child that passes the probe but fails the recheck; none enters the backend. - CI and the tmux matrix qualify tmuxp 1.74.0 with the Python libtmux source overlay that carries the marker (tmux-python/libtmux PR 780), and assert the marker besides the import path and floor. Released tmuxp still pins libtmux 0.61, so the overlay is not a coherent installed package pair.
why: At the 3.3a floor a few operations still misbehave on particular releases: named buffer delete and rename act on an unrelated buffer before 3.4, `split-window -p` is unreliable on 3.4, an invalid layout string kills a 3.3a daemon, an unnamed or raw `break-pane` ends or renames on exact 3.7, and a single-pane break prints no id before 3.6. Each must be decided from the connected daemon, for typed calls and for literal commands alike, so it can no longer fail after an earlier command in a batch had its effect. what: - TmuxFeatures inspects the literal commands a request carries (full verbs, aliases and unambiguous prefixes, option clustering, `--`) against the checked daemon version and refuses with UnsupportedFeatureException or IllegalArgumentException before the fenced batch is sent. - Versions.execute applies it after the version check; Server, IncarnationFence and handle batches pass the commands they represent. - Buffers.delete, Pane.paste and its callback form stop checking the version themselves: the dispatch-level guard covers them, and the paste temporary buffer is refused before it is created. - Pane.breakOut() is refused on exact 3.7; breakOut(name) keeps the post-break rename. A break is read back with display-message on the moved pane, so releases that print nothing for a single-pane break still return the new window. - Direct `paste-buffer -d -b`, user-authored if-shell bodies and alias contents keep native behaviour; no second script parser is added. Verified on real tmux with OptionalFeatureIntegrationTest.
why: Control clients are only qualified on stable tmux 3.7 and newer; a short-lived control attach crashes 3.2a and 3.6b servers. Until now the version check ran through the carrier and the later `-C` attach named the socket path again, so a daemon replaced in between could receive the attach, and a long socket path could exceed sun_path. what: - ControlAcquisition decides first, with the hook-free version probe, and refuses a daemon below a stable 3.7 (development builds and release candidates included) before any control client exists. It then reads the daemon identity, pins the socket, rereads the identity through the pin and attaches with `-N` to the pinned alias. One deadline covers qualification and attach. - ControlCarrier gains pinSocket; the default refuses, so custom carriers must retain the socket in their own realm. The process transport and the local carrier use LocalSocketPin: a private 0700 directory on the socket's filesystem holding a hard link, under the 103-byte limit, removed on close, EOF or failed attach. - ControlClient.attach, attachUnfenced and Server.control go through it; Server.control refuses before its identity read. Literal commands sent over a control line pass the same feature guards. - Subprocess and polling paths are untouched below 3.7. - Tests: control-positive cases carry the control tag and the matrix runs them from 3.7; every lane asserts the refusal and that no client attached. Cases that only needed some attached client use NativeClient. Fakes (FakeTmux, the Kotlin and Cats control scripts, ControlClientTest) answer the probe, the identity read and the pin. Verified on real tmux 3.3a and 3.7 with ControlAcquisitionIntegrationTest, ControlFloorIntegrationTest and the control suites.
why: The facade is two published modules with a Clojure runner of their own, and the repository's gates (platform coverage, release attestation, dependency verification, documentation facts) have to know them. what: - Include libtmux-clojure and libtmux-clojure-core-async, put them in the BOM, and add the Clojure, core.async and Manifold versions. - The clojure-library convention plugin compiles and runs the namespaces under a load guard; it defaults to JDK 25, the core's baseline. - integration-tests depend on the modules and run the Clojure suite as clojureIntegrationTest; docs scans .clj sources. - Checksums of the Clojure artifacts join the dependency verification metadata, and the release attests their jars.
why: Provide captured tmux values, explicit effects, bounded async work, and stream adaptation without duplicating the Java engine. what: - Publish core and optional core.async Clojure modules through the BOM. - Add captured snapshots, bounded tasks, control streams, and byte events. - Test owned real-tmux fixtures, documentation fences, artifacts, and Clojure boundary contracts.
…sion why: The facade was written before master moved its exception types to io.github.libtmux.exception, renamed the version refusal to UnsupportedFeatureException, took `capture()` for a package-private reader, and put a version probe and a fence in front of every call. what: - Translate TargetGoneException, ServerUnavailableException, UnsupportedFeatureException, ServerClosedException and DispatchException (with its TimedOut subtype); the refusal is now :tmux/unsupported-feature and is reported as not dispatched. - Read the capture view through Server.captureServer and run shell commands through Server.shell. - The fake transports of the unit tests answer the admission probe and count only the requests a call makes; grouped replies skip the leading version fence, so a group is five requests instead of four.
…criptions why: Master's control client now decodes pane output per pane, reports overflow as a gap ahead of the events that remain, and refuses a daemon below a stable tmux 3.7 before any client attaches. The facade carried its own byte-limited subscriptions, UTF-8 decoder and termination reasons for an older client. what: - attach! goes through Server.control, so the incarnation check, the 3.7 floor and the pinned socket are the Java core's; an older daemon raises :tmux/unsupported-feature, not dispatched, with no client. - subscribe! keeps :encoding (:bytes or :utf-8) and :capacity. The :max-bytes, :malformed and :max-panes options go: the Java client decodes per pane and writes a byte that is not UTF-8 as \xHH. - next! returns a :gap with :gap/events ahead of the events that remain and a terminal map whose :reason is :closed after a close and :ended, with the original :cause, when the client ended the stream. Events the client delivered stay readable after it ends; a close discards them. - core.async observe! drops the byte and decoder options and forwards gaps. - Integration tests run control scenarios on stable 3.7+ and assert the refusal, with no attached client, on older daemons; documentation snippets that attach use a `control` directive with the same rule. - Guide and READMEs state the control floor and the stream contract.
why: The Java core compiles for JDK 25, so the JDK 21 runtime the facade named loads none of it; the tmux lanes still ran releases the core now refuses; the macOS tmux build lacked a utf8proc choice that 3.3a and later require; and master's checks want actions pinned to commits and deps.edn on the current development version. what: - Run the compatibility workflow on JDK 25 and 27, start the tmux matrix at 3.3a (the core's own lanes refuse 3.2a and 3.3) and pass --disable-utf8proc to the macOS tmux build. - Pin the workflow's actions to the commits the other workflows use. - Move deps.edn to 0.0.1-alpha.17-SNAPSHOT.
Notes Server.captureServer and the Clojure close-runtime! fix.
why: A known daemon is admitted once, so the capture case's two data requests sit behind one probe, not two. what: - Expect three requests: the identity read, the grouped listings and the one probe.
…check class
why: `test-tmux-3.2a` and `test-tmux-3.3` exist in every module that
applies the matrix plugin, and Gradle failed the ones whose test set,
filtered to the version check class, is empty (":libtmux-junit5:test-tmux-3.2a").
what:
- The rejection lanes do not fail on a module with no matching test.
Verified: both lanes pass across all modules, running the version check case
only in integration-tests.
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 14:57
6988620 to
e57f5e0
Compare
why: The supported range starts at 3.3a, but the streaming guide said a
feature needed "3.2 and later", the parity map labelled its rows "3.2a
through 3.7b", and several test and source comments gave 3.2a as the
start of the range. Historical measurements ("measured on 3.2a") stay.
what:
- Say "every supported tmux" in the streaming guide, "3.3a through 3.7c"
in the parity map, and "across the supported range" in the comments
that stated a range; make the WRITING.md example comment not name a
release.
Verified with :docs:test.
why: Control clients now need tmux 3.7, but several integration cases only needed some client attached to a session, and the workspace CLI process test kept a private copy of the PTY helper. Both need the same standard-library pseudo-terminal driver. what: - Move the PTY helper into gradle/test-fixtures and serve it as a test resource of integration-tests and libtmux-workspace-cli, so it never enters a published artifact. - Add NativeClient, an ordinary terminal client that attaches to a session through that driver, owns its process tree and detaches on close. - ProcessTest reads the shared helper. Python 3 is already required by the PTY tests; CONTRIBUTING is updated with the control commit's documentation.
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 15:44
e57f5e0 to
e295b16
Compare
…able why: The watching examples attach a control client, which a daemon older than 3.7 now refuses. The JDK checks run them against the runner's tmux 3.4 and failed (RunnableExamplesSuite, ExamplesRunTest, MainsTest). what: - Those cases assume ControlAcquisition.supports (Scala: the fixture's supportsControl), so they run on 3.7 and newer and are skipped below. Verified with :examples:test under tmux 3.4.
…e capacity why: The Clojure facade reads a whole server as one consistent value and releases waits through a transport slot reserved for them. The Java core offered neither: a capture was a snapshot the caller had to wrap, and a wait-for release shared admission with ordinary commands. what: - Server.captureServer returns a CapturedServer: sessions, window links, pane occurrences and clients from one observed graph, read-only lists, no command after acquisition. (`capture()` is master's package-private snapshot reader, so the public name differs.) - Server.batchReservingCapacity and chainReservingCapacity dispatch through the admitted waiting path, so the release command is admitted like any other and a daemon below the floor is refused before it runs. - Unit and real-tmux cases for the view and the reserved-capacity groups.
why: On the JDK 27 lanes Gradle itself ran on 27 and the build-logic
Kotlin compile failed ("Inconsistent JVM-target compatibility ... (27)
and (26)").
what:
- Install the lane's JDK and 25 together with 25 last, as ci.yml does;
-PlibtmuxJavaVersion still selects the JDK that runs the Clojure.
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 18:53
f8faa9f to
e77e759
Compare
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 20:07
e77e759 to
80f1754
Compare
tony
force-pushed
the
bump-min-tmux-001
branch
from
October 17, 2026 22:26
80f1754 to
f7a8e83
Compare
tony
force-pushed
the
bump-min-tmux-001
branch
4 times, most recently
from
October 18, 2026 12:50
586e66d to
bd1e4d8
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.
Stacked on the Java tmux-support PRs
This draft now targets
bump-min-tmux-001and cannot merge before the core minimum change (tmux 3.3a floor, hook-free version check) and the optional-feature change (control needs tmux 3.7 or newer, exact-3.7 name rule, pinned control socket). Its diff is Clojure-only: no merges and no duplicates of those PRs' commits. After they land, retarget it tomaster.Summary
libtmux-clojurewith captured values, explicit tmux effects, local collection processing, bounded tasks, and owned control streams.libtmux-clojure-core-asyncwithout adding core.async to the core module.Server.captureServer(named so becausecapture()is master's package-private snapshot reader) and reserved-capacity batches that go through the checked waiting path.:tmux/unsupported-featurefor a refused floor, reported as not dispatched), version probes and fences in the unit-test transports,Server.shell.Contract
control/attach!goes throughServer.control: tmux 3.7 or newer, decided before any client attaches (next-3.7and3.7-rc2do not qualify;3.8-rc2andnext-3.8do). An older daemon raises:tmux/unsupported-feature, not dispatched, with no client attached.subscribe!keeps:encoding(:bytesor:utf-8) and:capacity.:max-bytes,:malformedand:max-panesare gone: master's Java client decodes per pane (a byte that is not UTF-8 is written\xHH) and the subscription is bounded by event count only, so the old memory bound in bytes no longer exists.next!returns a:gapahead of the events that remain and a terminal map whose:reasonis:closedor:endedwith the original:cause.Verification (Linux/WSL)
:docs:test,clojureDependencyMetadata,platformCoversEveryPublishedModule,spotlessCheck,:libtmux:test: pass.:integration-tests:clojureIntegrationTest: 41 tests, 0 failures on tmux 3.3a, 3.5, 3.7 and master (next-3.9). Control scenarios run on 3.7 and newer; older daemons assert the refusal with no attached client. Reporting the refusal as:tmux/transportfails every control case on 3.3a.Test plan