Skip to content

Repository files navigation

UARTBuddy

UARTBuddy icon

A multi-device embedded debugging workspace shared by humans and AI agents.

English | 简体中文

GitHub release macOS 12+ Apple Silicon Rust + egui MIT License

UARTBuddy owns physical serial ports once, then lets the GUI and local MCP clients share the same connections, event stream, history, flashing jobs, and USB camera. Version 1.0 is designed around multiple embedded devices: every device has an independent actor, connection, configuration, session, counters, and flash reservation.

Current version: v1.0.0 · Apple Silicon · macOS 12+

The problems it solves

One physical port should have one owner

Serial monitors, flashing tools, and AI agents cannot reliably open the same /dev/cu.* endpoint at the same time. Competing readers lose bytes and competing writers interleave commands. UARTBuddy is the single owner and exposes deliberate operations to every participant.

A project usually has more than one device

Real systems have controllers, sensors, motor drivers, test fixtures, and multiple prototypes. UARTBuddy keeps them connected concurrently. Selecting All devices produces a merged, color-coded event stream; selecting one device gives focused controls and logs. Normal UI sends always target one device. Multi-device writes require an explicit MCP call.

Agents need bounded, resumable context

Dumping a terminal buffer into an agent is slow and can overflow its context. UARTBuddy stores events in SQLite and exposes a global monotonic event_id. Reads apply device/type/session filters inside SQLite before a strict limit. events_wait blocks until matching events arrive, so an agent does not need a polling loop.

Flashing should not stop unrelated devices

UARTBuddy does not reimplement ESP32, STM32, or other vendor protocols. It discovers installed tools such as espflash, esptool, and stm32flash. A flash job reserves and releases only its target device, streams progress as events, supports cancellation and completion waiting, then restores that device's previous connection. Every other serial actor stays online. Each started flash is also recorded in SQLite with its time, absolute firmware path, byte size, MD5 fingerprint, version metadata, provider, target device, and final state.

Logs do not show the physical scene

The shared camera workspace gives both the GUI and MCP clients controlled photo and recording operations while serial devices continue running.

Architecture

flowchart LR
    D1["Device A"] <--> A1["Serial actor A"]
    D2["Device B"] <--> A2["Serial actor B"]
    DN["Device N"] <--> AN["Serial actor N"]
    A1 & A2 & AN --> E["Global event stream"]
    E --> DB["SQLite WAL store"]
    E <--> GUI["egui workspace"]
    E <--> MCP["Stateless MCP :8765"]
    MCP <--> Agent["Codex / Claude Code"]
    MCP --> Jobs["Flash job registry"]
    Jobs -. "reserve target only" .-> A1
    Camera["USB camera"] <--> GUI
    Camera <--> MCP
Loading
  • One worker actor owns each physical serial handle.
  • USB serial numbers provide stable endpoint identities across path changes.
  • Auto-reconnect resolves the current path from the stable identity.
  • Connection, RX/TX, MCP calls, flashing, errors, and completion are all events.
  • SQLite WAL provides durable history while the GUI and agents read concurrently.
  • The MCP service is localhost-only and starts with UARTBuddy.

Screenshots

Serial monitoring and agent-driven flashing

UARTBuddy serial terminal and MCP flashing

USB camera

UARTBuddy USB camera

MCP service

UARTBuddy MCP service

Features

  • Concurrent serial connections with native Apple Color Emoji icons, aliases, configuration, and state
  • Combined or focused event views with device badges, text/HEX display, and strict send targets
  • Persistent SQLite sessions containing RX, TX, system, MCP, and flash events
  • In-page history browser instead of a blocking modal
  • UTF-8, HEX, and Base64 MCP writes; explicit multi-write and request/response exchange
  • Strict cursor pagination and long event waits
  • Background flash jobs with progress, completion events, wait, and cancellation
  • Durable flash history with firmware path, size, MD5, version source, and final state
  • Target-only serial release during flashing
  • espflash, esptool, stm32flash, and custom provider discovery from the environment
  • USB camera discovery, live preview, JPEG capture, and MP4 recording
  • English and Simplified Chinese UI selected from macOS; English is the fallback

Install

Download the latest .dmg or .zip from GitHub Releases.

The package is currently built for Apple Silicon and ad-hoc signed. Video features require ffmpeg; serial and MCP serial features do not:

brew install ffmpeg

UARTBuddy scans FFMPEG_PATH, the login-shell environment, Homebrew, MacPorts, and common paths.

First run

  1. Open UARTBuddy and click + in the device rail.
  2. Choose a scanned endpoint, give it a meaningful alias, and set its serial parameters.
  3. Add every device used by the project.
  4. Connect devices independently, or enable auto-reconnect.
  5. Select All devices for a combined stream or one device for focused sending and history.

The compact device rail is Emoji-only, with Add at the top. Default icons are randomly assigned without repetition while the built-in pool has unused choices. Selection and connection/flashing state remain visible through each icon border.

The device profile stores a stable identity when the USB adapter exposes a serial number. A renamed /dev/cu.* path can therefore be rediscovered after unplugging and reconnecting it.

Connect an AI agent

UARTBuddy starts a stateless Streamable HTTP endpoint by default:

http://127.0.0.1:8765/mcp

Codex

Add this to ~/.codex/config.toml, then restart Codex:

[mcp_servers.uartbuddy]
url = "http://127.0.0.1:8765/mcp"
required = false
default_tools_approval_mode = "writes"
startup_timeout_sec = 3
tool_timeout_sec = 125

Claude Code

claude mcp add --transport http --scope user uartbuddy http://127.0.0.1:8765/mcp
claude mcp get uartbuddy

MCP v1 tools

UARTBuddy exposes 30 tools. All mutating serial and flashing operations require an explicit device_id; there is no implicit "current port" in MCP v1.

Area Tools
Device lifecycle endpoints_scan, devices_list, device_attach, device_update, device_remove, device_connect, device_disconnect
Serial data serial_write, serial_write_many, serial_exchange, serial_set_signals
Events and history events_read, events_wait, sessions_list, session_read
Flash jobs flashers_list, flash_start, flash_history_list, firmware_library_list, firmware_reflash, jobs_get, jobs_wait, jobs_cancel
Video video_list_devices, video_status, video_connect, video_disconnect, video_capture, video_record_start, video_record_stop

Event cursor pattern

  1. Call devices_list and retain latest_event_id.
  2. Perform a targeted operation.
  3. Call events_wait with after_event_id, device/type filters, and a timeout.
  4. Continue with the returned next_event_id.

limit is enforced after SQL filters and is capped at 2,000 events. The response always includes next_event_id and latest_event_id.

Exchange pattern

serial_exchange writes to one device and collects serial.rx events until one of these occurs:

  • the optional until text appears;
  • data has been idle for idle_ms; or
  • timeout_ms expires.

Flash pattern

  1. Call flashers_list.
  2. Call flash_start with device_id, provider_id, and an absolute firmware path.
  3. Call jobs_wait once, or watch flash.progress and flash.completed/flash.failed events with events_wait.

flash_start accepts an optional authoritative version. Without it, UARTBuddy first reads an ESP-IDF application descriptor, then checks firmware.bin.json/firmware.json, and finally tries a version-like filename suffix. Unknown versions remain empty instead of being guessed. Use flash_history_list to retrieve the durable records, optionally filtered by device_id.

For recognized ESP-IDF application images, UARTBuddy also records the ESP-IDF version, target chip, image-declared Flash capacity, project name, build time, Secure Version, Flash mode/frequency, and ELF SHA-256. The declared capacity comes from the image header and is not presented as a physical probe of the connected chip.

Before a flash starts, UARTBuddy copies the exact image into its content-addressed firmware library. Images are deduplicated by MD5 and remain available if the original source is moved or deleted. The Firmware tab can flash the latest device/tool configuration again with one click; MCP clients can use firmware_library_list and the explicit-target firmware_reflash tool.

Data locations

~/Library/Application Support/UARTBuddy/
├── uartbuddy-v1.sqlite3
├── uartbuddy-v1.sqlite3-wal
├── uartbuddy-v1.sqlite3-shm
├── uartbuddy.lock
└── video/
    ├── photos/
    └── recordings/

Version 1.0 intentionally does not import the pre-1.0 JSONL broker history. It uses a new device and event model with a separate SQLite database.

Custom flash providers

UARTBuddy scans the login-shell environment and common SDK locations. Additional providers can be defined in ~/.uartbuddy/flash-providers.json or paths listed by UARTBUDDY_FLASH_CONFIG. UARTBuddy invokes executables directly without a shell and substitutes {port}, {baud}, {firmware}, and {address} in the declared argument list.

Build from source

Requirements: Rust stable, macOS 12+, and optionally ffmpeg.

git clone https://github.com/llinzzi/UARTBuddy.git
cd UARTBuddy
cargo run --manifest-path rust_app/Cargo.toml

Build the signed local app bundle, DMG, and ZIP:

./scripts/build_macos.sh

Artifacts are written to dist/ and derive their version from rust_app/Cargo.toml.

Development checks

cd rust_app
cargo fmt --check
cargo test
cargo clippy -- -D warnings

Current limitations

  • Release packages target Apple Silicon and are not notarized yet.
  • Camera preview is fixed at 640×480; recordings do not include audio.
  • Full-text event search and export are not implemented yet.
  • UARTBuddy must remain the sole OS-level owner of every attached serial endpoint.

Contributing

Issues and pull requests are welcome. Hardware reports should include the board or adapter model, stable USB identity if available, serial parameters, relevant event IDs, and reproduction steps.

License

MIT

About

Native macOS serial terminal and MCP bridge for humans and AI agents

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages