Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The tools module provides an extensible system for agent capabilities. Tools can:
  • Call external APIs
  • Interact with the marketplace
  • Execute sandboxed code (via WASM)
  • Delegate tasks to other services
  • Build new software and tools dynamically
Tools execute in different domains (orchestrator vs. container) with safety controls, rate limiting, and approval requirements.

Core Types

Tool Trait

The main trait that all tools must implement.
#[async_trait]
pub trait Tool: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn parameters_schema(&self) -> serde_json::Value;
    
    async fn execute(
        &self,
        params: serde_json::Value,
        ctx: &JobContext,
    ) -> Result<ToolOutput, ToolError>;
    
    fn estimated_cost(&self, params: &serde_json::Value) -> Option<Decimal> {
        None
    }
    
    fn approval_requirement(&self, params: &serde_json::Value) -> ApprovalRequirement {
        ApprovalRequirement::Never
    }
    
    fn domain(&self) -> ToolDomain {
        ToolDomain::Orchestrator
    }
    
    fn rate_limit_config(&self) -> Option<ToolRateLimitConfig> {
        None
    }
}

Methods

name
fn(&self) -> &str
Return the tool name (must be unique in registry)
description
fn(&self) -> &str
Human-readable description of what the tool does
parameters_schema
fn(&self) -> serde_json::Value
JSON Schema defining the tool’s parameters
execute
async fn(&self, params: Value, ctx: &JobContext) -> Result<ToolOutput>
Execute the tool with given parameters and context
estimated_cost
fn(&self, params: &Value) -> Option<Decimal>
Estimate the cost of running this tool (optional)
approval_requirement
fn(&self, params: &Value) -> ApprovalRequirement
Whether this invocation requires approval
domain
fn(&self) -> ToolDomain
Where this tool should execute (Orchestrator or Container)
rate_limit_config
fn(&self) -> Option<ToolRateLimitConfig>
Rate limiting configuration for this tool

Example

use ironclaw::tools::{Tool, ToolOutput, ToolError};
use async_trait::async_trait;

struct EchoTool;

#[async_trait]
impl Tool for EchoTool {
    fn name(&self) -> &str {
        "echo"
    }
    
    fn description(&self) -> &str {
        "Echo back the input message"
    }
    
    fn parameters_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "message": {
                    "type": "string",
                    "description": "Message to echo"
                }
            },
            "required": ["message"]
        })
    }
    
    async fn execute(
        &self,
        params: serde_json::Value,
        _ctx: &JobContext,
    ) -> Result<ToolOutput, ToolError> {
        let message = params["message"].as_str()
            .ok_or_else(|| ToolError::InvalidParameters(
                "message must be a string".to_string()
            ))?;
        
        Ok(ToolOutput::text(message, Duration::from_millis(1)))
    }
}

ToolRegistry

Manages the collection of available tools.
new
fn() -> Self
Create a new empty tool registry
register
fn(&mut self, tool: Arc<dyn Tool>) -> Result<()>
Register a tool in the registry (fails if name already exists)
get
fn(&self, name: &str) -> Option<Arc<dyn Tool>>
Get a tool by name
list
fn(&self) -> Vec<&str>
List all registered tool names
schemas
fn(&self) -> Vec<ToolDefinition>
Get all tool schemas for LLM function calling

Example

use ironclaw::tools::ToolRegistry;

let mut registry = ToolRegistry::new();
registry.register(Arc::new(EchoTool))?;
registry.register(Arc::new(TimeTool))?;

// List all tools
for name in registry.list() {
    println!("Available: {}", name);
}

// Get a tool
if let Some(tool) = registry.get("echo") {
    let output = tool.execute(params, &ctx).await?;
}

ToolOutput

Result returned by tool execution.
result
serde_json::Value
The result data (JSON value)
cost
Option<Decimal>
Cost incurred (if any)
duration
Duration
Time taken to execute
raw
Option<String>
Raw output before sanitization (for debugging)

Constructors

success
fn(result: Value, duration: Duration) -> Self
Create a successful output with JSON result
text
fn(text: impl Into<String>, duration: Duration) -> Self
Create a text output (convenience for string results)
with_cost
fn(self, cost: Decimal) -> Self
Add cost information to the output
with_raw
fn(self, raw: impl Into<String>) -> Self
Add raw output for debugging

Example

use ironclaw::tools::ToolOutput;
use std::time::Duration;
use rust_decimal_macros::dec;

let output = ToolOutput::text("Hello, world!", Duration::from_millis(5))
    .with_cost(dec!(0.001));

ToolError

Error types for tool execution.
InvalidParameters
String
Parameters don’t match the schema or are invalid
ExecutionFailed
String
Tool execution failed with an error
Timeout
Duration
Tool execution exceeded timeout
NotAuthorized
String
User not authorized to use this tool
RateLimited
Option<Duration>
Rate limit exceeded, retry after duration
ExternalService
String
External service error (API, network, etc.)
Sandbox
String
Sandbox/WASM execution error

ApprovalRequirement

Defines how much approval a tool invocation needs.
Never
()
No approval needed (safe, read-only tools)
UnlessAutoApproved
()
Needs approval unless user has auto-approved this tool
Always
()
Always requires explicit approval (destructive operations)

Example

use ironclaw::tools::ApprovalRequirement;

impl Tool for FileDeleteTool {
    fn approval_requirement(&self, _params: &Value) -> ApprovalRequirement {
        ApprovalRequirement::Always  // Destructive operation
    }
}

impl Tool for FileReadTool {
    fn approval_requirement(&self, _params: &Value) -> ApprovalRequirement {
        ApprovalRequirement::Never  // Safe read-only
    }
}

ToolDomain

Where a tool should execute.
Orchestrator
()
Safe to run in the main agent process (pure functions, memory, job management)
Container
()
Must run inside a sandboxed container (filesystem, shell, code execution)
use ironclaw::tools::ToolDomain;

impl Tool for MemoryWriteTool {
    fn domain(&self) -> ToolDomain {
        ToolDomain::Orchestrator  // Safe in main process
    }
}

impl Tool for ShellTool {
    fn domain(&self) -> ToolDomain {
        ToolDomain::Container  // Needs isolation
    }
}

ToolRateLimitConfig

Rate limiting configuration for tools.
requests_per_minute
u32
default:"60"
Maximum invocations per minute per user
requests_per_hour
u32
default:"1000"
Maximum invocations per hour per user
new
fn(requests_per_minute: u32, requests_per_hour: u32) -> Self
Create a custom rate limit config
default
fn() -> Self
Default: 60/min, 1000/hour
use ironclaw::tools::ToolRateLimitConfig;

impl Tool for HttpTool {
    fn rate_limit_config(&self) -> Option<ToolRateLimitConfig> {
        Some(ToolRateLimitConfig::new(30, 500))  // Conservative limits
    }
}

Schema Validation

validate_tool_schema

validate_tool_schema
fn(schema: &Value, params: &Value) -> Result<()>
Validate parameters against a JSON Schema. Returns error if validation fails.
use ironclaw::tools::validate_tool_schema;

let schema = serde_json::json!({
    "type": "object",
    "properties": {
        "name": { "type": "string" },
        "age": { "type": "number" }
    },
    "required": ["name"]
});

let params = serde_json::json!({
    "name": "Alice",
    "age": 30
});

validate_tool_schema(&schema, &params)?;  // OK

Rate Limiting

RateLimiter

Per-user rate limiting for tool invocations.
new
fn() -> Self
Create a new rate limiter
check_and_increment
fn(&self, user_id: &str, tool_name: &str, config: &ToolRateLimitConfig) -> Result<(), Duration>
Check if request is allowed and increment counter. Returns error with retry-after duration if rate limited.
use ironclaw::tools::RateLimiter;

let limiter = RateLimiter::new();
let config = ToolRateLimitConfig::default();

match limiter.check_and_increment("user_123", "http", &config) {
    Ok(()) => {
        // Proceed with tool execution
    }
    Err(retry_after) => {
        return Err(ToolError::RateLimited(Some(retry_after)));
    }
}

Software Builder

Dynamically build and deploy new tools at runtime.

SoftwareBuilder

Trait for building software from natural language specifications.
#[async_trait]
pub trait SoftwareBuilder: Send + Sync {
    async fn build(
        &self,
        requirements: &BuildRequirement,
    ) -> Result<BuildResult, Box<dyn std::error::Error>>;
}

LlmSoftwareBuilder

LLM-powered software builder that generates code from specs.
new
fn(llm: Arc<dyn LlmProvider>, config: BuilderConfig) -> Self
Create a new LLM-based software builder
build
async fn(&self, requirements: &BuildRequirement) -> Result<BuildResult>
Build software from requirements using LLM code generation

BuildRequirement

name
String
Name of the software/tool to build
description
String
What the software should do
language
Language
Target language (Rust, Python, JavaScript, etc.)
software_type
SoftwareType
Type (Tool, Library, Service, etc.)
dependencies
Vec<String>
Required dependencies
test_cases
Vec<TestCase>
Test cases to validate the implementation

BuildResult

source_code
String
Generated source code
metadata
BuildMetadata
Build information (language, version, etc.)
test_results
Vec<TestResult>
Results of running test cases
validation_errors
Vec<ValidationError>
Any validation errors found

Example

use ironclaw::tools::{LlmSoftwareBuilder, BuildRequirement, Language, SoftwareType};

let builder = LlmSoftwareBuilder::new(llm, BuilderConfig::default());

let req = BuildRequirement {
    name: "fibonacci".to_string(),
    description: "Calculate Fibonacci numbers".to_string(),
    language: Language::Rust,
    software_type: SoftwareType::Tool,
    dependencies: vec![],
    test_cases: vec![],
};

let result = builder.build(&req).await?;
println!("Generated code:\n{}", result.source_code);

MCP (Model Context Protocol)

Integration with external MCP servers for tool discovery.

McpClient

Client for connecting to MCP servers and loading tools.
connect
async fn(server_url: &str) -> Result<Self>
Connect to an MCP server
list_tools
async fn(&self) -> Result<Vec<ToolDefinition>>
List available tools from the MCP server
load_tool
async fn(&self, name: &str) -> Result<Arc<dyn Tool>>
Load a specific tool from the MCP server
use ironclaw::tools::mcp::McpClient;

let client = McpClient::connect("http://localhost:3000").await?;
let tools = client.list_tools().await?;

for tool_def in tools {
    let tool = client.load_tool(&tool_def.name).await?;
    registry.register(tool)?;
}

WASM Tools

Load and execute tools compiled to WebAssembly.

WasmTool

A tool implementation that runs in a WASM sandbox.
load
async fn(wasm_bytes: &[u8]) -> Result<Self>
Load a WASM module as a tool
from_file
async fn(path: &Path) -> Result<Self>
Load a WASM module from a file
use ironclaw::tools::wasm::WasmTool;

let wasm_bytes = std::fs::read("tools/custom.wasm")?;
let tool = WasmTool::load(&wasm_bytes).await?;

registry.register(Arc::new(tool))?;

Built-in Tools

IronClaw includes several built-in tools in the builtin module:
  • EchoTool - Echo back input (testing)
  • TimeTool - Get current time
  • JsonTool - Parse and manipulate JSON
  • HttpTool - Make HTTP requests
  • MemoryReadTool - Read from workspace
  • MemoryWriteTool - Write to workspace
  • MemorySearchTool - Search workspace
  • ShellTool - Execute shell commands (container)
  • FileReadTool - Read files (container)
  • FileWriteTool - Write files (container)
See the source code for full details on each tool’s parameters and behavior.

Agent Module

Agent orchestration and tool execution

Workspace Module

Memory tools for persistent storage

Build docs developers (and LLMs) love