# Tool Trait in OpenHuman: Architecture, Implementation, and Security Model

> Explore the Tool trait in OpenHuman. Understand its architecture, implementation, and security model. Learn how it defines agent-callable tools with a sandboxed run method for secure concurrent execution.

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

---

**The `Tool` trait in OpenHuman defines the core contract for agent-callable tools, requiring implementations to provide a `run` method that executes under a sandboxed context with specific permissions, while being `Send + Sync` for concurrent use across the runtime.**

The `Tool` trait serves as the foundational interface enabling LLM agents to safely execute arbitrary functionality within the OpenHuman framework. Located in the `tinyhumansai/openhuman` repository, this trait establishes a strict contract between the agent runtime and external capabilities, ensuring that every tool invocation adheres to the project's security policies and sandboxing requirements.

## Core Definition and Source Locations

The `Tool` trait originates in the vendored **tinytools** crate, a submodule of the `tinyagents` dependency, and is re-exported through the core source to provide a unified public API.

According to the source code, the trait is publicly exposed at:

- **[`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs)** – The primary entry point that re-exports `Tool`, `ToolResult`, and `ToolArgs`.

The actual definition resides in the vendored dependency at:

- **[`vendor/tinyagents/vendor/tinytools/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinyagents/vendor/tinytools/src/lib.rs)** – Contains the original trait definition and supporting types.

This re-export pattern guarantees type compatibility across the entire system. By avoiding duplicate definitions, the core prevents type-mismatch bugs when the sandbox, policy engine, and dispatcher interact with tool implementations.

## Trait Contract and Required Methods

Any type implementing the `Tool` trait must satisfy a minimal but strict interface designed for safety and concurrency.

### Method Signature

The single required method follows this signature:

```rust
fn run(&self, ctx: &dyn ToolRunContext, args: Self::Args) -> ToolResult;

```

The trait uses an associated type `Args` for the input parameters, allowing each tool to define its own strongly-typed argument struct. These arguments must derive `serde::Deserialize` so the dispatcher can automatically parse JSON payloads from the LLM.

### Thread Safety Requirements

OpenHuman enforces strict concurrency constraints on tool implementations. The trait requires `Send + Sync` bounds, ensuring that tool instances can be shared safely across multiple async tasks within the core runtime. This design supports high-throughput agent systems where multiple turns may invoke tools concurrently.

## Implementing a Custom Tool

Creating a functional tool requires implementing the trait with a concrete argument type. Below is a complete implementation of a simple "echo" tool that returns the provided message.

```rust
use openhuman::tools::traits::*;

/// Arguments accepted by the tool – must derive `serde::Deserialize`.
#[derive(Debug, serde::Deserialize)]
pub struct EchoArgs {
    pub message: String,
}

/// The concrete tool implementation.
pub struct EchoTool;

impl Tool for EchoTool {
    type Args = EchoArgs;

    fn run(
        &self,
        _ctx: &dyn ToolRunContext,
        args: Self::Args,
    ) -> ToolResult {
        // The tool simply returns the provided message.
        ToolResult::content(args.message)
    }

    // Optional: declare required permission and sandbox mode.
    fn permission(&self) -> PermissionLevel {
        PermissionLevel::Read   // no privileged access needed
    }

    fn sandbox_mode(&self) -> SandboxMode {
        SandboxMode::None       // runs without a sandbox
    }
}

```

The implementation demonstrates three key patterns: defining a deserializable `Args` struct, providing the mandatory `run` method, and declaratively specifying security characteristics through optional trait methods.

## Registration and Runtime Integration

Before a tool becomes available to the LLM, it must be registered with the runtime's tool registry located in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs).

### Registering with the Tool Registry

```rust
use openhuman::tools::ops::*; // contains the registration helper

fn register_echo_tool(registry: &mut ToolRegistry) {
    registry.register(
        "echo",               // tool name used in the LLM schema
        EchoTool,             // the concrete implementation
        // The schema is automatically derived from `EchoArgs`
    );
}

```

After registration, the tool appears in the LLM's tool catalogue, enabling the model to generate structured calls. The dispatcher—implemented in **[`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs)**—parses these calls and routes them to the appropriate `Tool::run` implementation.

### Execution Hooks

The runtime supports intervention through the `ToolHook` trait defined in **[`src/openhuman/agent/hooks.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/hooks.rs)**. Hooks can execute before or after a tool runs, enabling logging, validation, or modification of arguments and results without changing the tool implementation.

## Security Model and Sandboxing

Every tool invocation passes through multiple security layers before execution begins.

### Permission Levels and Scopes

Tools declare their required access level through the `permission()` method, returning a `PermissionLevel` enum value. The core compares this against the agent's active `SecurityPolicy` and the tool's `ToolScope` before allowing execution.

### Sandboxing Strategy

If a tool requests filesystem or network access, the `sandbox_mode()` return value determines isolation behavior:

- **`SandboxMode::None`** – Runs without restrictions (appropriate for pure computation)
- **`SandboxMode::Filesystem`** – Restricts file operations to specific directories
- **`SandboxMode::Network`** – Isolates network calls according to policy

The sandbox subsystem enforces these constraints at runtime, preventing tools from exceeding their declared capabilities even if compromised.

## Summary

- The **`Tool` trait** defines a single `run` method accepting a context and typed arguments, returning a `ToolResult`.
- The trait is re-exported from the vendored tinytools crate at **[`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs)** to ensure type consistency across the codebase.
- Implementations must be **`Send + Sync`** to support safe concurrent execution within the async runtime.
- Tools integrate with OpenHuman's security model through **`PermissionLevel`** declarations and **`SandboxMode`** specifications.
- The **`ToolRegistry`** in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) exposes tools to the LLM, while the **`dispatcher`** routes invocations and **`ToolHook`** implementations enable cross-cutting concerns.

## Frequently Asked Questions

### Where is the Tool trait defined in OpenHuman?

The trait is originally defined in the vendored `tinytools` crate at [`vendor/tinyagents/vendor/tinytools/src/lib.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinyagents/vendor/tinytools/src/lib.rs) and publicly re-exported through [`src/openhuman/tools/traits.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/traits.rs). This architecture ensures that all components reference the same type definition, preventing interface mismatches between the core runtime and external tool implementations.

### What methods must a Tool implementation provide?

At minimum, implementers must provide the **`run`** method with the signature `fn run(&self, ctx: &dyn ToolRunContext, args: Self::Args) -> ToolResult` and specify the associated **`Args`** type. Optional methods include **`permission()`** and **`sandbox_mode()`**, which declare the tool's security requirements and isolation preferences to the policy engine.

### How does OpenHuman ensure thread safety for tools?

The `Tool` trait requires **`Send + Sync`** bounds on all implementations. This constraint allows the core runtime to share tool references across multiple concurrent tasks and async workers without risking data races or undefined behavior during parallel tool invocations.

### What happens during a tool invocation from the LLM?

The **`dispatcher`** ([`src/openhuman/agent/dispatcher.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/dispatcher.rs)) parses the model-generated tool call, validates the arguments against the registered schema, and checks the tool's permissions against the active `SecurityPolicy`. If approved, any registered **`ToolHook`** implementations execute, followed by the actual **`run`** method invocation within the specified sandbox constraints. The resulting `ToolResult` is marshalled back into the model's context window.