Documentation Index Fetch the complete documentation index at: https://mintlify.com/nullclaw/nullclaw/llms.txt
Use this file to discover all available pages before exploring further.
NullClaw provides native hardware peripheral support for embedded boards, enabling AI-powered control of GPIO pins, sensors, actuators, and microcontroller flashing.
Overview
NullClaw’s hardware architecture:
Arduino Serial JSON protocol over USB
Raspberry Pi Direct GPIO access via sysfs
STM32/Nucleo Flash & debug via probe-rs
Supported Hardware
Arduino Boards
Serial: /dev/ttyACM0 or /dev/ttyUSB0
Baud: 9600
Protocol: JSON over serial
Serial: /dev/ttyACM0
Baud: 9600
More GPIO pins, same protocol
Serial: /dev/ttyUSB0
Baud: 115200
WiFi-capable (future support)
Raspberry Pi
All models with GPIO header (Zero, 3, 4, 5)
Direct GPIO via /sys/class/gpio
I2C, SPI support planned
Native Linux, no external tools
STM32/Nucleo Boards
STM32F4, STM32L4, STM32H7 series
Nucleo-F401RE, Nucleo-F411RE
Flash via probe-rs CLI
Debug via SWD/JTAG
NullClaw exposes hardware capabilities as tools:
Tool Description Boards hardware_infoList connected devices All hardware_memoryRead/write device memory STM32, Arduino i2cI2C bus communication RPi, Arduino spiSPI bus communication RPi, Arduino gpio_readRead GPIO pin state RPi, Arduino gpio_writeSet GPIO pin state RPi, Arduino flash_firmwareFlash firmware to MCU STM32, Arduino
Arduino Setup
Flash Arduino Sketch
Upload the serial JSON protocol sketch:
void setup () {
Serial . begin ( 9600 );
pinMode ( 13 , OUTPUT);
}
void loop () {
if ( Serial . available ()) {
String cmd = Serial . readStringUntil ( ' \n ' );
// Parse JSON: {"cmd":"gpio_write","pin":13,"value":1}
if ( cmd . indexOf ( "gpio_write" ) > 0 ) {
int pin = cmd . substring ( cmd . indexOf ( "pin" :) + 5 , cmd . indexOf ( "," )). toInt ();
int value = cmd . substring ( cmd . indexOf ( "value" :) + 7 , cmd . indexOf ( "}" )). toInt ();
digitalWrite (pin, value);
Serial . println ( "{ \" status \" : \" ok \" }" );
}
}
}
Full protocol implementation available in ~/.nullclaw/workspace/examples/arduino_bridge.ino
{
"peripherals" : {
"arduino" : {
"enabled" : true ,
"port" : "/dev/ttyACM0" ,
"baud" : 9600 ,
"timeout_ms" : 1000
}
},
"tools" : {
"hardware_info" : { "enabled" : true },
"i2c" : { "enabled" : true },
"gpio_read" : { "enabled" : true },
"gpio_write" : { "enabled" : true }
}
}
Find Serial Port
# Linux
ls /dev/ttyACM * /dev/ttyUSB *
# macOS
ls /dev/tty.usbmodem * /dev/cu.usbmodem *
# With dmesg (Linux)
dmesg | grep tty
Test Connection
# Check hardware
nullclaw hardware scan
# Get device info
nullclaw hardware info
# Test GPIO
nullclaw agent -m "Set Arduino pin 13 to HIGH"
Raspberry Pi Setup
Enable GPIO Access
# Add user to gpio group
sudo usermod -aG gpio $USER
# Reload groups
newgrp gpio
# Verify permissions
ls -l /sys/class/gpio/export
{
"peripherals" : {
"raspberry_pi" : {
"enabled" : true ,
"gpio_base" : "/sys/class/gpio"
}
},
"tools" : {
"gpio_read" : { "enabled" : true },
"gpio_write" : { "enabled" : true }
}
}
GPIO Pin Mapping
Raspberry Pi GPIO pins (BCM numbering):
Physical BCM Name 3 GPIO 2 SDA 5 GPIO 3 SCL 7 GPIO 4 GPCLK0 11 GPIO 17 GPIO_GEN0 13 GPIO 27 GPIO_GEN2 15 GPIO 22 GPIO_GEN3
Use BCM numbers in commands:
nullclaw agent -m "Set GPIO 17 to HIGH"
Example Usage
Read Pin
Write Pin
Blink LED
nullclaw agent -m "Read the state of GPIO pin 17"
STM32/Nucleo Setup
Install probe-rs
# Install probe-rs CLI
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-installer.sh | sh
# Verify installation
probe-rs --version
{
"peripherals" : {
"stm32" : {
"enabled" : true ,
"probe" : "auto" ,
"chip" : "STM32F401RETx"
}
},
"tools" : {
"hardware_memory" : { "enabled" : true },
"flash_firmware" : { "enabled" : true }
}
}
Flash Firmware
# Build firmware
zig build firmware
# Flash to board
nullclaw hardware flash --board nucleo-f401re --file zig-out/bin/firmware.bin
# Or via agent
nullclaw agent -m "Flash firmware.bin to the STM32 board"
Read/Write Memory
# Read memory address
nullclaw agent -m "Read memory at address 0x08000000"
# Write byte
nullclaw agent -m "Write value 0xFF to address 0x20000000"
Direct memory access can brick devices. Only use on development boards with recovery options.
Hardware Commands
Scan Devices
# List all connected hardware
nullclaw hardware scan
# Output:
# Found 3 devices:
# - Arduino Uno (/dev/ttyACM0)
# - STM32F401RE (probe: 0483:374b)
# - Raspberry Pi GPIO (native)
Device Info
# Get capabilities
nullclaw hardware info arduino
# Output:
# Board: Arduino Uno
# Type: arduino_uno
# GPIO Pins: D2-D13, A0-A5
# Flash: 32 KB
# Serial: Yes
# I2C: Yes
# SPI: Yes
Flash Firmware
# Arduino
nullclaw hardware flash --board arduino --port /dev/ttyACM0 --file sketch.hex
# STM32
nullclaw hardware flash --board stm32 --chip STM32F401RETx --file firmware.bin
Monitor Serial
# Watch serial output
nullclaw hardware monitor /dev/ttyACM0
# With baud rate
nullclaw hardware monitor /dev/ttyACM0 --baud 115200
I2C Communication
Read sensors via I2C bus:
{
"tools" : {
"i2c" : {
"enabled" : true ,
"bus" : "/dev/i2c-1" ,
"allowed_addresses" : [ "0x48" , "0x68" , "0x76" ]
}
}
}
Read I2C Device
# Scan I2C bus
nullclaw agent -m "Scan I2C bus 1 for devices"
# Read from device
nullclaw agent -m "Read temperature from I2C device at 0x48"
# Write to device
nullclaw agent -m "Write 0x01 to I2C device 0x68 register 0x6B"
Common I2C Sensors
Device Address Type BMP280 0x76 Temperature/Pressure MPU6050 0x68 Accelerometer/Gyro ADS1115 0x48 ADC SSD1306 0x3C OLED Display
SPI Communication
Communicate with SPI devices:
{
"tools" : {
"spi" : {
"enabled" : true ,
"bus" : "/dev/spidev0.0" ,
"max_speed_hz" : 1000000 ,
"mode" : 0
}
}
}
SPI Transfer
# Transfer data
nullclaw agent -m "Send [0x9F, 0x00, 0x00] via SPI and read response"
Security
Hardware access is restricted:
Serial Port Allowlist
Only specific paths allowed:
const allowed_serial_prefixes = [ _ ][] const u8 {
"/dev/ttyACM" ,
"/dev/ttyUSB" ,
"/dev/tty.usbmodem" ,
"/dev/cu.usbmodem" ,
"/dev/tty.usbserial" ,
"/dev/cu.usbserial" ,
};
Prevents access to system serial devices.
I2C Address Restrictions
{
"tools" : {
"i2c" : {
"allowed_addresses" : [ "0x48" , "0x68" ] // Specific devices only
}
}
}
Empty list denies all I2C access.
GPIO Pin Limits
{
"peripherals" : {
"raspberry_pi" : {
"allowed_pins" : [ 17 , 22 , 27 ] // Specific pins only
}
}
}
Memory Access Guards
STM32 memory access:
Read-only by default
Write requires explicit approval
Flash regions protected
System memory blocked
Troubleshooting
Device Not Found
# Check USB connections
lsusb
# Check serial ports
ls -l /dev/ttyACM * /dev/ttyUSB *
# Check permissions
groups # Should include 'dialout' or 'uucp'
# Add user to group
sudo usermod -aG dialout $USER
Permission Denied
# GPIO access
sudo chmod 666 /sys/class/gpio/export
sudo usermod -aG gpio $USER
# Serial access
sudo usermod -aG dialout $USER
# I2C access
sudo usermod -aG i2c $USER
Arduino Not Responding
Check serial protocol:
# Test with screen
screen /dev/ttyACM0 9600
# Send test command
{ "cmd" : "ping" }
# Should receive: {"status":"ok"}
STM32 Flash Failed
# Check probe connection
probe-rs list
# Verify chip
probe-rs info --chip STM32F401RETx
# Try recovery mode
probe-rs erase --chip STM32F401RETx
GPIO Pin Not Working
# Check if exported
ls /sys/class/gpio/gpio17
# Export manually
echo 17 > /sys/class/gpio/export
# Set direction
echo out > /sys/class/gpio/gpio17/direction
# Test
echo 1 > /sys/class/gpio/gpio17/value
Advanced Usage
Custom Peripheral
Implement custom hardware interface:
const Peripheral = @import ( "peripherals.zig" ). Peripheral ;
pub const CustomBoard = struct {
name_str : [] const u8 = "custom_board" ,
pub fn peripheral ( self : * CustomBoard ) Peripheral {
return .{
. ptr = @ptrCast ( self ),
. vtable = & vtable ,
};
}
const vtable = Peripheral . VTable {
. name = name ,
. board_type = boardType ,
. health_check = healthCheck ,
. init_peripheral = initPeripheral ,
. read = read ,
. write = write ,
. flash = flash ,
. capabilities = capabilities ,
};
fn name ( ptr : * anyopaque ) [] const u8 {
const self : * CustomBoard = @ptrCast ( @alignCast ( ptr ));
return self . name_str ;
}
// Implement other methods...
};
Multi-Board Setup
{
"peripherals" : {
"arduino_1" : {
"enabled" : true ,
"port" : "/dev/ttyACM0" ,
"alias" : "sensor_board"
},
"arduino_2" : {
"enabled" : true ,
"port" : "/dev/ttyACM1" ,
"alias" : "actuator_board"
},
"stm32" : {
"enabled" : true ,
"chip" : "STM32F401RETx" ,
"alias" : "control_board"
}
}
}
Reference by alias:
nullclaw agent -m "Read sensor from sensor_board"
nullclaw agent -m "Activate relay on actuator_board"
Next Steps
Sandboxing Secure hardware access with sandboxing
AI Providers Configure AI models for hardware control