> ## 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.

# Tools

> Agent tool execution via vtable interface

## Overview

Tools are NullClaw's capability layer for LLM function calling. Every tool implements the `Tool` vtable interface, enabling the agent to execute system commands, file I/O, API calls, and hardware interactions.

## Tool Interface

```zig theme={null}
pub const Tool = struct {
    ptr: *anyopaque,
    vtable: *const VTable,

    pub const VTable = struct {
        execute: *const fn(
            ptr: *anyopaque,
            allocator: std.mem.Allocator,
            args: JsonObjectMap,
        ) anyerror!ToolResult,
        
        name: *const fn(ptr: *anyopaque) []const u8,
        description: *const fn(ptr: *anyopaque) []const u8,
        parameters_json: *const fn(ptr: *anyopaque) []const u8,
        
        deinit: ?*const fn(ptr: *anyopaque, allocator: std.mem.Allocator) void = null,
    };
};

pub const ToolResult = struct {
    success: bool,
    output: []const u8,       // Owned by caller, must free
    error_msg: ?[]const u8,   // Owned by caller, must free if non-null
};
```

## Available Tools (30+)

### File System Tools

| Tool             | Description                | Parameters                                             |
| ---------------- | -------------------------- | ------------------------------------------------------ |
| **file\_read**   | Read file contents         | `path: string, offset?: number, limit?: number`        |
| **file\_write**  | Write/overwrite file       | `path: string, content: string`                        |
| **file\_edit**   | Edit file (search/replace) | `path: string, old_string: string, new_string: string` |
| **file\_append** | Append to file             | `path: string, content: string`                        |

### Shell Execution

| Tool      | Description       | Parameters                               |
| --------- | ----------------- | ---------------------------------------- |
| **shell** | Run shell command | `command: string, timeout_secs?: number` |

### Memory Tools

| Tool               | Description         | Parameters                                        |
| ------------------ | ------------------- | ------------------------------------------------- |
| **memory\_store**  | Save memory entry   | `key: string, content: string, category?: string` |
| **memory\_recall** | Search memory       | `query: string, limit?: number`                   |
| **memory\_list**   | List all memories   | `category?: string`                               |
| **memory\_forget** | Delete memory entry | `key: string`                                     |

### Web Tools

| Tool              | Description           | Parameters                                                      |
| ----------------- | --------------------- | --------------------------------------------------------------- |
| **http\_request** | HTTP GET/POST         | `url: string, method?: string, headers?: object, body?: string` |
| **web\_search**   | Search the web        | `query: string, num_results?: number`                           |
| **web\_fetch**    | Fetch webpage content | `url: string, max_chars?: number`                               |
| **browser\_open** | Open URL in browser   | `url: string`                                                   |
| **screenshot**    | Take screenshot       | `output_path?: string`                                          |

### Git Tools

| Tool    | Description      | Parameters        |
| ------- | ---------------- | ----------------- |
| **git** | Run git commands | `command: string` |

### Hardware Tools

| Tool                 | Description       | Parameters                                                       |
| -------------------- | ----------------- | ---------------------------------------------------------------- |
| **hardware\_info**   | Get board info    | `board: string`                                                  |
| **hardware\_memory** | Read/write memory | `board: string, address: number, value?: number`                 |
| **i2c**              | I2C read/write    | `bus: number, address: number, register: number, value?: number` |
| **spi**              | SPI transfer      | `bus: number, data: array<number>`                               |

### Scheduling Tools

| Tool             | Description      | Parameters                                          |
| ---------------- | ---------------- | --------------------------------------------------- |
| **cron\_add**    | Add cron job     | `expression: string, command: string`               |
| **cron\_list**   | List cron jobs   | —                                                   |
| **cron\_remove** | Remove cron job  | `id: string`                                        |
| **cron\_run**    | Run job now      | `id: string`                                        |
| **cron\_update** | Update job       | `id: string, expression?: string, command?: string` |
| **cron\_runs**   | List recent runs | `limit?: number`                                    |

### Agent Tools

| Tool         | Description          | Parameters                            |
| ------------ | -------------------- | ------------------------------------- |
| **delegate** | Delegate to subagent | `agent_id: string, task: string`      |
| **spawn**    | Spawn async subagent | `task: string, timeout_secs?: number` |
| **schedule** | Schedule future task | `when: string, task: string`          |

### Messaging Tools

| Tool         | Description             | Parameters                                         |
| ------------ | ----------------------- | -------------------------------------------------- |
| **message**  | Send message to channel | `channel: string, target: string, message: string` |
| **pushover** | Send push notification  | `message: string, priority?: number`               |

### Integration Tools

| Tool         | Description             | Parameters                       |
| ------------ | ----------------------- | -------------------------------- |
| **composio** | Execute Composio action | `action: string, params: object` |
| **image**    | Get image metadata      | `path: string`                   |

## Tool Execution Flow

```mermaid theme={null}
flowchart TD
    LLM[LLM Returns Tool Call] --> Parse[Parse tool_calls JSON]
    Parse --> Lookup[Lookup Tool by Name]
    Lookup --> Args[Parse Arguments]
    Args --> Security{Security Check}
    Security -->|Deny| Reject[Return Error]
    Security -->|Allow| Execute[Execute Tool]
    Execute --> Result{Success?}
    Result -->|Yes| Format[Format Output]
    Result -->|No| Error[Format Error]
    Format --> Agent[Return to Agent]
    Error --> Agent
    Reject --> Agent
    Agent --> Context[Append to Context]
    Context --> LLM2[Next LLM Call]
```

### Step-by-Step

1. **LLM returns tool calls** in `ChatResponse.tool_calls`:
   ```json theme={null}
   {
     "id": "call_abc123",
     "name": "file_read",
     "arguments": "{\"path\":\"README.md\"}"
   }
   ```

2. **Agent dispatcher** looks up tool by name

3. **Parses arguments** from JSON string to `JsonObjectMap`

4. **Security policy check**:
   * Workspace scoping (file paths)
   * Command allowlist (shell commands)
   * Risk classification (high-risk commands)

5. **Tool execution** via `vtable.execute()`:
   ```zig theme={null}
   const result = try tool.execute(allocator, args);
   ```

6. **Result formatting**:
   ```zig theme={null}
   if (result.success) {
       // Append result.output to conversation
   } else {
       // Append result.error_msg as error
   }
   ```

7. **Next LLM call** with tool result in context

## Security Boundaries

### Workspace Scoping

By default, file tools are restricted to `~/.nullclaw/workspace/`:

```json theme={null}
{
  "autonomy": {
    "workspace_only": true,
    "allowed_paths": []  // Additional paths outside workspace
  }
}
```

**Path validation**:

* Null byte injection blocked
* Symlink escape detection
* Absolute path resolution
* Parent directory traversal blocked (unless in `allowed_paths`)

### Command Allowlist

Shell tool enforces command allowlist:

```json theme={null}
{
  "autonomy": {
    "allowed_commands": ["git", "npm", "zig"],  // Prefix matching
    "block_high_risk_commands": true
  }
}
```

**Risk levels**:

* **High**: `rm -rf`, `dd`, `mkfs`, `shutdown`, `reboot`
* **Medium**: `sudo`, `curl`, `wget`, `chmod +x`
* **Low**: `ls`, `cat`, `echo`, `git status`

### Sandbox Isolation

Tools execute within configured sandbox backend:

```json theme={null}
{
  "security": {
    "sandbox": {
      "backend": "auto"  // landlock | firejail | bubblewrap | docker
    }
  }
}
```

Sandbox blocks:

* Network access (unless allowed)
* Filesystem access outside workspace
* Subprocess spawning (unless allowed)
* Syscall filtering (landlock)

## Configuration

### Enable/Disable Tools

```json theme={null}
{
  "tools": {
    "http_request": {
      "enabled": true,
      "allowed_domains": ["api.github.com", "*.example.com"],
      "max_response_size": 1000000,
      "timeout_secs": 30
    },
    "web_search": {
      "enabled": true,
      "search_provider": "searxng",
      "search_base_url": "https://searx.example.com"
    },
    "shell": {
      "timeout_secs": 60,
      "max_output_bytes": 100000
    }
  }
}
```

### Tool Limits

```json theme={null}
{
  "tools": {
    "max_file_size_bytes": 10485760,  // 10 MB
    "shell_timeout_secs": 60,
    "shell_max_output_bytes": 100000,
    "web_fetch_max_chars": 50000
  }
}
```

## Tool Implementation Guide

### Minimal Tool

```zig:src/tools/my_tool.zig theme={null}
const std = @import("std");
const Tool = @import("root.zig").Tool;
const ToolResult = @import("root.zig").ToolResult;
const JsonObjectMap = @import("root.zig").JsonObjectMap;
const getString = @import("root.zig").getString;

pub const MyTool = struct {
    pub const tool_name = "my_tool";
    pub const tool_description = "Does something useful";
    pub const tool_params = 
        \\{"type":"object","properties":{
        \\  "input":{"type":"string","description":"Input text"}
        \\},"required":["input"]}
    ;

    pub fn execute(
        self: *MyTool,
        allocator: std.mem.Allocator,
        args: JsonObjectMap,
    ) anyerror!ToolResult {
        const input = getString(args, "input") orelse
            return ToolResult.fail("missing required parameter: input");

        // Do something with input...
        const output = try std.fmt.allocPrint(allocator, "Processed: {s}", .{input});

        return .{ .success = true, .output = output };
    }

    pub fn tool(self: *MyTool) Tool {
        return .{ .ptr = @ptrCast(self), .vtable = &vtable };
    }

    pub const vtable = @import("root.zig").ToolVTable(MyTool);
};
```

### Register Tool

Add to `src/tools/root.zig`:

```zig theme={null}
pub const my_tool = @import("my_tool.zig");

pub fn allTools(...) ![]Tool {
    // ...
    const mt = try allocator.create(my_tool.MyTool);
    mt.* = .{};
    try list.append(allocator, mt.tool());
    // ...
}
```

## Memory Tools Deep Dive

### memory\_store

Saves structured knowledge:

```json theme={null}
{
  "key": "alice_preference_editor",
  "content": "Alice prefers vim over emacs",
  "category": "core"
}
```

Categories:

* `core` — long-term facts
* `daily` — today's context
* `conversation` — session-specific
* Custom categories (e.g., `"project_alpha"`)

### memory\_recall

Hybrid search (FTS5 + vector similarity):

```json theme={null}
{
  "query": "What editor does Alice like?",
  "limit": 5
}
```

Returns scored results:

```json theme={null}
[
  {
    "key": "alice_preference_editor",
    "content": "Alice prefers vim over emacs",
    "score": 0.92,
    "timestamp": "2026-03-01T12:34:56Z"
  }
]
```

<Info>
  Vector search requires embedding provider configuration. Falls back to keyword-only (FTS5) if disabled.
</Info>

## Web Search Providers

The `web_search` tool supports multiple providers:

| Provider       | API Key Required | Features                   |
| -------------- | ---------------- | -------------------------- |
| **SearXNG**    | No               | Self-hosted, privacy-first |
| **DuckDuckGo** | No               | Free, rate-limited         |
| **Brave**      | Yes              | Privacy-focused, fast      |
| **Jina**       | Yes              | AI-optimized search        |
| **Perplexity** | Yes              | LLM-augmented search       |
| **Tavily**     | Yes              | Research-grade results     |
| **Exa**        | Yes              | Semantic search            |

Configuration:

```json theme={null}
{
  "tools": {
    "http_request": {
      "search_provider": "brave",
      "search_fallback_providers": ["jina", "duckduckgo"]
    }
  }
}
```

Env vars: `BRAVE_API_KEY`, `JINA_API_KEY`, etc.

## Hardware Tools (IoT)

### Supported Boards

* **Arduino** (Uno, Mega, Nano)
* **Raspberry Pi** (all models, GPIO via sysfs)
* **STM32/Nucleo** (via probe-rs)
* **ESP32** (via serial)

### Example: Read I2C Sensor

```json theme={null}
{
  "tool": "i2c",
  "bus": 1,
  "address": 0x48,
  "register": 0x00
}
```

Returns raw byte value from register.

## Next Steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/essentials/configuration">
    Full tool configuration reference
  </Card>

  <Card title="Security" icon="shield" href="/concepts/security">
    Learn about tool security policies
  </Card>
</CardGroup>
