# How the tinytools Tool Trait Bridges OpenHuman Host and tinyagents

> Explore the tinytools Tool trait in OpenHuman. Learn how it creates a type-safe interface for seamless LLM tool execution between host and tinyagents, eliminating serialization issues.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: deep-dive
- Published: 2026-08-30

---

**The tinytools Tool trait provides a shared, type-safe interface between the OpenHuman host and the tinyagents harness, allowing LLM tools to be defined once in the host and executed seamlessly by the agent runtime without serialization overhead or type mismatches.**

The OpenHuman architecture strictly separates core business logic from agent orchestration using a vendored `tinytools` crate. By importing this crate, both the host (`src/openhuman`) and the agent harness (`tinyagents`) share an identical definition of the **tinytools Tool trait**, ensuring compile-time guarantees for tool compatibility across the architectural boundary.

## Where the tinytools Tool Trait Is Defined

### Core Definition in the tinytools Crate

The canonical trait definition resides in [`vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs). This lightweight library is vendored inside the repository and consumed as a dependency by both the host and `tinyagents`, serving as the single source of truth for the tool interface.

### Host-Side Re-export

Rather than duplicating the interface, the host re-exports the trait in [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs). This zero-cost abstraction ensures that when the host implements `Tool`, it implements the exact same type that `tinyagents` expects at runtime, eliminating any adapter boilerplate or serialization bridges.

## The Tool Trait Interface

### Required Methods

The trait defines six methods that establish the contract between the LLM and the host implementation:

- `fn name(&self) -> &'static str` – Returns the human-readable identifier used in the tool catalogue.
- `fn description(&self) -> &'static str` – Provides the description injected into the LLM prompt.
- `fn input_schema(&self) -> tinytools::json::Value` – Supplies the JSON schema for validating model-generated arguments.
- `fn run(&self, args: tinytools::json::Value, ctx: &dyn tinytools::ToolRunContext) -> tinytools::ToolResult` – Executes the tool logic with access to runtime context.
- `fn host_extension(&self) -> Option<&dyn std::any::Any>` – Optional hook for attaching host-specific data like workspace paths.
- `fn host_call_extension(&self, data: &dyn std::any::Any) -> tinytools::ToolResult` – Optional callback for delegating side effects back to the host.

### Type Safety Across the Boundary

Because both sides import the same trait from [`vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs), the Rust compiler guarantees that any struct implementing `Tool` in the host satisfies the interface expected by `tinyagents::harness::tool_calling::dialect`. There is no risk of type mismatches or version skew between the catalogue generation and the execution phase.

## Implementing and Registering Host Tools

### Step 1: Implement the Trait

Create a struct in `src/openhuman/tools/` and implement the `Tool` trait with the required metadata and execution logic:

```rust
// src/openhuman/tools/example_tool.rs
use tinytools::{Tool, ToolResult, ToolRunContext};

pub struct EchoTool;

impl Tool for EchoTool {
    fn name(&self) -> &'static str { "echo" }
    
    fn description(&self) -> &'static str { 
        "Returns the supplied text unchanged." 
    }

    fn input_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "text": { "type": "string" }
            },
            "required": ["text"]
        })
    }

    fn run(
        &self,
        args: serde_json::Value,
        _ctx: &dyn ToolRunContext,
    ) -> ToolResult {
        let text = args.get("text")
            .and_then(|v| v.as_str())
            .ok_or_else(|| tinytools::error("Missing `text`"))?;
        Ok(tinytools::ToolContent::String(text.to_owned()))
    }
}

```

### Step 2: Expose via the Tool Registry

Register the implementation in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) by adding it to the `all_host_tools()` vector:

```rust
// src/openhuman/tools/ops.rs (excerpt)
use crate::tools::example_tool::EchoTool;

pub fn all_host_tools() -> Vec<Box<dyn Tool>> {
    vec![
        Box::new(EchoTool),
        // … other tools
    ]
}

```

### Step 3: Startup Registration

During core initialization, the host instantiates a `ToolGroup` and registers the list returned by `all_host_tools()` with the `tinyagents` dispatcher in [`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs). This registration makes the catalogue metadata available for prompt generation and the `run` implementations available for runtime dispatch.

## How tinyagents Discovers and Executes Tools

### Tool Discovery

The `tinyagents::harness::tool_calling::dialect` module iterates over registered `Tool` objects to build a catalogue. The `render_pformat_catalogue` function serializes each tool's `name`, `description`, and `input_schema` into the system prompt, informing the LLM of available capabilities.

### Execution Flow

When the model emits a tool call, the following sequence occurs:

1. The dialect parser (`tinyagents::harness::tool_calling::dialect::parse_call`) extracts the tool name and arguments from the LLM output.
2. The dispatcher in [`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs) performs a lookup in the host's registry to obtain a `&dyn Tool`.
3. The dispatcher invokes the `run` method, passing the parsed arguments and a `ToolRunContext` implementation.
4. The context object provides access to turn budget, thread ID, and workspace root while remaining type-safe and host-specific.

## Host Extensions for Advanced Use Cases

### Attaching Host Data

The `host_extension()` method allows tools to expose references to host-owned values stored as `dyn Any`. This is essential for tools that need access to resources like temporary directories or sandbox tokens that cannot be hardcoded into the tool definition.

### Delegating Side Effects

The `host_call_extension(&self, data: &dyn Any)` method enables the host to invoke callbacks on the extension data. This lets tools delegate privileged operations—such as filesystem writes or network calls—back to the host without breaking the `Tool` contract or introducing host dependencies into the trait.

### Optional Implementation

These extension methods are strictly optional. The majority of tools implement only the core quartet (`name`, `description`, `input_schema`, `run`) while relying on the `ToolRunContext` parameter for runtime state.

## Summary

- The **tinytools Tool trait** is defined in [`vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinyagents/vendor/tinytools/crates/tinytools/src/lib.rs) and re-exported by the host in [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs) to ensure zero type duplication.
- The trait contract includes metadata methods, JSON schema validation, and the `run` execution hook that accepts a `ToolRunContext`.
- Host tools are aggregated in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) and registered with the dispatcher at startup in [`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs).
- **tinyagents** uses `tinyagents::harness::tool_calling::dialect` for catalogue generation and `parse_call` for dispatch, invoking the host's `run` method directly through trait objects.
- Optional `host_extension` and `host_call_extension` hooks allow tools to access host resources while maintaining strict architectural separation.

## Frequently Asked Questions

### What is the tinytools Tool trait in OpenHuman?

The tinytools Tool trait is a Rust interface defined in the vendored `tinytools` crate that standardizes how tools are named, described, validated, and executed. It acts as the single source of truth for both the OpenHuman host and the tinyagents harness, ensuring they agree on tool signatures at compile time.

### How does the host register tools with tinyagents?

The host implements the `Tool` trait for each capability, aggregates instances in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) within the `all_host_tools()` function, and passes this list to the dispatcher during initialization in [`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs). This registration binds the tool catalogue to the runtime executor.

### What is the ToolRunContext used for?

The `ToolRunContext` trait provides runtime environmental data—such as budget constraints, thread identifiers, and workspace paths—to the `run` method. It is passed as a trait object (`&dyn ToolRunContext`) to maintain type erasure on the `tinyagents` side while allowing host-specific context implementations.

### How do host extensions work?

Host extensions use the `host_extension()` method to attach host-specific data (as `dyn Any`) to a tool instance, and `host_call_extension()` to invoke host-side callbacks on that data. These optional methods allow tools to perform privileged operations or access external resources by delegating to the host rather than implementing logic directly in the trait.