# How Harness::builder() Composes a Core for Library Embedding in OpenHuman

> Discover how Harness::builder() composes an embeddable core for library integration in OpenHuman. Learn to build a runtime through step-by-step configuration.

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

---

**The `Harness::builder()` static method returns a configurable builder object that assembles a fully-initialized core runtime through step-by-step axis configuration, culminating in a single `build()` call that produces an embeddable `Harness` instance for library integration.**

The `tinyhumansai/openhuman` repository provides a library-friendly entry point for embedding AI capabilities directly into Rust applications. Understanding how `Harness::builder()` composes a core for library embedding reveals a three-stage composition pattern that transforms configuration parameters into a running, in-process AI core capable of executing prompts without network overhead.

## The Three-Stage Composition Architecture

The composition process implemented in the OpenHuman source code follows a clear pipeline from empty builder to running core. Each stage corresponds to specific source files and responsibilities within the embedding layer.

### Stage 1: Builder Creation

In [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs), the `Harness::builder()` static method constructs a new `Builder` struct. This builder holds mutable configuration fields for every runtime axis, including the **provider**, **workspace**, **access tier**, **backend URL**, **MCP servers**, **skill directories**, and **tool groups**. The builder starts with sensible defaults but remains uninitialized until the caller specifies required dependencies like the AI provider.

### Stage 2: Axis Configuration

The caller configures the runtime through a fluent interface of chaining methods. According to [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs), each method—`provider()`, `workspace()`, `access()`, `backend_url()`, `mcp()`, `skills_dir()`, and `tool_groups()`—updates the corresponding internal field and returns `&mut self` to enable further chaining. These methods perform lightweight validation, such as verifying that a `Workspace::Dir(path)` exists on disk, before returning the builder for the next configuration step.

### Stage 3: Core Construction

When the caller finally invokes `build()`, the builder transfers its collected configuration to `CoreBuilder` located in [`src/core/runtime/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/runtime/builder.rs). This internal constructor performs three critical selections:

- **Service set**: Configures infrastructure components including HTTP RPC, socket handlers, cron schedulers, channels, and heartbeat monitors.
- **Domain set**: Registers business logic domains such as agent, memory, threads, config, and security controllers, plus optional families like flows, skills, and web3.
- **Tool groups**: Determines tool visibility—advertised to the LLM, withheld, or turned off entirely.

`CoreBuilder` then spawns the core's asynchronous task system, registers all domain controllers, installs the tool registry, and wraps the runtime inside an `embed::Core` handle. This handle is stored within the `Harness` struct defined in [`src/embed/harness/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/mod.rs), exposing high-level methods like `run(prompt)` and `turn(prompt)` for library consumers.

## Configuring Runtime Axes

The builder pattern provides granular control over the embedding environment through type-safe configuration methods. Each method targets a specific axis of the runtime:

- **`provider()`**: Accepts a `Provider` enum variant, such as `Provider::openai_compatible(base_url, api_key)`, configuring the LLM backend.
- **`workspace()`**: Defines storage semantics using `Workspace::Ephemeral`, `Workspace::Dir(path)`, or `Workspace::Inherit` for persistent or temporary session storage.
- **`access()`**: Sets the access tier and origin permissions, typically via `Access::full()` for unrestricted library usage.
- **`backend_url()`**: Specifies the TinyHumans API endpoint for authentication and cloud services.
- **`mcp()`**: Registers Model Context Protocol servers via `McpServer::stdio(name, command, args)` for external tool integration.
- **`tool_groups()`**: Controls tool advertisement using `ToolGroups::packed()` or `ToolGroups::with("media", GroupMode::Off)` to hide specific capabilities.

Because the core is **embedded** in the same process, there is no network hop between the library caller and the runtime—all RPC calls resolve to direct method invocations on the `embed::Core` handle.

## Practical Implementation Examples

The following examples demonstrate common patterns for library embedding found in [`examples/run_turn.rs`](https://github.com/tinyhumansai/openhuman/blob/main/examples/run_turn.rs) and [`tests/harness_embed.rs`](https://github.com/tinyhumansai/openhuman/blob/main/tests/harness_embed.rs).

### Basic Single-Turn Usage

This pattern creates a harness, composes the core, and executes a single prompt:

```rust
use openhuman::embed::harness::Harness;
use openhuman::provider::Provider;
use openhuman::workspace::Workspace;
use openhuman::access::Access;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let harness = Harness::builder()
        .provider(Provider::openai_compatible(
            "https://api.openai.com/v1",
            std::env::var("OPENAI_API_KEY")?,
        ))
        .workspace(Workspace::Ephemeral)
        .access(Access::full())
        .backend_url("https://api.tinyhumans.ai")
        .build()?;                     // ← core is now created and running

    let response = harness.run("Explain how Harness::builder works.").await?;
    println!("AI says: {}", response.message);
    Ok(())
}

```

### Multi-Turn Session Management

For conversational continuity, reuse the same core across multiple turns:

```rust
let harness = Harness::builder()
    .provider(Provider::openai_compatible("https://api.openai.com/v1", "sk-..."))
    .workspace(Workspace::Dir("./my_workspace".into()))
    .access(Access::full())
    .backend_url("https://api.tinyhumans.ai")
    .build()?;                     // core lives for the entire program duration

let mut session = harness.session();   // optional explicit session handle
for prompt in ["First question?", "Second question?"] {
    let reply = session.turn(prompt).send().await?;
    println!("→ {}", reply.message);
}

```

### Customizing Tool Visibility

Control which tool schemas the LLM receives by configuring tool groups before composition:

```rust
let harness = Harness::builder()
    .provider(Provider::openai_compatible("...", "..."))
    .tool_groups(ToolGroups::with("media", GroupMode::Off))
    .skills_dir("./skills")
    .build()?;

```

## Summary

- **`Harness::builder()`** in [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs) initiates a three-stage composition process for library embedding.
- **Axis configuration** uses fluent methods to set providers, workspaces, access tiers, and tool groups before core instantiation.
- **`CoreBuilder`** in [`src/core/runtime/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/runtime/builder.rs) translates builder state into a running core by selecting service sets, domain sets, and tool visibility rules.
- The resulting **embedded core** runs in-process, eliminating network latency while maintaining parity with the full OpenHuman desktop runtime.

## Frequently Asked Questions

### What source file implements the `Harness::builder()` method?

The `Harness::builder()` static method and the associated `Builder` struct are implemented in [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs). This file contains the fluent API for configuring providers, workspaces, and access tiers before core construction.

### How does workspace configuration affect the embedded core?

The `workspace()` method accepts `Workspace::Ephemeral` for temporary storage, `Workspace::Dir(path)` for persistent state on disk, or `Workspace::Inherit` to reuse an existing workspace. The builder validates that directory paths exist during the configuration phase, ensuring the core receives valid storage parameters.

### What is the difference between service sets and domain sets during core construction?

According to [`src/core/runtime/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/runtime/builder.rs), **service sets** configure infrastructure capabilities like HTTP RPC, socket communication, and cron scheduling, while **domain sets** register business logic controllers for agents, memory, threads, and optional features like skills or web3 integrations. Both sets are selected based on the builder's accumulated configuration before the asynchronous runtime spawns.

### Can I run multiple independent prompts on the same composed core?

Yes. After calling `build()`, the `Harness` instance owns a long-lived core. You can execute `harness.run(prompt)` for single-turn interactions or create a persistent session via `harness.session()` and chain `session.turn(prompt).await` calls to maintain conversational context across multiple prompts without reconstructing the core.