libtmux Reference MCP Search

Attach and send keys

Edit this page on GitHub

The task: get a handle on a tmux session, find its active pane, type a command into it, and read back what printed. This is the round trip nearly every real program built on libtmux starts from — an agent that runs a command and checks the result, a test harness driving a CLI, a dashboard polling a long-running process. “Attach” here means obtaining a live handle from your program, not a terminal takeover — see Attaching to tmux for that distinction and for the real, terminal-taking-over kind Python also exposes.

Every block below is either read straight out of a file in that port’s own repository at build time, or quoted by hand from a doctest or README where no standalone file exists — the table at the end of this page says which, names the exact source, and says how that port’s own test suite checks it. None of it was rewritten to look alike: a whole tested file naturally carries more or fewer than exactly the three steps above — error handling, a second helper, a comment explaining a choice specific to that port, or no read-back at all — and that surrounding code is left in rather than trimmed to match. A difference in shape below is real fidelity to what each port actually ships, not inconsistency.

// No tmux failure is thrown. Every call answers with a value that is either
// the result or the reason there isn't one.
const auto sessions = server.sessions();
if (!sessions.has_value()) {
std::fprintf(stderr, "%s\n", sessions.error().diagnostic.c_str());
return 1;
}
for (const libtmux::Session& session : *sessions) {
std::printf("%s has %lld window(s)\n", std::string{session.name()}.c_str(),
session.window_count());
}
const libtmux::Session& session = sessions->at(0);
// Build an arrangement without composing a single tmux argument.
const auto editor = session.new_window({.name = "editor"});
if (!editor.has_value()) {
std::fprintf(stderr, "%s\n", editor.error().diagnostic.c_str());
return 1;
}
const auto logs = editor->split({.horizontal = true, .percentage = 30});
if (!logs.has_value()) {
std::fprintf(stderr, "%s\n", logs.error().diagnostic.c_str());
return 1;
}
(void)logs->send_text("journalctl -f");
(void)logs->send_key("Enter");

Finding an existing session insteadLink to section

Every snippet above creates a fresh session. A script that runs more than once usually wants the opposite — attach if a session by that name already exists, create it otherwise. See Attaching to tmux for the verified call in each port, and Filtering and querying, in practice for what to do when the lookup might match more than one.

Where this comes fromLink to section

PortSourceIn this pageChecked by
Pythonsrc/libtmux/server.py, session.py, pane.py docstringshand-quoted, composed from three separate docstringspytest runs every >>> doctest (testpaths includes src/libtmux) against a real, isolated tmux session on every test run
TypeScriptexamples/quickstart/quickstart.tsread whole from the filerun against real tmux by bun test examples; its first half is also mirrored into README.md under a <!-- runs: ... --> marker, checked line-for-line by scripts/check-doc-runnable.ts
Rustcrates/libtmux/examples/scratch.rsread whole from the filerun to completion against a throwaway tmux by scripts/run-examples.sh (just examples), which CI runs and which also asserts the example leaves no session behind
Goexamples/quickstart/main.goread whole from the filethe whole file runs against a real tmux server as TestQuickstart; the docs:quickstart region inside it is additionally mirrored into README.md by go generate ./tmux, and CI fails if the two drift
Javaexamples/src/main/java/io/github/libtmux/examples/BuildAWorkspace.javaread whole from the filerun against real tmux by the examples module’s own ExamplesRunTest
.NETexamples/LibTmux.Examples/Snippets/OneShot.csread whole from the fileits ConnectAndBuild region is mirrored into README.md and checked by sync_snippets.py --check; the mirrored csharp run block is additionally compiled and run by ReadmeExampleTests
C++examples/05-readme.cpp, the connect and build regionshand-quoted — the file also carries the regions for five other sections of the READMEquoted verbatim into README.md, checked for drift by tools/docs/check_readme.py, and the whole file is built and run by CTest
SwiftExamples/Sources/ExampleCode/Changing.swiftread whole from the filematched against the README’s “Change what is there” section by Scripts/check_examples.py; compiled and run through the package’s public products by swift test --package-path Examples

“Read whole from the file” means the fence names the file with file="..." and the page is built by reading it, so the block above cannot say anything the file itself does not — there is no separate copy to fall out of sync. Nothing in any port’s repository uses the marker comments (region: name / endregion) this site’s own tooling looks for to slice a piece out of a longer file, so where only part of a file is relevant here, that part is quoted by hand instead, with the file and region named in the table above rather than pretended into a file= fence that would fail to build.

Esc

Type to search.