name: serial-terminal description: Safely interact with serial ports (send/receive data). Use when the user needs to communicate with serial devices like Arduino, ESP32, or other microcontrollers. CRITICAL - Never read /dev/tty* devices directly. allowed-tools: Bash(python:*)
Serial Terminal Skill
Safely interact with serial ports without directly reading /dev/tty* devices (which would crash Claude Code).
CRITICAL SAFETY RULES
- NEVER read from
/dev/tty*devices directly usingcat,head,tail, or any other command - NEVER use the Read tool on
/dev/tty*files - ALWAYS use the Python wrapper script for ALL serial operations
Device Identification
IMPORTANT: Always use /dev/serial/by-id/ paths when available!
When multiple devices are connected, raw paths like /dev/ttyACM0 can change between reboots or when devices are reconnected. The /dev/serial/by-id/ directory provides stable, descriptive paths that include the device serial number.
Example /dev/serial/by-id/ entries:
/dev/serial/by-id/usb-SEGGER_J-Link_001057754341-if00 -> ../../ttyACM2
/dev/serial/by-id/usb-SEGGER_J-Link_001057754341-if02 -> ../../ttyACM3
When the user asks to connect to a device:
- First run
listto show available devices with their serial numbers - Ask the user which device/serial number they want to use if multiple are present
- Use the
/dev/serial/by-id/path for the connection
Available Commands
The script is located at ~/.claude/skills/serial-terminal/scripts/serial_terminal.py
List Available Ports
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py list
This will show devices from /dev/serial/by-id/ with their serial numbers, making it easy to identify which device is which.
Send Data
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py send <port> "<message>" [options]
Options:
--baud <rate>: Baud rate (default: 115200)--newline: Append newline to message (useful for command-line interfaces)
Example:
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py send "/dev/serial/by-id/usb-SEGGER_J-Link_001057754341-if02" "AT" --newline --baud 9600
Receive Data
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py receive <port> [options]
Options:
--baud <rate>: Baud rate (default: 115200)--timeout <secs>: How long to wait for data (default: 2.0)--bytes <n>: Max bytes to read (default: 4096)--hex: Display data as hex dump
Example:
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py receive "/dev/serial/by-id/usb-SEGGER_J-Link_001057754341-if02" --timeout 5 --baud 115200
Send and Receive (most common)
Send a command and wait for response in one operation:
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py sendrecv <port> "<message>" [options]
Example:
python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py sendrecv "/dev/serial/by-id/usb-SEGGER_J-Link_001057754341-if02" "help" --newline --timeout 3
Troubleshooting
Permission denied
The user may need to add themselves to the dialout group:
sudo usermod -a -G dialout $USER
# Then logout and login again
Or use sudo for a quick test:
sudo python3 ~/.claude/skills/serial-terminal/scripts/serial_terminal.py list
No response received
- Check baud rate matches the device
- Increase timeout with
--timeout - Verify the device is connected with
list - Try adding
--newlineif the device expects CR/LF
Device busy
Another program may have the port open. Close any serial monitors or other tools.
Script Details
The Python script uses only standard library modules:
os- Low-level file operationstermios- Serial port configurationselect- Non-blocking I/O (safe timeout handling)fcntl- File descriptor control
It safely handles serial I/O by:
- Using
select()to wait for data with timeout (never blocks indefinitely) - Setting non-blocking mode to prevent hangs
- Properly restoring terminal settings on exit