# trzsz-go: native trzsz file transfer for shell terminals

> trzsz-go is a Go implementation of the trzsz protocol, which lets you drag files into an SSH session and pull them back out without leaving the terminal, and it can also be embedded as a library in Go terminal applications. It replaces the old lrzsz pattern of running rz and sz inside a session, and it is a drop-in upgrade path for anyone used to that.

**trzsz/trzsz-go** — trzsz-go is the go version of trzsz, makes all terminals that support local shell to support trzsz ( trz / tsz ).

- Repository: https://github.com/trzsz/trzsz-go
- Website: https://trzsz.github.io/go
- Stars: 1,068 · Forks: 58
- Language: Go
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/trzsz-trzsz-go

## The problem: file transfer that leaves the terminal

trzsz-go is a CLI tool that enables native trzsz, trz and tsz, file transfer support in terminals with local shell support. It can also be embedded into Go-based terminal applications to provide native trzsz integration.

The problem it addresses is old and still common. The traditional way to move a file over SSH is to run rz or sz inside the session, which is the ZMODEM approach that lrzsz provides. That works, but it is fragile. The transfer is bound to the terminal's own capabilities, it depends on a program being installed on both ends, and the flow of the transfer is separate from the SSH session rather than integrated with it. The topic tags name the ancestry directly: lrzsz, rz, sz, zmodem, and trz and tsz as the trzsz equivalents.

What trzsz changes is that the transfer becomes native to the session rather than something you start inside it. The README's phrasing is that it makes all terminals that support local shell to support trzsz, and the mechanism is that you put trzsz in front of the command you were going to run anyway. The topic list also includes tmux, which tells you that the interesting and difficult case is the terminal multiplexer, where a naive implementation either breaks the multiplexer or silently fails to transfer.

The primary language is Go, the licence is MIT, and the release history shows v1.2.0 on 2026-01-17, v1.1.8 on 2024-08-18 and v1.1.7 on 2023-12-23. The repository is not archived and the last push was on 2026-10-10, so the work is current.

One recommendation in the README deserves attention because it is not obvious. It is recommended to use the go version of trzsz on the server, and to use trzsz-ssh, tssh, on the local machine. The protocol is a pair, and the recommended configuration is the Go implementation on the far end and the ssh helper on the near end.

## How the shell wrapper works, and the tmux problem

The usage section is the part that tells you how the thing actually behaves, and it is a sequence of three wrapping rules.

On the local computer, you add trzsz before the shell to support trzsz, trz and tsz:

```sh
trzsz bash
trzsz PowerShell
trzsz ssh x.x.x.x
```

So trzsz is a wrapper, not a transfer command in the first instance. It starts the program you actually want, in a mode where the terminal's own file transfer extensions are available.

The drag-and-drop variant adds --dragfile before the ssh:

```sh
trzsz -d ssh x.x.x.x
trzsz --dragfile ssh x.x.x.x
```

The jump server case is where it gets interesting, and it is the case the tmux topic tag points at. If you use tmux on the jump server, you use trzsz --relay ssh to log in to the remote server:

```sh
trzsz ssh jump_server
tmux
trzsz --relay ssh remote_server
```

The relay mode exists because a file transfer protocol needs a terminal on both ends, and a multiplexer sitting between them breaks the assumption that the two ends are talking to each other directly. The relay option handles the hop.

On the remote server, the commands are the familiar ones: similar to lrzsz with rz and sz, command trz to upload files and command tsz /path/to/file to download files.

The recommendation section adds two practical pieces. It is recommended to set `alias ssh="trzsz ssh"` for convenience, and `alias ssh="trzsz -d ssh"` for dragging files to upload. And if you use tmux on the local computer, you run tmux, without trzsz, first, and then trzsz ssh to log in. The order differs between the two ends: on the jump server tmux runs inside the wrapper, while on the local computer tmux is started first and the wrapper runs inside it.

The two alternative paths for people on the other side of the ecosystem are worth noting. The README points to trzsz-ssh, tssh, as the recommended local companion, and to https://trzsz.github.io/py for more general information about trzsz. So the protocol has several implementations and this one is the Go entry point, and the recommendation is that you use the matching pair.

## Building it, and the three binaries it produces

The Makefile shows the shape of the project, and it is three commands from one tree.

The default target builds three binaries, trz, tsz and trzsz, and the rules are explicit about their sources: the trz binary from ./cmd/trz and the shared ./trzsz/ package, the tsz binary from ./cmd/tsz, and the trzsz binary from ./cmd/trzsz. The shared package is the protocol implementation, and the three commands are the three ways to invoke it.

The install target copies all three into /usr/bin, and on Windows the target prints that the install target is not supported for Windows. The Windows handling is present throughout the Makefile: the binary names become trz.exe, tsz.exe and trzsz.exe, and the clean target uses PowerShell Remove-Item -Force rather than rm -f.

The test target runs the tests in the ./trzsz directory with verbose output and no cache, and there is a fallback for the test binary name, since the Makefile looks for a gotest binary first and falls back to go test.

Building from source is documented in the README as:

```sh
git clone --depth 1 https://github.com/trzsz/trzsz-go.git
cd trzsz-go
make
sudo make install
```

The Go install route requires go 1.26 or later and installs the same three commands:

```sh
go install github.com/trzsz/trzsz-go/cmd/trz@latest
go install github.com/trzsz/trzsz-go/cmd/tsz@latest
go install github.com/trzsz/trzsz-go/cmd/trzsz@latest
```

The binaries are usually located in ~/go/bin/, and on Windows in C:\Users\your_name\go\bin\.

The packaging coverage is unusually wide, and the README documents a route for every platform family. There is apt for Ubuntu and Debian, dnf for Fedora, CentOS and RHEL, and yum for legacy CentOS and RHEL with a gemfury or a wlnmp repository. There is yay for ArchLinux, brew install trzsz-go for MacOS, crew for ChromeOS, and scoop, winget and choco for Windows. There is also pixi, conda and mamba from conda-forge, and a local install from the GitHub Releases with deb, rpm and tar.gz artefacts.

The Ubuntu and Debian routes are worth comparing since they differ. Ubuntu adds the PPA and installs software-properties-common, while Debian installs curl and gpg and writes the repository list by hand with a signed-by keyring path, pointing at the jammy distribution.

## ZMODEM compatibility and clipboard integration

Two optional features are documented, and both have sharp edges that are stated rather than hidden.

The first is ZMODEM support. Use -z or --zmodem to enable the rz / sz feature, for example `trzsz -z ssh remote_server`. The catch is stated plainly: lrzsz needs to be installed on the client, the local computer, with examples given as `brew install lrzsz` and `apt install lrzsz`. So enabling the legacy path adds a second dependency on the local side, and the reason is straightforward, the zmodem protocol is a different protocol from the native one and needs the other implementation.

There is a platform exclusion here too. `trzsz --zmodem ssh xxx` is not supported on Windows, and the README directs you to trzsz-ssh, tssh, instead, with the form `tssh --zmodem xxx`.

The second is clipboard integration, enabled with -o or --osc52. The name and the flag point at the OSC 52 terminal escape sequence, which is the mechanism terminals use to set the system clipboard, and the -o shorthand is consistent with that. The honest position is that the flag exists, the detail is in the documentation at trzsz.github.io/go.

One accuracy note in the README is worth repeating, because it sets expectations about the transfer display. About the progress, the transferred and speed are not precise, there will be some deviation. It just indicates that a transfer is in progress. So the progress indicator is a rough indicator, and the README is straightforward about it rather than implying a byte-accurate display.

The dependency list in go.mod explains the rest of the implementation. There is github.com/creack/pty and github.com/UserExistsError/conpty for pseudo-terminals, the latter being the Windows equivalent, and chzyer/readline for line editing in the wrapped shell. lipgloss and the charmbracelet colour stack handle the terminal rendering, and atotto/clipboard and ncruces/zenity cover the clipboard and the native dialog boxes. google/shlex is there for tokenising the command line, klauspost/compress for the compression side of the transfer, and the author's own go-arg and promptui packages handle argument parsing and the interactive prompts. golang.org/x/term and golang.org/x/text handle the terminal and the text encoding.

## Where trzsz-go is the wrong choice

There are three limits, and the first one is a matter of scale rather than function.

The first is that trzsz is for interactive sessions with people in them. It is a wrapper around a command you are about to run, and the file transfer is available while that command runs. It is not a batch tool, not a sync tool, and not a replacement for a proper file transfer workflow. If your transfers are scripted, scheduled, or large enough to want resume and verification, then a tool that transfers over an interactive terminal session is the wrong category, and scp, sftp or rsync over the same SSH connection are the right answer.

The second is the shell interception itself. Every usage path puts trzsz in front of your shell or your ssh command, and that changes how the command behaves. A wrapper that sits between you and your shell is a place where the terminal's own file transfer negotiation can be altered, and if a program under the wrapper changes how it uses the terminal, the transfer path can be affected. The README's advice about running tmux first, without trzsz, and then trzsz ssh, is exactly the kind of detail that shows the interaction is not entirely transparent, and the three different orderings across local, jump server and remote are there because the naive arrangement does not work.

The third is the dual-implementation requirement. The trzsz protocol has more than one implementation, and the README recommends the Go version on the server and tssh on the local side. If one end of your infrastructure is not under your control, a client that insists on a specific peer implementation is a constraint. This is also why the ZMODEM fallback exists at all, and why that fallback needs lrzsz installed on the local machine.

For completeness, there is an embedding path that changes the calculus. The library can be built into a Go terminal application, which is what the README means by it can also be embedded into Go-based terminal applications. If you are writing the terminal application yourself, this is the right way to consume it, and the examples/ directory in the repository has an ssh_client.go and its own go.mod, so the library usage is documented by example rather than by an API reference. For an end user who just wants to move files over SSH, the CLI is the whole story.

## Conclusion

Adopt trzsz-go if you transfer files over SSH regularly and want the drag-and-drop and trz/tsz workflow without the fragility of lrzsz, or if you are building a Go terminal application and want the protocol handled for you. Do not adopt it if your transfers are one-off and scp already works for you, because this adds a wrapper to your shell invocations. Verify first that the Go version is what runs on the server side, since the README recommends it, and that the shell you use is one the trzsz wrapper can sit in front of without interfering with your terminal multiplexer setup.

## FAQ

### What is trzsz-go and what does it do?

It is a Go CLI tool that enables native trzsz, trz and tsz, file transfer support in terminals with local shell support, and it can also be embedded into Go-based terminal applications. It is the Go implementation of the trzsz protocol, which replaces the older lrzsz pattern of running rz and sz inside a session.

### How do I install trzsz-go?

The README documents routes for apt on Ubuntu and Debian, dnf and yum on the Red Hat family, yay on ArchLinux, brew install trzsz-go on MacOS, crew on ChromeOS, scoop, winget and choco on Windows, and pixi, conda and mamba from conda-forge. A Go install is `go install github.com/trzsz/trzsz-go/cmd/...@latest`, which requires go 1.26 or later.

### How do I use trzsz with SSH and tmux?

Put trzsz in front of the command, for example `trzsz ssh x.x.x.x`, and add --dragfile to enable dragging files to upload. If you use tmux on the jump server, log in with `trzsz ssh jump_server`, start tmux, and then connect onward with `trzsz --relay ssh remote_server`. If tmux is on the local computer, run tmux first and then trzsz ssh.

### Does trzsz-go support ZMODEM and clipboard integration?

Yes for both. The -z or --zmodem flag enables the rz and sz feature, which requires lrzsz installed on the local client, and it is not supported on Windows, where the README points to tssh --zmodem instead. Clipboard integration is enabled with -o or --osc52.

## Sources

- [License: MIT](https://github.com/trzsz/trzsz-go/blob/main/LICENSE)
- [Project website](https://trzsz.github.io/go)
- [README](https://github.com/trzsz/trzsz-go/blob/main/README.md)
- [Releases](https://github.com/trzsz/trzsz-go/releases)
- [trzsz/trzsz-go on GitHub](https://github.com/trzsz/trzsz-go)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/trzsz-trzsz-go
