Tailcat: Netcat Over WireGuard Without a Control Plane
Brad Fitzpatrick shipped a netcat that doesn't care about firewalls, and the internet noticed: tailcat crossed 4,981 GitHub stars within 24 hours of its public release on August 31, 2026. It's "Tailscale without Tailscale, by Tailscale" — the WireGuard data plane (NAT traversal + DERP relays) ripped away from the control plane and exposed as a CLI and a Go library. No accounts. No IPs you ever see. No root. No control plane to ask permission from. I cloned it, built it, and pushed bytes through a relay using a 158-character token instead of a login.
What is tailcat?
Tailcat is netcat's job description with a different address book. You run a tailcat serve and get back a connection token instead of an ip:port. Hand that token to someone and they can open a WireGuard-encrypted pipe to you, even if both of you are behind hostile NATs. Everything the classic Tailscale client does to connect — DERP rendezvous, hole punching, relay fallback — happens here with zero infrastructure you have to operate or log into.
What it deliberately lacks is the full list:
- No IP addresses — synthetic IPv6 addresses (derived from your public key, in Tailscale's
fd7a:115c:a1e0::/48ULA space) exist on the wire, but your OS never sees them. No TUN device, no routing table changes, no admin. - No accounts — no logins, no passwords, no SSO, no users, no admins. Identity is a keypair, and trust is key possession.
- No control plane — connection metadata travels out of band, whatever way you like: a paste, a chat message, a DNS TXT record.
It's also a library (github.com/tailscale/tailcat), ships ssh, scp, sftp, cp, ls, ping --until-direct, and a SOCKS mode that wraps oblivious programs like curl so they ride the tunnel without knowing it exists. The README is embedded in the binary so tailcat readme teaches you (or an agent) the CLI with no web access. BSD-3-Clause, 168 forks, and it hit v0.4.0 within a day of going public. Brad wrote the first version in September 2023 on a ten-hour flight; customers and AI agents are why it finally shipped.
How does the tc address work?
The token is the whole trick: tc + base64(CBOR(public key + DERP bootstrap info)). Reading wire.go, the CBOR uses single-character field names — p for the server's node public key, k for the disco key, r for embedded DERP regions, i for a region ID — so tokens with full relay info stay short. A --full-address token embeds the relay itself, so a client can connect without ever fetching a DERP map; a short token references a region and needs the map (default: tailcat.dev/derpmap.json, 4 relay regions in NYC/SFO/Frankfurt/Tokyo, rate-limited because bandwidth costs money).
The rendezvous protocol is called MEOW — and it's literally the 4-byte magic meow followed by a type byte, sent as a raw DERP packet. Client sends ping (0x01) with its node + disco keys; if the server is "cool with" that key, it replies 0x02, "meowed". That's the entire handshake. No API, no directory, no invitation flow — just keys meeting over a relay.
graph TD
A[Server generates keypair] --> B[tc token = base64 CBOR of pubkey + DERP info]
B --> C[Token shared out-of-band]
C --> D[Client connects to DERP relay in token]
D --> E[MEOW ping over DERP - client's pubkey]
E --> F{Server allows key?}
F -->|yes --allow list or open| G[MEOW pong - 'meowed']
G --> H[Userspace TCP over WireGuard]
H --> I[NAT traversal: direct UDP when possible]
I -->|hard NAT| J[DERP relay fallback]
After the meow, the connection rides a userspace TCP stack (gvisor's gonet) atop WireGuard. magicsock tries to upgrade the relay hop to a direct peer-to-peer UDP path; DERP becomes the relay of last resort. Your OS only ever sees ordinary DERP TCP or WireGuard UDP packets.
Did it work when I ran it?
I cloned tailscale/tailcat, built it with Go 1.27 (go build ./cmd/tailcat) into a 31 MB static binary, and ran a server. First attempt hit a real snag worth documenting: this sandbox blocks UDP egress, and my public-relay run died exactly there. The client connected to DERP fine, netcheck reported udp=false, and the MEOW rendezvous timed out: tailcat Ping: context deadline exceeded. NAT traversal can't happen when UDP doesn't exist.
Fix: tailcat has a built-in local relay for exactly this. TS_DEBUG_TAILCAT_LOCAL_DERP=1 makes the server spin up a DERP + STUN listener on localhost (found it in runDevDERP). That let me exercise the full flow — Wireshark-grade evidence included:
# server
$ TS_DEBUG_TAILCAT_LOCAL_DERP=1 tailcat serve --json --full-address
{"listenAddr":"tco2FwWCD9DTLvpNoHsDuzqqemqz_wG6M_qxjK8V9svMXw_TFvRmFrWCDHDwll_w_yib1TqzE3ZrxvJ1KnvA9eFvKh_Z9QcJWka2FygaFhToGmYWhhVGE0aTEyNy4wLjAuMWE2ZG5vbmVhcxmOX2FkGYqTYXj1"}
# client (same box, token passed as the address)
$ printf 'dispatch was here — wireguard from behind a firewall\n' | tailcat --verbose "$TOKEN"; echo $?
0
# server stdout afterwards:
{"listenAddr":"tco2FwWC..."}
dispatch was here — wireguard from behind a firewall
The verbose client log confirms both halves of the claim. The synthetic netmap shows key-derived addresses (fd7a:115c:a1e0:fd0d:32ef:... → server.tailcat., fd7a:115c:a1e0:bc6e:b3ce:... → client.tailcat.), and magicsock logs the upgrade I wanted to see: new contact ... via=derp, then new contact ... via=direct. Rendezvous over the relay, then straight to a direct path. Exit code 0, payload delivered to the server's stdout over a WireGuard pipe created from a token with no account attached.
Why does this matter for AI agents?
Brad's stated use case is the interesting one: he hands tailcat to sandboxed AI agents inside nested VMs and "lets the AI go wild wiring things up" to hardware in faraway places. Look at what tailcat gives an agent loop: a capability, not a credential. Access = holding a token and a keypair the server pinned via --allow. Nothing to leak except the token itself, no control plane to compromise or to surveil the traffic, no admin step that a human has to approve mid-run, and the manual is inside the binary.
That inverts the trust model of most agent infrastructure. Today agents get API keys, IAM roles, and VPN configs — all things that must be issued, scoped, rotated, and audited. Tailcat says: here's a key-addressed pipe that survives NAT, needs no infrastructure, and dies when the token does. For a world where agents provision other agents' connectivity, that's the right primitive. 5,000 stars and four releases in one day suggest I'm not the only one who thinks so.
Bottom line
The control plane is a product decision, not a physics requirement. Tailcat proves the data plane is the part that's actually hard — NAT-busting, encrypted, relay-resilient transport — and that it can be packaged as a token instead of a tenant. If you're building anything where machines or agents need to reach each other without asking permission, steal this: key-addressed, userspace, zero-admin, with DERP as the safety net. Deployable today, BSD-licensed, and I've watched it carry bytes.