How nodeterm Uses the tmux paste-buffer -p Command for Reliable Multi-Line Input
The paste-buffer -p command in nodeterm delegates bracketed-paste framing decisions to tmux itself, ensuring multi-line text transmits correctly across all tmux versions without relying on version-specific variable probes.
The nodeterm project runs each terminal session inside a persistent tmux pane to maintain state and enable agent communication. When transmitting multi-line commands or agent payloads, the application must handle bracketed-paste mode correctly to prevent mangled input. The paste-buffer -p command provides a version-independent mechanism that respects the target pane's actual paste mode state.
The Problem with Version-Dependent Bracketed-Paste Detection
Earlier implementations of nodeterm's tmux integration attempted to detect bracketed-paste support by probing the tmux variable #{bracket_paste_flag}. This approach proved fragile because the variable only returns accurate values on tmux 3.7 and newer. On older versions commonly deployed in production environments (3.4, 3.2, 3.3, etc.), this probe always returns false.
When the probe fails, applications fall back to raw newline insertion using \r terminators instead of \n. This causes multi-line input to split incorrectly, breaking agent integrations with Claude, Codex, Gemini, and other AI systems that expect properly framed payloads. According to the source analysis in CLAUDE.md, this created the historic "multi-line write mangles" bug that affected agent message delivery.
How paste-buffer -p Solves Version Compatibility
The robust solution implemented in nodeterm removes version detection entirely by leveraging tmux's native paste handling through the -p flag.
Delegating Framing Decisions to tmux
The -p flag instructs tmux to wrap buffer contents with bracketed-paste escape sequences (\e[2004h and \e[2004l) only if the application inside the target pane has explicitly requested bracketed-paste mode. This delegates the decision to the tmux server, which maintains accurate state information regardless of version.
When the pane does not request bracketed paste, tmux transmits the text unchanged without adding escape sequences. This eliminates the need for nodeterm to query #{bracket_paste_flag} or maintain version-specific code paths. As implemented in the source code, this approach works uniformly across tmux 3.2 through 3.7 and future releases.
Handling Copy-Mode Edge Cases
The command also addresses interactions with tmux's copy-mode. When a pane enters copy-mode (for scrolling or selection), raw paste operations might behave unpredictably or insert text into the scrollback buffer rather than the active prompt.
Nodeterm guards against this by prepending a conditional check to cancel copy-mode before executing the paste operation. This ensures the payload reaches the active shell regardless of the pane's current state.
Implementation in nodeterm Source Code
The integration appears throughout nodeterm's core modules, with specific implementations handling different payload types.
Constructing the Command in pty-manager.ts
In src/core/pty-manager.ts, the sendText implementation constructs a compound tmux command that loads text into a temporary buffer, conditionally exits copy-mode, and executes the paste operation with proper flags.
// src/core/pty-manager.ts (excerpt)
const cmd = `tmux load-buffer -b nt - \\; if-shell -F -t ${target} '#{pane_in_mode}' 'send-keys -t ${target} -X cancel' \\; paste-buffer -d -p -r -b nt -t ${target}`;
This command sequence performs three critical operations:
load-buffer -b nt– Loads the payload into a temporary buffer namedntif-shell '#{pane_in_mode}'– Detects if the pane is in copy-mode and cancels itpaste-buffer -d -p -r– Pastes with delete-after (-d), bracketed-paste support (-p), and newline preservation (-r)
The -r flag specifically ensures that newlines remain as \n characters rather than being converted to carriage returns, which preserves multi-line command structure.
Agent Message Delivery
The same mechanism appears in src/core/agents/agent-message.ts when delivering JSON payloads to AI agents. By routing all agent communication through paste-buffer -p, nodeterm guarantees that structured data arrives intact without frame corruption or line-ending translation errors.
// src/core/agents/agent-message.ts (conceptual excerpt)
// Payload is first written to tmux buffer, then delivered via:
tmux paste-buffer -p -b agent_buffer -t ${target_pane}
High-Level Architecture Documentation
The design rationale appears in src/core/tmux-naming.ts, which documents how the -p flag removes the "bracket-paste question" by eliminating version-dependent probes. This file serves as the architectural reference for why nodeterm prefers delegated paste handling over manual escape sequence injection.
Verification and Testing
The project includes integration tests in src/core/tmux-paste.realtmux.test.ts that validate paste-buffer -p behavior across supported tmux versions. These tests confirm that the command correctly frames text on older tmux installations (3.2, 3.3, 3.4) while maintaining compatibility with newer releases.
The test suite specifically verifies that multi-line payloads containing \n characters arrive at the target application without mangling, proving that the -p flag removes the version-specific limitations that previously affected nodeterm's tmux integration.
Summary
- The
tmux paste-buffer -pcommand delegates bracketed-paste framing to the tmux server, eliminating version-dependent variable probes. - This fixes multi-line input mangling on tmux versions older than 3.7 by ensuring proper
\npreservation and escape sequence handling. - Nodeterm implements this in
src/core/pty-manager.tswith a compound command that also handles copy-mode cancellation. - Agent messages in
src/core/agents/agent-message.tsrely on the same mechanism for reliable JSON payload delivery. - Integration tests in
src/core/tmux-paste.realtmux.test.tsverify correct behavior across all supported tmux versions.
Frequently Asked Questions
What does the -p flag do in tmux paste-buffer?
The -p flag instructs tmux to examine the target pane's bracketed-paste state and automatically wrap the buffer contents with \e[2004h (start paste) and \e[2004l (end paste) escape sequences only when the underlying application has requested bracketed-paste mode. If the pane does not support or request this mode, tmux transmits the raw text without escape sequences.
Why did older nodeterm versions struggle with multi-line input?
Previous implementations probed #{bracket_paste_flag} to detect paste mode support, but this variable only returns accurate values on tmux 3.7+. On older versions, the false negative caused nodeterm to use \r line endings instead of \n, splitting multi-line commands into fragmented inputs that broke agent parsing and shell execution.
How does nodeterm prevent paste operations from interfering with copy-mode?
The command constructed in src/core/pty-manager.ts includes an if-shell guard that checks #{pane_in_mode}. When copy-mode is active, the command first executes send-keys -X cancel to exit scrollback/selection mode before invoking paste-buffer -p, ensuring text always reaches the active command line.
Which tmux versions support the paste-buffer -p functionality?
The -p flag for bracketed-paste awareness works reliably across all tmux versions supported by nodeterm, including 3.2, 3.3, 3.4, and 3.7+. Because the flag delegates framing logic to the tmux server rather than querying version-specific variables, it provides consistent behavior regardless of the host system's tmux installation age.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →