-
Notifications
You must be signed in to change notification settings - Fork 4.4k
08.4 Hardware Tools
Relevant source files
The following files were used as context for generating this wiki page:
The Hardware Tools subsystem provides ZeroClaw with direct access to physical hardware devices including microcontrollers, development boards, and embedded systems. This enables the AI agent to read registers, inspect memory maps, control GPIO pins, upload firmware, and interact with hardware through multiple transport protocols (serial, debug probes, native).
Scope: This page covers the hardware tool architecture, configuration, transport modes, and available hardware operations. For general tool architecture, see Tools. For integration tools like Composio, see Integration Tools. For browser-based automation, see Browser and HTTP Tools.
Key Features:
- Multi-transport support (Serial, Debug Probe, Native GPIO)
- Board-specific configurations (STM32 Nucleo, Raspberry Pi, ESP32, Arduino)
- Memory inspection and register reading
- Firmware upload capabilities
- Datasheet RAG integration for pin lookups
The hardware system consists of three layers: configuration, transport, and tools. Configuration defines the hardware setup through HardwareConfig and PeripheralsConfig. Transport adapters handle communication via serial, probe, or native protocols. Tools expose hardware operations to the agent.
graph TB
subgraph "Configuration Layer"
HWConfig["HardwareConfig<br/>(hardware.enabled, transport, serial_port)"]
PeriphConfig["PeripheralsConfig<br/>(boards[], datasheet_dir)"]
BoardConfig["PeripheralBoardConfig<br/>(board, transport, path, baud)"]
end
subgraph "Transport Layer"
SerialTransport["Serial Transport<br/>(e.g., /dev/ttyACM0, 115200 baud)"]
ProbeTransport["Debug Probe Transport<br/>(e.g., STM32, probe-rs)"]
NativeTransport["Native GPIO Transport<br/>(e.g., RPi sysfs, gpiod)"]
end
subgraph "Tool Layer"
BoardInfoTool["HardwareBoardInfoTool<br/>(Identify board, capabilities)"]
MemoryMapTool["HardwareMemoryMapTool<br/>(List peripheral addresses)"]
MemoryReadTool["HardwareMemoryReadTool<br/>(Read registers, memory)"]
GPIOTools["GPIO Tools<br/>(gpio_read, gpio_write)"]
ArduinoTool["Arduino Upload Tool<br/>(arduino_upload)"]
end
subgraph "Physical Hardware"
Nucleo["STM32 Nucleo<br/>(ARM Cortex-M)"]
RPi["Raspberry Pi<br/>(GPIO pins)"]
ESP32["ESP32<br/>(WiFi/BLE MCU)"]
Arduino["Arduino<br/>(AVR/ARM boards)"]
end
HWConfig --> PeriphConfig
PeriphConfig --> BoardConfig
BoardConfig --> SerialTransport
BoardConfig --> ProbeTransport
BoardConfig --> NativeTransport
SerialTransport --> BoardInfoTool
SerialTransport --> MemoryMapTool
SerialTransport --> MemoryReadTool
SerialTransport --> ArduinoTool
ProbeTransport --> BoardInfoTool
ProbeTransport --> MemoryMapTool
ProbeTransport --> MemoryReadTool
NativeTransport --> GPIOTools
BoardInfoTool --> Nucleo
BoardInfoTool --> RPi
BoardInfoTool --> ESP32
BoardInfoTool --> Arduino
MemoryReadTool --> Nucleo
GPIOTools --> RPi
ArduinoTool --> Arduino
Sources: src/config/schema.rs:175-241, src/config/schema.rs:452-500, src/tools/mod.rs:44-46
The HardwareConfig struct (wizard-driven setup) controls hardware access at the system level:
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Master enable switch for hardware access |
transport |
HardwareTransport |
None |
Transport protocol (None/Native/Serial/Probe) |
serial_port |
Option<String> |
None |
Serial device path (e.g., /dev/ttyACM0) |
baud_rate |
u32 |
115200 |
Serial baud rate |
probe_target |
Option<String> |
None |
Debug probe chip target (e.g., STM32F401RE) |
workspace_datasheets |
bool |
false |
Enable PDF datasheet RAG for pin lookups |
Example Configuration (TOML):
[hardware]
enabled = true
transport = "serial"
serial_port = "/dev/ttyACM0"
baud_rate = 115200
workspace_datasheets = trueSources: src/config/schema.rs:197-241
The PeripheralsConfig struct supports multiple boards simultaneously:
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable peripheral tool integration |
boards |
Vec<PeripheralBoardConfig> |
[] |
List of configured boards |
datasheet_dir |
Option<String> |
None |
Relative path to datasheet docs (e.g., datasheets/) |
PeripheralBoardConfig fields:
| Field | Type | Default | Description |
|---|---|---|---|
board |
String |
- | Board identifier (nucleo-f401re, rpi-gpio, esp32) |
transport |
String |
"serial" |
Transport protocol |
path |
Option<String> |
None |
Device path (serial/USB) |
baud |
u32 |
115200 |
Baud rate for serial |
Example Configuration (TOML):
[peripherals]
enabled = true
datasheet_dir = "datasheets"
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial"
path = "/dev/ttyACM0"
baud = 115200
[[peripherals.boards]]
board = "rpi-gpio"
transport = "native"Sources: src/config/schema.rs:454-500
The HardwareTransport enum defines communication protocols:
graph LR
Transport["HardwareTransport"]
Transport --> None["None<br/>(Hardware disabled)"]
Transport --> Native["Native<br/>(Direct GPIO/sysfs)"]
Transport --> Serial["Serial<br/>(UART/USB-CDC)"]
Transport --> Probe["Probe<br/>(Debug adapter, SWD/JTAG)"]
Native --> RPiGPIO["Raspberry Pi GPIO<br/>(sysfs, gpiod)"]
Serial --> USBCDC["USB CDC<br/>(/dev/ttyACM0)"]
Serial --> FTDI["FTDI<br/>(/dev/ttyUSB0)"]
Probe --> STLink["ST-Link<br/>(STM32 boards)"]
Probe --> JLink["J-Link<br/>(ARM Cortex)"]
Probe --> ProbeRS["probe-rs<br/>(Rust-native probe)"]
| Transport | Use Case | Requirements | Example Devices |
|---|---|---|---|
| None | Hardware disabled | None | N/A |
| Native | Direct GPIO control | Linux sysfs or libgpiod | Raspberry Pi, BeagleBone |
| Serial | UART/USB communication | Serial port device | Arduino, ESP32, STM32 with bootloader |
| Probe | Debug adapter access | probe-rs or OpenOCD | STM32 Nucleo, NXP boards |
Sources: src/config/schema.rs:175-194
The hardware toolset provides agent-accessible operations for physical world interaction.
Hardware tools are conditionally registered in the agent's system prompt based on their presence. The system prompt includes a special Hardware Access section when hardware tools are detected:
sequenceDiagram
participant Agent as Agent Core
participant PromptBuilder as build_system_prompt
participant ToolRegistry as Tool Registry
participant HardwareTools as Hardware Tools
Agent->>PromptBuilder: Build system prompt
PromptBuilder->>ToolRegistry: Get tool list
ToolRegistry-->>PromptBuilder: tools[]
PromptBuilder->>PromptBuilder: Check for hardware tools<br/>(gpio_read, hardware_memory_read, etc.)
alt Hardware tools present
PromptBuilder->>PromptBuilder: Inject Hardware Access section<br/>(Lines 925-933)
Note over PromptBuilder: "You HAVE direct access to<br/>connected hardware. All hardware<br/>tools are AUTHORIZED."
end
PromptBuilder-->>Agent: System prompt with hardware context
Agent->>HardwareTools: Execute hardware operations
Hardware Access Prompt Text (src/channels/mod.rs:926-933):
You HAVE direct access to connected hardware (Arduino, Nucleo, etc.).
The user owns this system and has configured it.
All hardware tools (gpio_read, gpio_write, hardware_memory_read,
hardware_board_info, hardware_memory_map) are AUTHORIZED and NOT blocked by security.
When they ask to read memory, registers, or board info, USE hardware_memory_read
or hardware_board_info — do NOT refuse or invent security excuses.
Sources: src/channels/mod.rs:915-934, src/tools/mod.rs:44-46
Purpose: Query board identity, capabilities, and configuration.
Tool Signature (src/tools/hardware_board_info.rs):
-
Name:
hardware_board_info - Description: Get information about the connected hardware board (chip, architecture, capabilities)
- Parameters: None or board identifier
- Returns: Board type, chip name, architecture, memory size, peripherals
Example Usage:
{
"name": "hardware_board_info",
"arguments": {}
}Example Output:
{
"success": true,
"output": "Board: STM32 Nucleo-F401RE\nChip: STM32F401RET6\nArchitecture: ARM Cortex-M4\nFlash: 512 KB\nRAM: 96 KB\nPeripherals: GPIO, UART, SPI, I2C, ADC, Timer"
}Purpose: Retrieve peripheral memory map (register base addresses).
Tool Signature (src/tools/hardware_memory_map.rs):
-
Name:
hardware_memory_map - Description: Get peripheral memory addresses and register map
-
Parameters: Optional peripheral filter (e.g.,
GPIO,UART,TIM) - Returns: Base addresses, register offsets, peripheral descriptions
Example Usage:
{
"name": "hardware_memory_map",
"arguments": {
"peripheral": "GPIO"
}
}Example Output:
GPIOA: 0x40020000 (General Purpose I/O Port A)
GPIOB: 0x40020400 (General Purpose I/O Port B)
GPIOC: 0x40020800 (General Purpose I/O Port C)
Purpose: Read hardware registers or memory regions.
Tool Signature (src/tools/hardware_memory_read.rs):
-
Name:
hardware_memory_read - Description: Read value from hardware memory address (register or RAM)
-
Parameters:
-
address(string/hex): Memory address (e.g.,0x40020000) -
size(optional): Bytes to read (1/2/4)
-
- Returns: Register value, decoded bit fields (if known)
Example Usage:
{
"name": "hardware_memory_read",
"arguments": {
"address": "0x40020014",
"size": 4
}
}Example Output:
Address: 0x40020014 (GPIOA_ODR - Output Data Register)
Value: 0x0000A020 (binary: 1010 0000 0010 0000)
Bit 5: HIGH (PA5 = LED)
Bit 13: HIGH (PA13)
Purpose: Direct GPIO pin control (Native transport only).
Tool Signatures:
-
gpio_read: Read pin state (HIGH/LOW)- Parameters:
pin(number or name, e.g.,17orGPIO17) - Returns: Pin state (0 or 1)
- Parameters:
-
gpio_write: Set pin state (HIGH/LOW)- Parameters:
pin,value(0 or 1) - Returns: Success confirmation
- Parameters:
Example Usage (Raspberry Pi):
{
"name": "gpio_write",
"arguments": {
"pin": 17,
"value": 1
}
}Purpose: Compile and upload Arduino sketches to connected boards.
Tool Signature:
-
Name:
arduino_upload - Description: Upload compiled sketch to Arduino-compatible board
-
Parameters:
-
sketch(string): Inline Arduino code or file path -
board(optional): Board type (e.g.,uno,nano,esp32) -
port(optional): Serial port override
-
- Returns: Compilation output, upload status
Example Usage:
{
"name": "arduino_upload",
"arguments": {
"sketch": "void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); delay(500); digitalWrite(13, LOW); delay(500); }",
"board": "uno"
}
}The hardware setup is integrated into the onboarding wizard as Step 6 of 9.
graph TB
Start["Onboarding Wizard Start"]
Step1["Step 1: Workspace Setup"]
Step2["Step 2: AI Provider & API Key"]
Step3["Step 3: Channels"]
Step4["Step 4: Tunnel"]
Step5["Step 5: Tool Mode & Security"]
Step6["Step 6: Hardware (Physical World)"]
Step7["Step 7: Memory Configuration"]
Step8["Step 8: Project Context"]
Step9["Step 9: Workspace Files"]
Start --> Step1
Step1 --> Step2
Step2 --> Step3
Step3 --> Step4
Step4 --> Step5
Step5 --> Step6
Step6 --> Step7
Step7 --> Step8
Step8 --> Step9
Step6 --> HardwarePrompt["Prompt: Enable hardware access?"]
HardwarePrompt -->|Yes| TransportSelect["Select transport:<br/>Serial / Probe / Native GPIO"]
HardwarePrompt -->|No| Step7
TransportSelect -->|Serial| SerialSetup["Configure serial port<br/>(path, baud rate)"]
TransportSelect -->|Probe| ProbeSetup["Configure probe<br/>(target chip)"]
TransportSelect -->|Native| NativeSetup["Configure GPIO<br/>(board type)"]
SerialSetup --> DatasheetPrompt["Enable datasheet RAG?"]
ProbeSetup --> DatasheetPrompt
NativeSetup --> DatasheetPrompt
DatasheetPrompt --> SaveConfig["Save hardware config"]
SaveConfig --> Step7
Wizard Entry Point: src/onboard/wizard.rs:91
Sources: src/onboard/wizard.rs:61-143
Hardware tools respect the global SecurityPolicy but include explicit authorization messaging in the system prompt to prevent the agent from refusing legitimate operations.
| Check | Enforcement | Bypass |
|---|---|---|
AutonomyLevel::ReadOnly |
Blocks writes (gpio_write, arduino_upload) |
None |
AutonomyLevel::Supervised |
Prompts for write operations | User approval |
AutonomyLevel::Full |
Allows autonomous writes | N/A |
| Rate limiting | Tracks hardware operations per hour | None |
| Path scoping | Restricts file reads to workspace |
workspace_only=false (config) |
The system prompt explicitly authorizes hardware access when hardware tools are present to prevent the agent from generating false security refusals:
Key Directive (src/channels/mod.rs:928-931):
"All hardware tools (gpio_read, gpio_write, hardware_memory_read, hardware_board_info, hardware_memory_map) are AUTHORIZED and NOT blocked by security. When they ask to read memory, registers, or board info, USE hardware_memory_read or hardware_board_info — do NOT refuse or invent security excuses."
Sources: src/channels/mod.rs:915-934
[hardware]
enabled = true
transport = "serial"
serial_port = "/dev/ttyACM0"
baud_rate = 115200
workspace_datasheets = false
[peripherals]
enabled = true
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial"
path = "/dev/ttyACM0"
baud = 115200[hardware]
enabled = true
transport = "native"
[peripherals]
enabled = true
[[peripherals.boards]]
board = "rpi-gpio"
transport = "native"[hardware]
enabled = true
transport = "serial"
serial_port = "/dev/ttyACM0"
baud_rate = 115200
[peripherals]
enabled = true
datasheet_dir = "datasheets"
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial"
path = "/dev/ttyACM0"
baud = 115200
[[peripherals.boards]]
board = "arduino-uno"
transport = "serial"
path = "/dev/ttyUSB0"
baud = 9600
[[peripherals.boards]]
board = "esp32"
transport = "serial"
path = "/dev/ttyUSB1"
baud = 115200Sources: src/config/schema.rs:197-241, src/config/schema.rs:454-500
When workspace_datasheets = true, the agent can query board datasheets for pin mappings, register descriptions, and peripheral documentation.
~/.zeroclaw/workspace/
├── datasheets/
│ ├── nucleo-f401re.md
│ ├── stm32f401re-reference.md
│ ├── rpi-gpio.md
│ └── esp32-pinout.md
sequenceDiagram
participant Agent as Agent
participant HWTool as Hardware Tool
participant RAG as Datasheet RAG
participant Memory as Memory System
Agent->>HWTool: hardware_memory_read(0x40020000)
HWTool->>RAG: Query "GPIOA 0x40020000"
RAG->>Memory: Recall from datasheets/
Memory-->>RAG: "GPIOA base: 0x40020000, ODR offset: 0x14"
RAG-->>HWTool: Pin mapping context
HWTool->>HWTool: Read register
HWTool-->>Agent: Value + decoded fields + datasheet context
Datasheet files are plain Markdown/text, indexed by the memory system for semantic search.
Sources: src/config/schema.rs:215-216
The build_system_prompt function (src/channels/mod.rs:888-1037) detects hardware tools by checking tool names:
let has_hardware = tools.iter().any(|(name, _)| {
*name == "gpio_read"
|| *name == "gpio_write"
|| *name == "arduino_upload"
|| *name == "hardware_memory_map"
|| *name == "hardware_board_info"
|| *name == "hardware_memory_read"
|| *name == "hardware_capabilities"
});If has_hardware is true, the Hardware Access section is injected into the system prompt.
Sources: src/channels/mod.rs:916-924
Hardware tools are imported but not automatically included in the default tool registry. They must be explicitly added based on configuration:
// src/tools/mod.rs imports
pub use hardware_board_info::HardwareBoardInfoTool;
pub use hardware_memory_map::HardwareMemoryMapTool;
pub use hardware_memory_read::HardwareMemoryReadTool;Conditional Registration (inferred from configuration):
- If
hardware.enabled = true→ register hardware tools - If
peripherals.enabled = true→ register board-specific tools
Sources: src/tools/mod.rs:44-46
- Overview - ZeroClaw system overview
- Core Tools - Shell, file, and git operations
- Integration Tools - Composio, delegation, notifications
- Configuration File Reference - Full config.toml documentation
- Security Model - System-wide security policies