Tuxlink is a native Linux desktop Winlink client for amateur radio (ham radio) emergency communications. It implements the Winlink B2F protocol directly in Rust and drives real radios over HF, VHF packet, APRS, and the internet. A live HF Winlink session and a VHF APRS tactical-chat channel run at the same time in one workspace, and the same station is operable by an AI agent under an operator-armed consent gate.
Tuxlink fuses strategic and tactical emergency communications in one workspace: long-haul Winlink email over HF, and tactical APRS messaging over VHF and UHF with native control of the Benshi UV-Pro handheld. Routines automate repeatable radio tasks under the same Part 97 consent model, and Elmer, the docked in-app assistant, or any external MCP-capable agent can operate the station directly, gated by the operator's arm/disarm control.
Tip
Coming from Winlink Express or Pat? Start with
Moving from other Winlink clients:
settings mapping, conceptual differences, current parity gaps, and a
recommended migration sequence (including how to carry mailbox history across
by copying the native-mbox/ directory).
The running Tuxlink mailbox with privacy-safe sample data: dashboard ribbon, folder sidebar, message list, reading pane, and status bar.
Winlink is the de-facto amateur radio email system used by emergency-communications (emcomm) teams, ARES and CERT organizations, the Red Cross, and offshore cruisers. It moves email-style messages over radio when the internet is down.
Two clients already reach the Winlink network on Linux. Winlink Express, the proprietary Windows reference client, runs under WINE. Pat is an open-source Go client with broad transport support, pairing a command-line tool with an optional browser-served web UI.
| Winlink Express | Pat | Tuxlink | |
|---|---|---|---|
| Native Linux, no WINE | No (Windows) | Yes | Yes |
| ARM / Raspberry Pi | No | Yes | Yes |
| Native desktop GUI | Windows only | No (CLI + web UI) | Yes |
| Winlink forms | Yes | Yes (fetched) | Yes (included + native composers) |
| Native UV-Pro Bluetooth control | No | No | Yes |
| AI-agent control (MCP server) | No | No | Yes |
| Automation routines (flowchart designer, schedule triggers) | Not documented | Scriptable (CRON-like scheduled connect / QSY commands); no visual designer | Yes (designer, dashboard, run journal, consent gating) |
| In-app AI assistant (Elmer) | Not documented | Not documented | Yes |
| Multi-window operation (pop surfaces into separate OS windows) | Not documented | No (single web UI / CLI surface) | Yes |
| FT8 band monitoring | Not documented | Not documented | Yes (receive-only) |
| Off-air space weather (WWV/WWVH decode) | Not documented | Not documented | Yes |
Tuxlink takes a third path: it implements the Winlink B2F protocol itself, natively in Rust. The mailbox, the CMS connection, and the wire-protocol exchange are one self-contained application. The same build-it-natively approach reaches the radio link: Tuxlink is developing Sonde, a clean-room native HF modem of its own.
On that native engine it ships a single Tauri desktop application. The complete Winlink Express Standard Forms catalog, an address book, station finding, location-aware request workflows, full-text search, and an offline map all ship in the box, and first run is a guided wizard. The OS keyring holds the Winlink CMS password; Tuxlink never writes it to a config file on disk. The mailbox, compose pane, address book, and session log all render inside one desktop window.
Tuxlink unifies two layers of emergency communication that operators have historically run on separate devices. The strategic layer carries Winlink email over HF to wherever propagation reaches. The tactical layer carries APRS position and text over VHF and UHF to stations in local range, with native control of the Benshi UV-Pro handheld. Both run from one workspace on a mains-powered Linux station, instead of a Windows laptop for Winlink alongside a battery handheld for APRS.
Note
Tuxlink is in alpha and looking for testers. It installs from .deb,
.rpm, and .AppImage artifacts on every release. It is not yet ready for
field deployment. Install it, run it through real workflows, and
file an issue with a clear
repro and the exported logs (Help → Logging → Export logs).
Specifically, Tuxlink needs validation with a wide variety of radios. It's
tested against a Digirig, a DRA-series soundcard interface with CAT-keyed HF
rigs (through the included rigctld), Bluetooth KISS, and the Benshi UV Pro
protocol. Please report hardware successes/failures with specific radios and
interfaces using the Help menu in Tuxlink.
Version tags are generated automatically from conventional-commit activity by release-please and track repository velocity, not release readiness. The Maturity section covers which paths are validated and which are operator-verified.
Tuxlink ships the following on Linux for x86_64 and arm64:
- Native B2F engine. The Winlink B2F protocol is implemented directly in Rust: CMS over telnet (TLS or plaintext), the full propose / accept message exchange, and on-disk mailbox persistence. No external modem daemon or sidecar process handles CMS.
- Telnet to CMS. Operator-to-CMS sessions over the internet for development, training, and fall-back when HF propagation is poor.
- AX.25 1200-baud packet. Connected-mode AX.25 over a KISS TNC: USB serial, Bluetooth RFCOMM, or KISS-over-TCP to a soundcard modem such as Dire Wolf. Inline radio panel with an SSID picker and a digipeater relay path.
- ARDOP HF (pictured). A complete panel for the ARDOP transport, driving a
local
ardopcfover its command and data sockets: Find a Gateway sorts RMS stations by distance from your grid; favorites and recent stations are saved per transport; ALSA capture/playback and the PTT serial line are picked inline; ARQ bandwidth is selectable; and a live quality meter, an ARDOP frame ribbon, and the session log track the link as it runs, freeze-free, with a working abort. - VARA HF, on-air validated; VARA FM supported. The VARA panel dials Winlink gateways end to end: it selects the ARQ bandwidth (500 / 2300 / 2750 Hz) to match the gateway channel's advertised width, takes the channel's published center frequency and dials the rig to the correct sideband spot over CAT, keys PTT on VARA's keying events, and runs the B2F exchange over the ARQ link, verified against a production VARA gateway at 500 Hz on real HF (see Maturity).
The ARDOP HF panel: Find a Gateway, the connect tabs, inline ALSA and PTT selectors, ARQ bandwidth, and the live quality meter.
VARA is Windows software, not a Linux-native modem, so Tuxlink resolves that with a guided installer rather than asking the operator to sort it out. A Set up VARA HF… flow, offered during the first-run wizard and any time from the panel, installs VARA under Wine on x86-64 Linux with a live checklist. The installer is built on wine-vara-setup, a vendored companion project that scripts the Wine prefix, the VARA download, and the registration steps end to end. Agents can drive the same setup, configuration, and dialing surface through the MCP server, behind the operator-armed gate.
ARM builds have no Wine target for VARA to run under, so ARM operators (Raspberry Pi and similar boards) run ARDOP natively instead, a modem Tuxlink drives directly with no Windows compatibility layer in the way. One first-run caveat applies to VARA regardless of architecture: the current release still requires a handful of manual audio and CAT provisioning steps outside the product (matching the VARA sound-card device to the right ALSA endpoints, confirming the CAT serial port, and similar one-time setup); automating that provisioning is tracked as open work.
The Set up VARA HF surface, with the guided installer hand-off above the VARA host and rig-control settings.
Routines automate repeatable radio tasks (a scheduled propagation check, a standing gateway connect and mail pull, a multi-step compose-and-send) as a flowchart the operator builds rather than a script the operator writes. A designer canvas assembles the steps, a dashboard shows what is scheduled and what last ran, and a run journal keeps the history. Schedule triggers are configured inside the same designer, as one of a routine's trigger kinds rather than a separate tab.
Part 97 consent is modeled directly into a routine, not bolted on afterward. An attended routine still pauses at each transmit step for a per-transmit confirmation, exactly like operating the radio panel by hand. An automatic routine may run a transmit step unattended, but only after the operator records an explicit, one-time acknowledgment at design time; a routine that would transmit automatically without that acknowledgment fails validation and cannot be enabled.
The Routines designer: a space-weather capture track on the canvas, the action palette, a step inspector, and the schedule and enable settings.
Elmer is the assistant docked in the Tuxlink shell. It is not a chat overlay answering questions from the sidelines; it operates the station through the same tool surface an external AI agent reaches over MCP, gated by the same operator-armed authorization the rest of this README describes. Ask it to work a multi-station connect loop under one arm window and it will dial, retry, and work through a list of QSY candidates in sequence; ask it a station-operation question and it searches and reads the built-in documentation corpus rather than guessing.
docs/ELMER.md is the full engineering-level writeup: architecture, the security model, what the agent can and cannot do, and its plainly stated limits.
Elmer answering a station question through its tool surface: it searches the built-in docs and reads VARA status before replying.
- APRS tactical chat. Per-callsign message threads over APRS on VHF and UHF with delivery-acknowledgement tracking, presented inline beside the address book. A fixed, mains-powered station carries local tactical traffic without draining a handheld.
- Native Benshi UV-Pro support. Tuxlink drives the Benshi UV-Pro handheld directly over Bluetooth, through its RFCOMM / GAIA control link, with no cable, no sound card, and no separate TNC. A control strip surfaces the radio, and the same Bluetooth link carries a KISS data path for APRS tactical chat, AX.25 packet, and Winlink. A modern handheld and a Linux machine make a complete strategic-and-tactical station.
- FULL and tactical identities. A licensed FULL identity for Winlink and tactical identities for local operation, managed under Settings → Identities.
Routines, the Tac Map, and APRS Chat can each pop out of the main window into their own OS window: the Tac Map on a side monitor while the mailbox stays in front, or a Routines dashboard left running in its own window during a net. Layouts persist across a full quit and relaunch, and closing a popped window's own close button never disturbs the mailbox; it puts the surface away quietly rather than discarding anything.
This is where the strategic and tactical layers show up together: an HF Winlink session runs in the main window, launched from the status-bar Connect control with saved session details, while a popped-out APRS Chat window carries live VHF tactical traffic on a second monitor. One operator works store-and-forward email on HF and real-time tactical chat on VHF at the same time, in windows arranged however the station is laid out.
Popping a window out costs memory (each is a separate WebKitGTK process); a dashboard-grade popped window runs in the ~30 MiB class on the reference hardware (Raspberry Pi 5, 16 GB, software GL), and a content-heavier surface such as the Tac Map, which carries its own tile cache, costs more on top of that base. A window's process exists only while it is popped out and is reclaimed the moment it docks back.
The main window, a popped-out Tac Map, and a popped-out APRS Chat window running at once: HF Winlink and VHF tactical operation in one workspace.
- Mailbox. Inbox, Outbox, Sent, Drafts, Archive, plus operator-created nested user folders. A selection-aware context menu performs bulk Archive and Move across multiple messages.
- Compose. New message, Reply, Reply All, and Forward. Cc is carried end to end through the native B2F path. Drafts auto-save to a local store keyed by a stable draft id and reopen exactly as left.
- Address book. Contacts and distribution groups with an inline editor. Recipient fields autocomplete from contacts and expand groups to their members at send time.
- HTML Forms, full Winlink Express catalog. The complete Winlink Express
Standard Forms snapshot (251 templates) ships built in. Compose or view any
catalog form through a hierarchical browser; native React composers cover the
highest-volume forms (ICS-213, Bulletin), and the long tail renders through
Tuxlink-skinned child webviews. Received form-tagged messages render their
viewer template inline. Drop a
.htmlfile into the custom-forms directory and it appears in the browser on next launch, for club-specific forms or templates released after the included snapshot. - Find Messages. Token-driven full-text search across folders
(
FOLDER:,FROM:,SUBJECT:,BEFORE:,AFTER:,UNREAD:,HAS:), plus saved and recent searches.
- Find a Gateway. A location-aware station finder polls Winlink RMS gateway lists by mode and sorts results by distance from the operator's grid square. Star a gateway to save it as a favorite; the radio panels surface saved favorites and recent connections per transport.
- Request Center. A request-first workspace resolves location-aware catalog requests (state and marine forecasts, propagation, solar-terrestrial, aurora, public gateway lists) from the operator's grid square, runs a catalog-wide search, and composes Saildocs GRIB requests. Selected items collect in a unified basket and dispatch per rail.
- Offline map. A position and station map renders from a configurable tile source, with tile-source provenance status and a validated-precision gate for fine zoom.
- GPS privacy controls. Position broadcast defaults to off. Operators may switch to local-display-only or broadcast at a chosen precision. The default reduces a broadcast position to a 4-character Maidenhead grid (about one degree). Higher precision is opt-in.
Tuxlink decodes NOAA/SWPC solar-terrestrial indices (the A-index, K-index,
and solar flux) directly from the WWV/WWVH voice broadcast, with no internet
path involved: the receiving radio's own audio is the only input. Because the
bulletin only airs at :18 and :45 past the hour, the control arms a one-shot
capture for the nearest window rather than listening continuously. A one-time
speech-to-text model fetch (scripts/fetch-stt-model.sh) is required before
the first decode; a genuinely air-gapped installation can copy the model file
across instead of fetching it live. This is a capability Winlink Express does
not have.
A receive-only FT8 listener renders a live waterfall, a decoded-call list, and a CAT-driven band strip for sweeping across the FT8 sub-bands. It exists as a propagation and band-openness instrument, not a message transport: nothing in the FT8 panel transmits, and no message ever routes through it. Watching which grids are decoding on a given band is a fast, receive-only read on whether HF is open before committing to a Winlink connect attempt.
The Station Intelligence panel: the propagation-colored gateway map beside a live decoded-call list, above the CAT-confirmed FT8 waterfall and raw decode feed.
- Native desktop GUI. Tauri 2.x with a React 18 + TypeScript frontend rendered by WebKitGTK 4.1. Custom title bar and native-style menu bar, a dashboard ribbon (callsign, grid, time, connection, Connect), the folder sidebar, the message list with search highlighting, the reading pane, and a mode-aware radio panel.
- Onboarding wizard. A first-run wizard takes a new operator from install to first message: callsign, grid, default transport, and an optional test send. It offers a CMS-connected path and an offline / radio-only path.
- Session log. A per-mode surface inside the radio panel renders both the human-readable projection of the CMS session and the raw B2F wire dialogue.
- Color schemes. Six included presets (Default dark, Daylight, High contrast light, Paper, Night / tactical red, Grayscale) plus an inline Theme Designer for custom palettes, for outdoor and bright-sun LCD readability.
- Diagnostic logging. Structured logging exports to a single
.tar.zstarchive via Help → Logging → Export logs, or attaches automatically through Help → Report Issue. Environment probes capture keyring, audio, serial, modem-process, network, and display state at startup and on errors. - OS keyring credentials. The OS keyring (secret-service on Linux) holds the Winlink CMS password. Tuxlink never persists it to a config file on disk.
Emergency operating happens in a tent at noon and an EOC at 3 a.m. Every color scheme re-skins the whole interface: ribbon, folders, message list, reading pane, not just an accent. Night / tactical (red) preserves night vision in a darkened shelter; Daylight is a light, high-contrast palette for reading an LCD in direct sun. The same mailbox, two lighting modes:
Tuxlink embeds a Model Context Protocol (MCP) server that exposes the running client to an AI agent (Claude, Codex, Gemini CLI, or any MCP-capable client) over a local Unix-domain socket. Elmer, the in-app assistant described above, reaches the identical tool surface in-process; an external agent and Elmer are two entry paths into one router, under one authorization model (see docs/ELMER.md for the architecture).
- Tiered tool surface. Diagnostic tools report backend, modem, position, configuration, and device state. Station-intelligence tools query the RMS gateway directory, predict HF path reliability by hour from the operator's grid square, and report space-weather indices. Further tools drive rig and modem control, compose and queue messages, and, only when authorized, connect to the CMS and transmit.
- Operator-armed egress. An agent cannot transmit, connect, or change configuration on its own. The operator arms send-authority in the GUI; egress and write tools are denied until armed, and the grant auto-expires. On-air transmission remains a per-invocation operator act under Part 97.
- Prompt-injection containment. Reading untrusted message or wire content taints the session and re-locks send-authority until the operator explicitly clears it. An instruction embedded in a received message cannot become a transmission within the same armed window.
- Curated knowledge and prompts. The server serves operator knowledge as MCP resources: a glossary, transport and device guides, and diagnostic playbooks, with guided prompts for common workflows and a read-first guide to the tool surface and the authorization model.
- Local-only transport. The server binds a Unix-domain socket in the user's
runtime directory, reached through the included
tuxlink-mcpstdio shim. It opens no network port.
Download the .deb, .rpm, or .AppImage for your distribution and
architecture (x86_64 or arm64, with SHA256SUMS) from the
latest release.
EmComm Tools Community (ECT) and Debian 12 Bookworm run an older system base
than the mainline packages target, so every release also publishes a dedicated
low-floor tuxlink_<version>_<arch>_ect.deb for them, identical to the mainline
build except that Apple HEIC image decoding is compiled out. Install it with
apt install ./tuxlink_*_ect.deb; details in
docs/install.md.
Install, first-run, uninstall, and build-from-source steps live in docs/install.md. Tuxlink requires WebKitGTK 4.1 and a secret-service keyring daemon.
The first-run wizard guides a new operator from install to first message, on a CMS-connected path or an offline / radio-only path. A guided tour with UI spotlighting follows the wizard for a new operator's first look at the running mailbox, and Elmer can re-trigger the same spotlight against any control on request:
The Request Center resolves location-aware catalog requests, searches the Winlink catalog, and collects selected items in a unified send basket:
Images are generated from the current frontend in WebKitGTK using privacy-safe sample data.
Where each path stands:
- On-air validated (RF path end-to-end): four modes are vetted on the air: AX.25 1200-baud packet, ARDOP HF, VARA HF, and APRS tactical chat over Bluetooth KISS. Packet, ARDOP, and VARA all connect over a real radio, and the transmit path to the Winlink network is proven end-to-end: a production Winlink CMS protocol response was received over the air, on both the packet and the VARA HF paths. That response was a rejection pending the client registration noted below, which is precisely what confirms the chain (transmit, RF link, gateway, CMS) is intact; the gap is an account, not a path. VARA HF's validation includes the hardest case: a 500 Hz-bandwidth ARQ link to a production gateway, with the full B2F handshake completed across the RF channel. Peer-to-peer sessions work on packet and ARDOP. APRS tactical chat has run continuously over a sustained Bluetooth KISS link at the same time as an HF Winlink session: the simultaneous HF/VHF workspace is functional. Transmission always requires explicit, per-invocation operator consent (see Amateur radio and Part 97).
- Validated (internet): native CMS connection over telnet and real Winlink message receive and render, against the Winlink CMS test server.
- Operator-pending (Part 97): APRS beacon transmit (own-position beaconing) is built and pending operator on-air verification; the APRS receive and chat paths and native UV-Pro Bluetooth control are vetted on the air (above). On-air validation of any new transmit path, including clean abort and de-key, is the operator's to perform.
- Production CMS registration: message exchange with the production Winlink CMS requires Winlink's prior registration of the Tuxlink client. The over-the-air rejection above confirms the RF path already reaches the production CMS; message exchange begins once registration completes. Until then, CMS message exchange targets the test server.
FT8 is receive-only by design. The listener has no transmit path, so there is nothing on that surface for on-air validation to prove; band-openness reading is the entire feature.
- Dockable surfaces and Routines. Multi-window pop-out and the Routines automation engine are built and covered by CI, including the consent-gating paths; field validation is pending at the next release cut.
- VARA peer-to-peer on the air. The VARA gateway-session path is on-air validated (above); direct station-to-station VARA sessions are built and awaiting on-air verification.
- USB rig autodetect. Rig control itself (CAT tune and PTT through the
included Hamlib
rigctld) is shipped and on-air proven; picking the radio automatically from the attached USB devices is not. - Native HF modem. VARA is x86 Windows software that runs under WINE on x86 Linux but not on ARM. Tuxlink targets a clean-room native HF modem (Sonde, developed as a separate project) rather than shipping VARA; VARA-TCP wire compatibility and the guided WINE setup serve operators who run VARA.
Tuxlink's desktop application lives in src-tauri/ (Tauri 2.x with a React 18 +
TypeScript frontend in src/ rendered by WebKitGTK 4.1). The Winlink engine, the
CMS connection, the B2F exchange, the mailbox, and the AX.25 packet path are
native Rust in src-tauri/; no external modem or sidecar process intervenes for
CMS. The desktop app ships as a single crate in the v0.x series, per
ADR 0002.
Sonde, the clean-room native HF modem, is developed as a separate clean-room project in its own repository (per ADR 0019). Tuxlink will consume it as an external modem backend; it is not yet wired into the desktop app's Winlink session lifecycle.
An embedded MCP server (Rust crates tuxlink-mcp-core for the tool surface and
tuxlink-security for the egress-authorization core) exposes the running client
to AI agents over a local Unix-domain socket. The same router serves Elmer,
the in-app assistant, over an in-process duplex connection, so the in-app and
external agent paths share one tool surface and one authorization gate rather
than two separate implementations. Agent transmit, connect, and
configuration-write actions pass through an operator-armed authorization gate;
neither path opens a network port. docs/ELMER.md documents
this architecture, the security model, and Elmer's capabilities in full.
CLAUDE.md documents the agent workflow, commit discipline, ethos, and safety rails this project operates under.
Tuxlink transmits under the operator's amateur radio callsign to real Winlink CMS gateways. CMS-connected features require a valid amateur radio license. The licensed operator bears responsibility for ensuring every transmission complies with Part 97 of the FCC rules, or the equivalent regulations in the operator's jurisdiction.
Tuxlink prohibits automated or agent-initiated transmissions absent explicit, per-invocation operator consent. Routines carry the same model forward: an attended routine pauses for that per-transmit consent at run time, and an automatic routine may only transmit unattended after the operator has recorded an explicit acknowledgment at design time. See docs/live-cms-testing-policy.md.
In-app documentation lives at Help → Documentation; built-in topics cover the
wizard, every transport, the mailbox, composing, HTML forms, operating modes,
search, settings, color schemes, keyboard shortcuts, troubleshooting, and AI agent
integration. The
source markdown resides in docs/user-guide/ for reading
outside the app. Help → About Tuxlink shows the running build's version,
license, and source-repository links.
GNU AGPL v3 or later. Copyright 2026 Cameron Zucker.
docs/development.md documents the build prerequisites, toolchain setup, and runtime keyring requirement. CLAUDE.md holds the agent workflow, commit discipline, and project ethos.










