Content
# UARTBuddy
<p align="center">
<img src="rust_app/assets/uartbuddy-icon.png" width="128" alt="UARTBuddy icon">
</p>
<p align="center">
<strong>Enables safe sharing of a physical serial port between humans and AI agents.</strong>
</p>
<p align="center">
<a href="https://github.com/llinzzi/UARTBuddy/releases/latest"><img alt="GitHub release" src="https://img.shields.io/github/v/release/llinzzi/UARTBuddy?include_prereleases"></a>
<img alt="macOS 12+" src="https://img.shields.io/badge/macOS-12%2B-000000?logo=apple">
<img alt="Apple Silicon" src="https://img.shields.io/badge/Apple%20Silicon-arm64-4385F4">
<img alt="Rust" src="https://img.shields.io/badge/Rust-egui-EA4335?logo=rust">
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-34A853"></a>
</p>
UARTBuddy is a macOS serial port debugger written in Rust + egui. It exclusively owns the physical serial port and shares it with AI agents like Codex and Claude Code through the local MCP server.
> Current version: `v0.5.0` · Apple Silicon · macOS 12+
## Problem Statement
In embedded system debugging, the real challenge is not just "opening the serial port," but enabling multiple participants to share the same session.
### 1. Physical serial ports can only be reliably occupied by one process
GUI serial assistants, flashing tools, and AI agents cannot share the same port without conflicts, data corruption, or interrupted flashing.
### 2. Human-readable logs are not accessible to AI agents
Traditional serial assistants display logs in the GUI, but AI agents cannot incrementally read them. When the serial port is handed over to a command-line tool, humans lose the visual interface and manual sending capabilities.
### 3. Critical failures can be lost in the log stream
Device restarts, intermittent I²C errors, or crash logs may be overwritten before they can be examined.
### 4. Flashing tools are often duplicated and not worth reimplementing
Existing flashing tools for ESP32, STM32, and other chips are mature and widely available. The goal is to solve serial port sharing, command scheduling, real-time output, and connection recovery.
## UARTBuddy's Approach
UARTBuddy lets a single Serial Broker exclusively own the physical serial port:
```mermaid
flowchart LR
Device["Embedded Device"] <--> Port["Physical Serial Port"]
Port <--> Broker["UARTBuddy Serial Broker"]
Broker <--> GUI["Human GUI"]
Broker <--> MCP["Local MCP :8765"]
MCP <--> Agent["Codex / Claude Code"]
Broker --> History["JSONL Persistent History"]
MCP --> Flash["espflash / esptool / stm32flash"]
Flash -. "Release before flashing, recover after" .-> Port
```
- GUI and agents read the same log stream without contending for the serial port.
- GUI sends are displayed as `TX`, while MCP sends are displayed as `MCP TX`.
- MCP client connections, tool invocations, successes, and errors are displayed as independent events.
- Flashing tool stdout/stderr is streamed into the terminal in real-time.
## Key Features
- Native light GUI with serial port scanning, connection, and parameter configuration
- UTF-8 and HEX display and sending with optional LF appending
- Millisecond timestamps and visual grouping of RX, TX, MCP, and system events
- "Copy All" and history session selection with full details view
- Built-in Streamable HTTP MCP with default local server
- 13 MCP tools for serial port, flashing, and history management
- Automatic discovery of `espflash`, `esptool`, and `stm32flash`
- User-configurable flashing adapters with restricted MCP execution
- Flashing tool stdout/stderr streaming and exit status display
## Preview
### Serial Terminal and MCP Events

Human sends, device outputs, MCP calls, and flashing processes are displayed in a unified timeline with color-coded event labels.
### MCP Connection and Flashing Environment

In-app configuration for Codex and Claude Code MCP connections, as well as local flashing tool scanning.
## Quick Start
### Download
Download from [Releases](https://github.com/llinzzi/UARTBuddy/releases):
- `UARTBuddy-0.5.0-arm64.dmg`: macOS installer
- `UARTBuddy-0.5.0-arm64.zip`: self-contained app package
Open the DMG, drag `UARTBuddy.app` to the Applications folder, and launch it.
### Connect Serial Port
1. Select the `/dev/cu.*` device.
2. Configure baud rate, data bits, parity, stop bits, and flow control.
3. Click "Connect Serial Port".
4. Send text or HEX data from the bottom input field.
5. View previous connection sessions by clicking "History".
## Connect AI Agent
UARTBuddy listens on `http://127.0.0.1:8765/mcp` by default.
### Codex
Add the following configuration to `~/.codex/config.toml`:
```toml
[mcp_servers.uart_buddy]
url = "http://127.0.0.1:8765/mcp"
required = false
default_tools_approval_mode = "writes"
startup_timeout_sec = 3
tool_timeout_sec = 30
```
Restart Codex or add the MCP server through the Codex settings.
### Claude Code
```bash
claude mcp add --transport http --scope user uart_buddy http://127.0.0.1:8765/mcp
```
Verify the connection:
```bash
claude mcp get uart_buddy
```
## Usage Examples
```text
List available serial ports.
Connect to /dev/cu.usbmodem1301 at 115200 bps.
Read the last 200 device logs and find recurring I2C errors.
Send "help" with LF to the device.
Scan the local flashing environment.
Flash firmware.bin to the current ESP32 using esptool.
```
## MCP Tools
| Tool | Type | Description |
| --- | --- | --- |
| `serial_list_ports` | Read-only | List available serial ports |
| `serial_status` | Read-only | Query connection parameters and log cursor |
| `serial_read_logs` | Read-only | Incrementally read RX, TX, MCP TX, and system logs |
| `serial_connect` | Write | Connect to a specified serial port |
| `serial_disconnect` | Write | Disconnect from the current serial port |
| `serial_send` | Write | Send UTF-8 or HEX data |
| `serial_flash_scan` | Read-only | Scan the flashing environment |
| `serial_flash_status` | Read-only | Query flashing status and tool output |
| `serial_flash` | Write | Schedule a discovered flashing adapter |
| `serial_flash_cancel` | Write | Cancel flashing and recover the serial port |
| `serial_history_list` | Read-only | List persistent sessions |
| `serial_history_read` | Read-only | Read a full history page |
| `serial_history_delete` | Write | Delete a completed history session |
## Flashing Environment
UARTBuddy does not reimplement chip flashing protocols; instead, it schedules installed tools:
| Adapter | Default Tool | Firmware Format |
| --- | --- | --- |
| ESP Rust | `espflash` | `.bin` |
| Espressif | `esptool` / `esptool.py` | `.bin` |
| STM32 UART Bootloader | `stm32flash` | `.bin`, `.hex` |
The environment scan combines the login shell environment and checks common directories.
## History and Logging
Each serial port connection creates an independent session. Logs are appended to a JSONL file:
```text
~/Library/Application Support/UARTBuddy/history/
```
The in-app terminal retains the last 5,000 lines for smooth rendering, while disk history is unlimited.
## Security Boundaries
- MCP is bound to `127.0.0.1:8765`.
- UARTBuddy exclusively owns the physical serial port.
- Flashing is restricted to discovered and whitelisted tools.
- Flashing commands are executed directly without shell interpolation.
## Building from Source
Requires Rust toolchain and macOS 12+.
Run the development version:
```bash
cd rust_app
cargo run --release
```
Check code:
```bash
cd rust_app
cargo fmt --check
cargo test
cargo clippy -- -D warnings
```
Build the standalone app and DMG:
```bash
./scripts/build_macos.sh
```
Output:
```text
dist/
├── UARTBuddy.app
└── UARTBuddy-0.5.0-arm64.dmg
```
## Project Structure
```text
rust_app/
├── assets/uartbuddy-icon.png
└── src/
├── main.rs # Native app entry
├── app.rs # egui GUI
├── broker.rs # Serial port owner and event stream
├── history.rs # JSONL persistent history
├── flash.rs # Flashing adapters and environment scan
├── mcp.rs # Streamable HTTP MCP
└── model.rs
```
## Limitations
- Currently only Apple Silicon builds are available.
- No code signing or notarization.
## Roadmap
- Log search, filtering, and export
- History session filtering and batch management
- Additional verified serial port flashing adapters
- Universal 2 / Intel Mac builds
- Developer ID signing and Apple notarization
## Contributing
Submit issues and pull requests. Run:
```bash
cd rust_app
cargo fmt --check
cargo test
cargo clippy -- -D warnings
```
For changes involving physical hardware, please specify the device model, serial port parameters, flashing tool version, and verification results in the PR.