A daemon and CLI that lets AI agents and humans share a single serial device. Race-free RPC, raw-mode shell, UDS or TCP, cross-platform.
Embedded development means a lot of staring at a serial console — kicking
a bootloader, reading kernel logs, exercising firmware against a corner
case. Increasingly an AI coding agent wants to do that staring too:
react to a stack trace, set a U-Boot env var, drive a board through a
regression suite. The naïve loop — agent describes a command in
chat → human copies it into tio → human pastes
the output back — is slow, brittle, and pointless.
Serial Tether's job is to hand that loop directly to the agent
without elbowing the human out. The daemon takes
ownership of /dev/ttyUSB0 once. From there, three audiences
share the same port at the same time:
Transactional, structured, bounded RPC. Race-free run,
ANSI- and echo-stripped output, standard exit codes,
configurable length truncation that protects LLM context budgets.
A tio-style raw-mode shell, plus tail to
watch every byte the agent sends or receives. No "agent mode" that
locks the operator out — the human gets a god's-eye view.
Shell-friendly exit codes (124 timeout, 7 unauthorized, 4 device gone, …), JSON output with a decoded text field. Same wire whether the daemon is local, behind SSH, or on a VM across the room.
Two humans in their own tether shells, attached to the same daemon
on a single serial port. Every byte the device emits is broadcast to every
session — screen -x for a U-Boot prompt.
Human in a tether shell on the left; on the right, a scripter
running one-shot tether run / ports / config
from another terminal. The scripter's commands echo live into the human's pane.
Same setup, but the right pane is an LLM/agent calling
tether --json run for transactional RPCs, plus a live
tether config --baud toward the end.
One tetherd process owns N serial ports. Clients address each by
an operator-chosen id (tether -d board0, tether -d board1),
with per-device baud / parity / etc. inline in -D. Each device
has its own ring buffer, writer lock, and event broadcast — traffic stays isolated.
All four paths give you the same two binaries: tetherd (daemon) and tether (client).
macOS or Linuxbrew — no Rust toolchain needed.
brew install hulryung/tether/serial-tether
Anywhere Rust runs.
cargo install serial-tether
Pre-built tar.xz, no dependencies.
curl -fsSL https://github.com/hulryung/serial-tether/releases/latest/download/serial-tether-installer.sh | sh
Clone and cargo build --release.
git clone https://github.com/hulryung/serial-tether
cd serial-tether
cargo build --workspace --release
Open one terminal for the daemon, another for the client.
# Terminal 1 — daemon owns the serial port
tetherd -D /dev/tty.usbserial-XXXX -b 115200 --tcp
# banner prints reachable IPs and an auto-generated auth token
# Terminal 2 — drop into a tio-style interactive shell
tether
# Ctrl-A then Q to quit
# Or, for an AI agent / shell script:
tether --json run "version" --newline crlf -u "ASAD SOC => " --literal --timeout-ms 3000
# Or, from a remote host (lima VM, CI runner, your laptop):
TETHER_AUTH_TOKEN=<token-from-banner> \
tether -s tcp://daemon-host:5557 status
If the daemon isn't running, tether tells you exactly how to
start one. Friendly errors all the way down.
run acquires a writer-lock at the daemon, captures the
ring-buffer head before the write, and matches starting
from there. No client-side composition of send +
expect.
consumer_cursor for matched RPC responses and
notify_cursor for live data push are
independent — a tail can watch while a run matches, no race.
Daemon retries the device with backoff if the USB hiccups; clients
can pass --auto-reconnect to retry their failed RPC
once after the daemon recovers.
Native TCP transport with token auth. Same wire format as UDS.
tetherd can listen on both at once.
socat- and nc-debuggable. No codegen, no
schema files. Per-request --log-protocol dump on the
daemon side.
--strip-ansi, --strip-echo,
--max-output-bytes 8192, exit codes you can branch on
in shell. JSON has a decoded output field — no base64.
Concepts, architecture, mental model, and design rationale. Read this first.
One-page command cookbook for AI agents — exit codes, JSON shape, race-free patterns, common pitfalls.
JSON-RPC 2.0 over NDJSON specification, v1 draft. Methods, notifications, error codes.
Five working Bash automation scripts: U-Boot bdinfo, set-and-verify env, parse help, wait for boot, detect shell.