# How OpenHuman Handles Tool Definitions via tinytools: A Technical Deep Dive

> Discover how OpenHuman manages tool definitions using the tinytools crate. Learn about strict compile-time compatibility between Rust core and TinyAgents runtime in this technical deep dive.

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

---

**OpenHuman delegates all tool contract definitions to the `tinytools` crate, re-exporting its core traits through [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs) to ensure strict compile-time compatibility between the Rust core and the TinyAgents runtime.**

The `tinyhumansai/openhuman` repository implements a modular AI agent system where **tool definitions via tinytools** serve as the canonical interface for all executable capabilities. Rather than duplicating interface definitions, the project vendors the `tinytools` dependency under `vendor/tinyagents/vendor/tinytools` and re-exports its types, creating a single source of truth for the `Tool` trait and its associated types.

## Core Architecture of OpenHuman Tool Definitions

### The tinytools Trait System

At the heart of OpenHuman's tool system lies the **`Tool`** trait defined in the vendored `tinytools` crate and exposed through [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs). This trait mandates three essential methods that every concrete tool must implement:

- `run()` – Executes the tool's logic with JSON arguments and returns a `ToolResult`
- `schema()` – Returns a `ToolSchema` describing the tool's JSON-RPC interface
- `name()` – Provides the string identifier used for dispatch

The trait also defines **`ToolResult`** and **`ToolContent`** wrappers in the same file, standardizing how tool outputs serialize back to the LLM context. Because these definitions live in the external `tinytools` crate rather than the OpenHuman source tree, any breaking change to the trait signature triggers immediate compile-time errors across both the core library and the TinyAgents harness.

### Tool Registration and Discovery

Concrete tool implementations register themselves through the **`ToolRegistry`** system located in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs). During startup, `tools::ops::register_all_tools()` iterates over compiled tool packs defined in [`src/openhuman/tools/toolpacks/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/toolpacks/registry.rs), inserting each tool into a global registry that the agent harness queries when building the LLM's available tool catalogue.

## Implementing Tools in OpenHuman

Creating a new tool requires implementing the re-exported `Tool` trait from `tinytools`. Below is a minimal implementation pattern used throughout the `src/openhuman/tools/impl/` directory:

```rust
use tinytools::{Tool, ToolResult, ToolContent, ToolSchema};
use serde_json::json;

pub struct EchoTool;

impl Tool for EchoTool {
    fn name(&self) -> &'static str { "echo" }

    fn schema(&self) -> ToolSchema {
        ToolSchema::new()
            .with_description("Returns the supplied text unchanged")
            .with_parameters(json!({ "text": { "type": "string" } }))
    }

    fn run(&self, args: serde_json::Value) -> ToolResult {
        let text = args["text"].as_str().unwrap_or_default();
        Ok(ToolResult::new(ToolContent::text(text)))
    }
}

```

Registration typically occurs within domain-specific tool packs:

```rust
use crate::tools::registry::ToolRegistry;

pub fn register_echo(reg: &mut ToolRegistry) {
    reg.register(Box::new(EchoTool));
}

```

## The Tool Execution Flow

OpenHuman processes **tool definitions via tinytools** through a five-stage pipeline that bridges the LLM and Rust implementations:

1. **Schema Exposure** – The harness in `vendor/tinyagents/src/...` queries the `ToolRegistry` to build a JSON-RPC catalogue describing all registered tools' parameters and descriptions.

2. **LLM Invocation** – When the model generates a tool call, the payload matches one of the schemas defined by the `schema()` methods.

3. **Dispatch Resolution** – `tinyagents::harness::tool_calling` parses the request into a `ParsedToolCall`, resolves the tool name against the registry, and invokes the concrete implementation through the shared `Tool` trait.

4. **Execution** – The tool's `run()` method executes within the OpenHuman runtime, processing arguments and returning a `ToolResult`.

5. **Result Integration** – The harness serializes the `ToolResult` into `ToolContent` and injects it back into the conversation turn, allowing the LLM to continue reasoning with the tool's output.

## Conditional Compilation and Feature Gates

OpenHuman's modular architecture respects Cargo feature flags when exposing **tool definitions via tinytools**. The registration logic in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) uses `#[cfg(feature = "...")]` attributes to conditionally include tool families, while the underlying trait definitions remain available regardless of feature state.

```rust
#[cfg(feature = "documents")]
mod document_tools {
    // Document-related tool implementations live here
    // and register themselves only when the feature is enabled
}

```

When the `documents` feature is disabled, the module is excluded from compilation and `register_all_tools()` skips adding those tools to the catalogue. However, the `tinytools` types themselves (`Tool`, `ToolResult`, `ToolContent`) remain present because they are part of the always-on vendored dependency, ensuring other domains can still compile against the trait interface.

## Summary

- **OpenHuman re-exports** the `Tool` trait and result types from the vendored `tinytools` crate via [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs), ensuring version consistency.
- **Tool registration** occurs through [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs), which aggregates implementations from [`src/openhuman/tools/toolpacks/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/toolpacks/registry.rs) into a global `ToolRegistry`.
- **Execution flow** moves from LLM schema generation through `tinyagents::harness::tool_calling` dispatch to concrete `run()` implementations, with results serialized back through `ToolContent`.
- **Feature gates** in the registration layer allow conditional compilation of tool families without breaking the underlying trait contracts.
- **Compile-time safety** is enforced because the `Tool` trait lives in the external `tinytools` crate, causing build failures if OpenHuman implementations drift from the expected interface.

## Frequently Asked Questions

### What is the tinytools crate in OpenHuman?

The `tinytools` crate is the upstream dependency vendored at `vendor/tinyagents/vendor/tinytools` that defines the core `Tool` trait, `ToolResult`, and `ToolContent` types. OpenHuman re-exports these types through [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs) rather than maintaining duplicate definitions, ensuring that both the Rust core and TinyAgents runtime share identical interface contracts.

### How do I register a new tool in OpenHuman?

New tools implement the `Tool` trait from `tinytools` and call `ToolRegistry::register()` during initialization. The [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) module orchestrates this through `register_all_tools()`, which iterates over tool packs defined in [`src/openhuman/tools/toolpacks/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/toolpacks/registry.rs). Each tool pack typically contains a registration function that instantiates and boxes the concrete tool implementation.

### Can I disable specific tools at compile time?

Yes. OpenHuman uses Cargo feature flags to conditionally compile tool families. Wrapping tool modules in `#[cfg(feature = "feature_name")]` attributes allows the registration logic in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) to skip unavailable tools while keeping the underlying `tinytools` trait definitions accessible to the rest of the codebase.

### Where does the JSON schema for tool arguments come from?

Each tool implements the `schema()` method required by the `Tool` trait, returning a `ToolSchema` object that describes the tool's JSON-RPC interface. The TinyAgents harness queries these schemas from the `ToolRegistry` to construct the tool catalogue presented to the LLM during prompt generation.