Skip to content

08.4 Hardware Tools

Nikolay Vyahhi edited this page Feb 19, 2026 · 3 revisions

Hardware Tools

Relevant source files

The following files were used as context for generating this wiki page:

Overview

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

Hardware Architecture Overview

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
Loading

Sources: src/config/schema.rs:175-241, src/config/schema.rs:452-500, src/tools/mod.rs:44-46


Configuration System

HardwareConfig

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 = true

Sources: src/config/schema.rs:197-241


PeripheralsConfig

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


Hardware Transport Modes

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)"]
Loading

Transport Selection Logic

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


Hardware Tools

The hardware toolset provides agent-accessible operations for physical world interaction.

Tool Registration and System Prompt Integration

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
Loading

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


Available Hardware Tools

1. hardware_board_info

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"
}

2. hardware_memory_map

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)

3. hardware_memory_read

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)

4. GPIO Tools (gpio_read, gpio_write)

Purpose: Direct GPIO pin control (Native transport only).

Tool Signatures:

  • gpio_read: Read pin state (HIGH/LOW)

    • Parameters: pin (number or name, e.g., 17 or GPIO17)
    • Returns: Pin state (0 or 1)
  • gpio_write: Set pin state (HIGH/LOW)

    • Parameters: pin, value (0 or 1)
    • Returns: Success confirmation

Example Usage (Raspberry Pi):

{
  "name": "gpio_write",
  "arguments": {
    "pin": 17,
    "value": 1
  }
}

5. arduino_upload

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"
  }
}

Onboarding Integration

The hardware setup is integrated into the onboarding wizard as Step 6 of 9.

Wizard Flow

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
Loading

Wizard Entry Point: src/onboard/wizard.rs:91

Sources: src/onboard/wizard.rs:61-143


Hardware Security Model

Hardware tools respect the global SecurityPolicy but include explicit authorization messaging in the system prompt to prevent the agent from refusing legitimate operations.

Security Checks

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)

System Prompt Authorization

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


Configuration Examples

Example 1: STM32 Nucleo via Serial

[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

Example 2: Raspberry Pi GPIO (Native)

[hardware]
enabled = true
transport = "native"

[peripherals]
enabled = true

[[peripherals.boards]]
board = "rpi-gpio"
transport = "native"

Example 3: Multi-Board Setup

[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 = 115200

Sources: src/config/schema.rs:197-241, src/config/schema.rs:454-500


Datasheet RAG Integration

When workspace_datasheets = true, the agent can query board datasheets for pin mappings, register descriptions, and peripheral documentation.

Datasheet Directory Structure

~/.zeroclaw/workspace/
├── datasheets/
│   ├── nucleo-f401re.md
│   ├── stm32f401re-reference.md
│   ├── rpi-gpio.md
│   └── esp32-pinout.md

RAG Query Flow

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
Loading

Datasheet files are plain Markdown/text, indexed by the memory system for semantic search.

Sources: src/config/schema.rs:215-216


Implementation Notes

Tool Detection Logic

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


Tool Registry

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


Related Pages


Clone this wiki locally