# pms-infra-agent-serial
----
## β οΈ Caution
**Do not grant unrestricted control to AI.**
Unsupervised use or misuse may lead to unintended consequences.
All AI systems must remain strictly under human oversight and control.
Use responsibly, with full awareness and at your own risk.
----
## π Overview
**`pms-infra-agent-serial`** is a Haskell infrastructure library that provides AI agents with direct, low-level control over serial communication endpoints.
Unlike prompt-oriented serial abstractions, this library exposes raw serial I/O as both UTF-8 strings and byte-level hex strings. This allows agents to handle device-specific protocols, binary command frames, console sessions, and real-time serial monitoring with fine-grained control.
The library is a core component of the [`pty-mcp-server`](https://github.com/phoityne/pty-mcp-server) ecosystem and implements the `agent-serial-*` family of MCP tools.
---
## π§ Provided MCP Tools
### `agent-serial-open`
Opens a serial port connection for subsequent read/write operations.
Only one serial port connection can be active at a time.
- `device` β Serial device path (for example `/dev/ttyUSB0` or `COM3`)
- `commSpeed` β Baud rate (for example `9600` or `115200`; default: `9600`)
- `bitsPerWord` β Data bits (`5` to `8`; default: `8`)
- `stopb` β Stop bits (`1` or `2`; default: `1`)
- `parity` β Parity (`NoParity`, `Odd`, or `Even`; default: `NoParity`)
- `flowControl` β Flow control (`NoFlowControl` or `Software`; default: `NoFlowControl`)
- `timeout` β Read timeout in tenths of a second (default: `1`)
### `agent-serial-close`
Closes the active serial port connection and releases all associated resources.
### `agent-serial-read`
Reads up to the specified number of bytes from the active serial port and returns the data as a **UTF-8 string**.
Returns an empty string if no data is available before timeout.
- `size` β Maximum number of bytes to read
> β οΈ If the received data contains non-UTF-8 bytes or binary protocol frames, use `agent-serial-read-byte` instead.
### `agent-serial-read-byte`
Reads up to the specified number of bytes from the active serial port and returns the data as an **uppercase hex string** (e.g., `FF0A1B41`).
Use this for binary protocols or when precise byte-level inspection is required.
- `size` β Maximum number of bytes to read
### `agent-serial-write`
Writes the specified **UTF-8 string** to the active serial port.
- `data` β Text data to write
- `appendNewline` β When omitted or `true`, appends CR+LF automatically. When `false`, sends the string as-is.
> β οΈ To send exact byte sequences (for example binary frames, checksums, or explicit CR+LF bytes), use `agent-serial-write-byte`.
### `agent-serial-write-byte`
Decodes the specified **hex string** and writes the resulting bytes to the active serial port.
Use this for binary protocols or when precise byte-level control is required.
- `data` β Hex string to decode and write (e.g., `DEADBEEF0D0A`; uppercase and lowercase are accepted)
---
## π‘ Usage Notes
### Serial protocol handling
Prompt detection, command framing, response parsing, retries, checksums, and other protocol-specific behavior are the **responsibility of the agent**, not the library.
Use `agent-serial-read-byte` and `agent-serial-write-byte` when communicating with devices that require byte-accurate exchanges.
Example binary command flow:
```
β 010300000002C40B (Agent: write Modbus RTU request as bytes)
β 010304000A0014DA3E (Device: response read as bytes)
```
Example console flow:
```
β "login: " (Device prompt β read as UTF-8 string)
β "admin\r\n" (Username β send with appendNewline or exact bytes)
β "Password: " (Password prompt)
```
### Newline behavior
`agent-serial-write` appends CR+LF by default to support common serial-console workflows.
Set `appendNewline` to `false` when the target protocol requires exact text without automatic line endings.
### Read size limit
Read operations cap the requested size to the internal read buffer size.
For large outputs, poll repeatedly with `agent-serial-read` or `agent-serial-read-byte`.
---
## ποΈ Architecture
### Module Structure
```
PMS.Infra.Agent.Serial
βββ DM.Type -- Data type definitions (AppData, tool parameter types)
βββ DM.Constant -- Constants
βββ DS.Core -- Core domain service logic
βββ DS.Utility -- Utility functions (serial settings, hex decoding, AppContext helpers)
βββ App.Control -- Application control: tool dispatch and serial lifecycle management
```
### Key Design Points
- **Single active port**: Only one serial port can be open at a time per server instance. State is managed via `STM.TMVar`.
- **Configurable serial settings**: `agent-serial-open` supports baud rate, data bits, stop bits, parity, flow control, and read timeout.
- **Non-blocking reads**: Read operations return available data within the configured serial timeout, allowing the agent to poll at its own pace.
- **Byte-level I/F**: In addition to UTF-8 string I/F, hex string I/F is provided for binary protocol handling. Device protocol processing is delegated to the agent.
---
## π¦ Dependencies
- [`pms-domain-model`](https://github.com/phoityne/pms-domain-model)
- [`serialport`](https://hackage.haskell.org/package/serialport)
---
## π Credits & License
- **Execution & Process Lead:** Claude Sonnet 4.6, Gemini 3 Flash, GPT-5.5
- **Direction & Policy:** phoityne
- **License:** Apache-2.0 β see [LICENSE](./LICENSE)
---