A desktop serial/TCP workbench for inspecting frames, sending payloads, and automating device protocols.
Note
LinkDeck is pre-1.0. The workbench is usable, but configuration and scripting interfaces may still evolve.
LinkDeck is a native desktop application for people who debug serial devices and TCP protocols all day. Instead of treating traffic as an endless byte log, it turns each byte stream into complete frames, keeps capture and transmission together, and offers a built-in Lua and sequence automation path when manual poking is not enough.
- Frame-aware capture. Configure delimiter, fixed-size, length-prefix, or header/length/checksum framing. Half frames, sticky frames, oversize payloads, and checksum failures are handled before data reaches the UI.
- Serial and TCP in one workbench. Work with serial ports, TCP clients, TCP servers, and accepted connections using the same monitor, composer, and inspection model.
- A monitor built for signal. Filter by direction, switch between ASCII and HEX, search payloads, pause without losing capture, follow new traffic, and inspect complete frames with session statistics.
- Fast transmission. Send ASCII or HEX directly, choose line endings, recall history, and reuse saved Commands across channels.
- Lua when you need logic. Script against serial and TCP channels with
send_expect,expect, regex and Lua-pattern matching, pluslog,hex, andjsonhelpers. - Repeatable sequences. Build native send/delay/expect programs with repeat, interval, pause, resume, cancellation, and persisted definitions.
- Local-first configuration. Presets, favorites, Commands, and Sequences live in one predictable YAML document.
- Go 1.27.1 or newer
- Bun
- The native webview prerequisites for your platform; see the MyGo documentation
git clone https://github.com/scialpicoody/linkdeck.git
cd linkdeck
bun install
go mod download
bun run devbun run dev starts the native window and the Vite development server. For UI-only work, run bun run dev:web; browser mode has no Go host, so bindings and backend events are unavailable.
bun run buildPackaged output is written to build/. Use bun run build, not plain go build: the MyGo build embeds the compiled frontend into the application binary.
- Open Connect and choose serial, TCP client, or TCP server.
- Configure the endpoint and framing that match your device or protocol.
- Watch complete frames in the Monitor, then select a row to inspect its payload and session statistics.
- Use the operations dock to transmit a one-off payload, run a Sequence, or inspect captured frames.
- Switch to Scripts when a protocol exchange needs state, matching, or custom logic.
LinkDeck keeps channel identity, counters, and frame history when a device is unplugged or a TCP peer disconnects. Reconnect from the retained configuration instead of rebuilding the workspace.
Scripts use an embedded Lua runtime and can open serial or TCP connections directly. A typical request/response exchange looks like this:
local link = assert(serial.open("/dev/ttyUSB0", {
baudrate = 115200,
timeout_ms = 1000,
}))
local reply = assert(send_expect(link, "AT\r", "OK", {
mode = "prefix",
timeout_ms = 1000,
}))
log(hex.encode(reply))
serial.close(link)The scripting surface includes:
serial.open,serial.send,serial.recv, andserial.closetcp.open,tcp.listen,tcp.accept,tcp.send,tcp.recv, andtcp.close- Top-level
send_expectandexpectwithprefix,regex, andpatternmodes log,hex.encode/hex.decode, andjson.encode/json.decode- Short source runs, saved-file runs, and long-lived sessions with function calls and auto-reload
Execution is serialized per Lua state. Runs have configurable timeouts, and blocking matcher callbacks are cancellation-aware.
LinkDeck reads the first existing YAML file from this order:
| Priority | Location |
|---|---|
| 1 | The path in LINKDECK_CONFIG |
| 2 | config.yaml beside the executable |
| 3 | The per-user configuration directory |
Per-user locations:
- macOS:
~/Library/Application Support/linkdeck/config.yaml - Linux:
~/.config/linkdeck/config.yaml - Windows:
%AppData%\linkdeck\config.yaml
The selected file is authoritative; settings are not merged across layers. A missing file uses built-in defaults, and writes are atomic.
See resources/config.example.yaml for a complete annotated example covering channel presets, script favorites, Commands, and Sequences.
LinkDeck combines a Go application host with a React and TypeScript workbench:
serial / TCP transport
|
v
frame extraction
|
v
matcher-first script pool
|
v
stream queue and status snapshots
|
v
mygo events and generated bindings
|
v
React workbench
The transport, stream, scripting, automation, and frontend layers have separate responsibilities. Framing and codec code remain pure libraries, and the automation engine depends on a small sender interface rather than transport drivers.
| Path | Responsibility |
|---|---|
main.go |
MyGo app lifecycle, service bindings, events, and window setup |
internal/serial, internal/tcp |
Transport drivers and connection lifecycles |
internal/framing |
Delimiter, fixed-size, length-prefix, and checksum framing |
internal/stream |
Per-channel read loops, batching, backpressure, and reset behavior |
internal/script |
Lua runtime, sessions, matchers, and opaque channel handles |
internal/automation |
Native send/delay/expect execution, timing, and cancellation |
internal/link |
Adapters from transport services to script and automation contracts |
src/ |
React workbench, capture stores, panels, and generated bindings |
docs/ |
Product design, ADRs, configuration, and primary-source research |
| Task | Command |
|---|---|
| Start the desktop app | bun run dev |
| Start browser-only UI | bun run dev:web |
| Regenerate Go-to-TypeScript bindings | bun run generate |
| Build the packaged app | bun run build |
| Lint and format checks | bun run check |
| TypeScript checks | bun run typecheck |
| Frontend tests | bun run test |
| Dead-code checks | bun run knip |
| All Go tests | go test ./... |
Run a focused Go test with go test ./internal/framing -run TestDelimiterHalfFrames. Run a focused frontend test with bunx vitest run src/lib/channels.test.ts.
src/mygo.ts is generated. Never edit it by hand; change the Go API and run bun run generate.
Before opening a pull request, run:
bun run check
bun run typecheck
bun run test
bun run knip
go test ./...- Workbench design
- Configuration
- Send and automation design
- Visual language ADR
- Domain vocabulary
- Agent and contributor guidance
Issues and pull requests are welcome. Open an issue before making substantial changes to the public API, information architecture, or visual language. Use the vocabulary in CONTEXT.md, check relevant ADRs and design docs, and include verification details in pull requests.
No license has been declared yet. The source is publicly viewable, but no reuse license is currently granted.