CLI tool
neuralink/tsui avatar
neuralink/tsui

tsui is a Tailscale terminal UI for the users Tailscale left on the command line

An (experimental) elegant TUI for configuring Tailscale.

528 stars24 forksGoMIT

At a glance

What is it?
tsui is a Go program from Neuralink that puts a settings screen, exit node comparison, debug information and bandwidth view in front of Tailscale, built on Bubble Tea with the Tailscale client library itself. It installs as a single binary on macOS and Linux, and the README calls it experimental.
Who is it for?
Adopt tsui if you administer Tailscale from a Linux machine and would rather click through settings than remember the CLI flags, because the feature list covers the operations that are otherwise memorised commands, and it is a single binary with no dependency on the Tailscale package. Do not adopt it for Windows, since the README supports tsui on macOS and Linux only, both x86_64 and aarch64.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap the project fills, and why it exists

The README explains the motivation in a single sentence: Tailscale has lovely desktop apps for macOS and Windows, so Linux users are stuck configuring Tailscale with CLI commands.

That is a precise statement of the problem, and the word stuck is the operative one. The Tailscale CLI can do everything the desktop app does, but every operation is a command with flags that have to be remembered, and the commands that matter, switching an exit node, checking which peers are reachable, regenerating a login URL, pulling the debug bundle, are not things most people use often enough to remember.

So tsui is a terminal user interface built around the same operations, and the feature list is exactly the list of things a CLI user does badly:

- Edit Tailscale options with a full settings interface - Switch exit nodes and compare their latency - View and copy debug information - See your bandwidth - See and copy IP addresses of accessible peers - Easily log in, out, and reauthenticate

Two of those deserve a note. Comparing exit node latency is not a Tailscale feature, it is a tsui feature, and it is the one that adds information rather than just moving the same controls into a keyboard interface. Seeing and copying the IP addresses of accessible peers is the second, because that is the information you need when a peer is not resolving and you are trying to work out whether the problem is the tailnet or the device.

The project is from Neuralink, and the homepage is neuralink.com/tsui. The primary language is Go, the licence is MIT, the default branch is main, and the last push was on 2026-10-18. The recent releases are v0.2.0 from 2024-09-03, v0.1.0 from 2024-08-16 and v0.0.4 from 2024-08-01, and the description calls the tool experimental.

That combination, an active repository with a 2024 release history, says something specific: the code is being worked on while the last tagged release is two years old, which is the pattern of an internal tool that gets maintained rather than versioned for outside users.

It links the Tailscale client library rather than shelling out

The go.mod is where the design decision becomes visible, and it is not the obvious one.

The direct dependencies are three: github.com/charmbracelet/bubbletea at 0.26.6 for the terminal UI framework, github.com/charmbracelet/lipgloss at 0.12.1 for styling, and tailscale.com at 1.70.0. That last one is the significant entry. tsui imports the Tailscale client library directly, so it runs the Tailscale client in-process and talks to the local API, rather than executing tailscale commands and parsing their output.

The difference matters in three ways. First, there is no output parsing, so the behaviour does not depend on the wording of a CLI help message or on the formatting of a table. Second, the tool is talking to the same client the daemon uses, so it sees the state the daemon has, including things the CLI surfaces awkwardly. Third, it means tsui is bound to a particular client library version, and the pinned 1.70.0 is a statement about which Tailscale generation it was built against.

The indirect dependency list is where the cost shows. It includes the Tailscale platform layers for Windows, macOS and Linux, the go-osc52 package and the termenv and muesli packages for terminal capability detection and colour handling, go-isatty and go-runewidth and uniseg for terminal measurement, edwards25519 and the consensus libraries for the cryptographic side that Tailscale needs, and the DERP and control-plane plumbing that comes with the tailscale.com module whether you want it or not. A TUI that links the whole Tailscale client is a large binary, which is why the README says tsui is distributed as a single binary that shouldn't require any dependencies, and that is a deliberate trade rather than an accident.

The repository layout matches the shape of the program. There is tsui.go at the root, menus.go and view.go for the interface structure, update.go for the self-update path, clipboard/ for the clipboard handling, ui/ for the screens, version/ for the version string, libts/ for the Tailscale-facing code, and scripts/ for the build scripts.

The roadmap, the self-update path, and what the interface is missing

The README lists what the authors want to add next, and the list is short enough to be a good description of the current gaps.

More useful peer options is first, which reads as the biggest gap in the feature set. The current version lets you see and copy the IP addresses of accessible peers, but the README does not describe any way to change a peer's settings, and for a tailnet that is a real limitation because a peer is where you set a subnet router, an exit node or an advertised route.

Start the daemon on macOS is second, which is an interesting admission. The tool supports macOS, and it configures a daemon that macOS does not run by default. So on a Mac the user is expected to have Tailscale running some other way, and the author wants tsui to be able to start it.

Multiple accounts and custom login URLs is third, and it is a limitation with a security dimension. A Tailscale installation normally has one account, and the login flow produces a URL you visit in a browser to authenticate. Supporting several accounts means switching which tailnet you are logged into, and supporting custom login URLs means pointing at a different identity provider or a self-hosted headscale instance rather than the default.

The interface structure is visible in the repository layout, and it tells you how the program is organised. menus.go holds the menu definitions, view.go the screens, ui/ the individual views, clipboard/ the clipboard handling, update.go the self-update logic, and libts/ the code that talks to Tailscale. There is also a version/ directory, which in a project with an update.go is where the current version is tracked so the updater can compare it against the released one.

That update.go is worth a mention on its own. A tool distributed as a single binary through a curl installer and a releases page will go stale, and a self-update path is how the author avoids users running an old binary that no longer speaks the current client library. It is also a maintenance obligation: the update check has to keep working when the release layout changes.

Installing, and the two ways to build it

tsui supports macOS and Linux, both x86_64 and aarch64 architectures, and there are two installation routes.

The first is an installer script:

sh
curl -fsSL https://neuralink.com/tsui/install.sh | bash

The second is to download the latest release from the releases page, which points at the neuralinkcorp/tsui repository. Either way you end up with a single binary that shouldn't require any dependencies, and once it is installed you run tsui with no arguments.

For development there are two supported toolchains, and the README explains when to prefer each.

With Nix, which it calls likely your best option if you have Nix installed, because it guarantees the environment is set up consistently and the dependencies you need are available. You need the nix-command and flakes experimental features enabled. Then:

sh
nix develop

go run .

or to run directly through Nix:

sh
nix run

and to build a binary:

sh
nix build

./result/bin/tsui

With Go, the README says if you want to use Nix you can still build with the Go toolchain, and lists the requirements: Go installed, and on Linux libx11-dev. There is a clipboard detail too. On Wayland Linux sessions, install wl-clipboard if you want native Wayland clipboard support, because tsui falls back to X11 when wl-copy is unavailable. On macOS you may also need the X11 development package for Go's cgo-based X11 support.

The X11 dependency is worth flagging. It is not optional in the sense that the clipboard package falls back to X11, and Go's cgo-based X11 support requires the X11 development headers to build, which is why libx11-dev appears in the Linux requirements.

The development commands mirror each other:

sh
go run .
sh
go build .

./tsui

Production builds are handled by two scripts, and both need Docker, with Nix also needed on macOS. The first builds binaries for all platforms and architectures and only works on macOS:

sh
./scripts/build-all.sh

The second builds Linux binaries for all architectures:

sh
./scripts/build-linux.sh

For either script, binaries land in the artifacts/ directory. The Dockerfile.build file at the repository root is what the scripts use to get a reproducible toolchain, and the asymmetry between the two scripts is a deliberate one, since cross-compiling from Linux to macOS is not something Go handles cleanly.

Where tsui is the wrong tool

Three limits, and the first is about what the interface can do.

The first is that a TUI cannot show you more than a terminal can hold. The peer list, the exit node comparison and the debug information are all things a terminal renders happily. The bandwidth view is the one that pushes against the format, because a live bandwidth graph wants to be a graph, and what you get instead is a number in a panel that you read once a second. The upstream Tailscale desktop apps can draw that; a terminal client cannot.

The second is the coupling to a pinned client library. Because tsui imports tailscale.com directly at version 1.70.0, the tool has to be rebuilt when Tailscale's client library changes underneath it, and that is a compatibility job the author has to do rather than one you can influence. For a tool whose whole purpose is to configure Tailscale, being out of step with the daemon it configures is a functional problem, not just a cosmetic one. The 2024 release history against an October 2026 last push is consistent with that: the code is being kept working against a moving dependency without a stream of tagged releases.

The third is that this is a Linux and macOS tool for a product whose desktop apps cover those platforms, so the audience is narrower than it may first appear, and it is a single-vendor project rather than a community one. The homepage is a corporate domain, the repository lives under a company organisation rather than a community one, and the README asks nothing of contributors beyond the implied usual. There is no issue tracker policy, no discussion forum and no code of conduct in the repository entries. That is fine for an internal tool that happens to be published, and it is the reason there is no GitHub releases beyond 2024 and no visible maintenance commitment for outside users.

The alternative approach is the Tailscale CLI with a wrapper script, or the upstream tailscale web interface that runs on the tailnet's own coordination server. The difference is that tsui is the only one of the three that gives you a settings interface locally without going to the browser, and it is also the only one that has to be rebuilt when the client library moves. For a machine you administer every day the interface is the reason to use it. For a machine you touch once a quarter, the CLI is less to install and never goes stale.

Editorial conclusion

Adopt tsui if you administer Tailscale from a Linux machine and would rather click through settings than remember the CLI flags, because the feature list covers the operations that are otherwise memorised commands, and it is a single binary with no dependency on the Tailscale package. Do not adopt it for Windows, since the README supports tsui on macOS and Linux only, both x86_64 and aarch64. Verify first that your Tailscale daemon is reachable the way tsui expects, that the version of the Tailscale client library the binary was built against matches the daemon you run, since the program links tailscale.com directly rather than shelling out, and that the clipboard features work on your session, because tsui falls back to X11 when wl-copy is unavailable on a Wayland session.

Frequently asked questions

What does tsui do for Tailscale users?

It provides a terminal interface for editing Tailscale options with a full settings screen, switching exit nodes and comparing their latency, viewing and copying debug information, seeing bandwidth, seeing and copying peer IP addresses, and logging in, out or reauthenticating.

Which platforms does tsui support?

macOS and Linux, both x86_64 and aarch64 architectures. It is distributed as a single binary that should not require any dependencies, either from the installer script or from the releases page.

How does tsui talk to Tailscale?

It links the Tailscale client library itself, tailscale.com at 1.70.0, rather than running tailscale commands and parsing their output, and it builds its interface on Bubble Tea with Lip Gloss for styling.

What does tsui need on a Wayland Linux session?

The README says to install wl-clipboard if you want native Wayland clipboard support, because tsui falls back to X11 when wl-copy is unavailable. On Linux you also need libx11-dev to build, and on macOS you may need the X11 development package.

How do I build tsui with Nix?

Enable the nix-command and flakes experimental features, then use nix develop with go run . to work on it, nix run to run it directly, or nix build and ./result/bin/tsui to produce a binary. The Nix path guarantees a consistent environment with the dependencies available.

How are tsui production binaries built?

With two scripts that require Docker, and Nix as well on macOS. ./scripts/build-all.sh builds binaries for all platforms and architectures but only works on macOS, and ./scripts/build-linux.sh builds Linux binaries for all architectures. Output goes to the artifacts/ directory.

Official sources

  1. License: MIT
  2. neuralink/tsui on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/neuralink-tsui.svg)](https://hysenlabs.com/projects/neuralink-tsui)

Was this useful?