How to Use openhuman_core::Harness for Library Embedding in OpenHuman

The openhuman_core::Harness struct provides a typed, async-friendly API for embedding the full OpenHuman core runtime into Rust applications, enabling turn-by-turn chat sessions without spawning external processes.

OpenHuman supports both standalone Tauri-based deployment and direct library embedding for Rust developers. The Harness type—defined in src/embed/harness/mod.rs—wraps the complete Core runtime, including all background services, domain families, and tool packs, exposing a thin ergonomic layer for driving conversational agents programmatically.

Understanding the Harness Architecture

The Harness struct acts as a reference-counted handle to the underlying Core runtime. Because it stores the runtime inside an Arc<CoreHandle>, cloning a Harness instance is computationally cheap and safe to share across async tasks. According to the source code comments in src/embed/harness/mod.rs, the public API intentionally mirrors the CLI entry point but provides full type safety and async/await compatibility for library consumers.

The Harness lifecycle follows three distinct phases:

  1. Configuration – Use Harness::builder() to construct a HarnessBuilder and specify providers, workspaces, access tiers, and runtime components.
  2. Initialization – Call .build().await to load configuration, spawn the Core runtime via CoreBuilder, and return a ready-to-use Harness.
  3. Execution – Invoke .run(prompt).await to execute a single conversational turn and receive a structured TurnResult.

Building a Harness Instance

Construction begins with the HarnessBuilder, located in src/embed/harness/builder.rs. The builder implements a fluent API where each configuration method consumes self and returns the updated builder, allowing method chaining for ergonomic setup.

use openhuman::embed::harness::{Harness, HarnessBuilder};
use openhuman::openhuman::{Provider, Workspace};
use openhuman::openhuman::access::Access;

let harness = Harness::builder()
    .provider(Provider::openai_compatible("https://api.openai.com", "sk-…"))
    .workspace(Workspace::Ephemeral)
    .access(Access::full())
    .backend_url("https://api.tinyhumans.ai")
    .build()
    .await?;

The build() method—implemented in src/embed/harness/mod.rs—performs the heavy initialization work. It resolves configuration sources (environment variables override configuration files), constructs the CoreBuilder, and wires optional components such as MCP servers, autonomy settings, and security policies. If any required runtime component fails to initialize, build() returns an error immediately.

Key builder configuration methods include:

  • .provider(Provider) – Sets the LLM provider endpoint and credentials.
  • .workspace(Workspace) – Configures persistent or ephemeral storage for the session.
  • .access(Access) – Defines the permission tier (e.g., Access::full()).
  • .services(ServiceSet) – Selects which background services (RPC, socket, cron) to spawn.
  • .domains(DomainSet) – Chooses which domain families to initialize.
  • .tools(ToolGroups) – Specifies available tool packs for the agent.
  • .autonomy(AutonomySettings) and .policy(SecurityPolicy) – Configure runtime security constraints.

Running Conversational Turns

Once initialized, the Harness::run method drives individual chat turns. The method signature accepts any type implementing Into<String> for the prompt and returns a TurnResult containing the complete interaction transcript.

let result = harness.run("Summarize the OpenHuman architecture.").await?;
println!("Agent reply: {}", result.agent_message);

As implemented in src/embed/harness/mod.rs, the run method:

  1. Creates a lightweight Session with a local identifier.
  2. Initializes a turn context via core.turn(session).
  3. Sends the prompt through turn.send_prompt().
  4. Returns a TurnResult populated with agent_message, tool_calls, and transcript fields.

The TurnResult struct provides structured access to:

  • agent_message – The final textual response from the language model.
  • tool_calls – A vector of ToolCall objects recording every tool invocation, including name, arguments, and return values.
  • transcript – A JSON representation of the full conversation history suitable for persistence or inspection.

Headless Embedding and Runtime Customization

For background workers or CLI tools that require the Core logic without UI-related overhead, OpenHuman supports headless configuration via explicit ServiceSet and DomainSet selection. The example in examples/embed_headless.rs demonstrates this pattern:

use openhuman::core::runtime::builder::{ServiceSet, DomainSet, ToolGroups};

let harness = Harness::builder()
    .provider(Provider::openai_compatible("https://api.openai.com", "sk-…"))
    .workspace(Workspace::Ephemeral)
    .access(Access::full())
    .services(ServiceSet::none())      // Disables RPC, socket, and cron services
    .domains(DomainSet::harness())     // Loads only core domains required for embedding
    .tools(ToolGroups::packed())       // Includes default tool packs
    .build()
    .await?;

This configuration minimizes resource consumption by skipping the full service suite while retaining the conversational capabilities provided by the harness domains. Developers can mix and match ServiceSet, DomainSet, and ToolGroups variants to compose exact runtime requirements.

Key Source Files and Implementation Details

Understanding the module structure helps when extending or debugging embedded deployments:

  • src/embed/harness/mod.rs – Defines the public Harness struct, the run method, TurnResult, and the HarnessBuilder::build implementation that wires the Core runtime.
  • src/embed/harness/builder.rs – Implements the fluent HarnessBuilder struct with chainable setters for provider, workspace, access tiers, and runtime components.
  • examples/run_turn.rs – Minimal demonstration of constructing a harness and executing a single conversational turn.
  • examples/embed_headless.rs – Reference implementation for headless deployments with disabled UI services.
  • src/core/runtime/builder.rs – Underlying CoreBuilder that HarnessBuilder delegates to for runtime initialization.

Summary

  • openhuman_core::Harness serves as the primary entry point for embedding OpenHuman as a library, wrapping the complete Core runtime in a cheap-to-clone handle.
  • Initialization follows a builder pattern via Harness::builder(), supporting configuration of providers, workspaces, service sets, and security policies before calling .build().await.
  • Execution uses Harness::run(prompt).await to drive turn-by-turn conversations, returning a TurnResult containing the agent message, tool calls, and JSON transcript.
  • Headless deployments minimize overhead by specifying ServiceSet::none() and DomainSet::harness() to disable unnecessary background services.
  • All implementation details reside in src/embed/harness/mod.rs and src/embed/harness/builder.rs, with runnable examples available in examples/run_turn.rs and examples/embed_headless.rs.

Frequently Asked Questions

How does Harness differ from the OpenHuman CLI?

The CLI spawns a separate process that manages its own lifecycle and configuration parsing, while Harness provides a typed, programmatic API for direct integration into Rust applications. The Harness API mirrors CLI capabilities but operates entirely in-process via async Rust, making it suitable for library embedding where process isolation is undesirable.

Can I share a Harness instance across multiple async tasks?

Yes. The Harness struct holds the Core runtime inside an Arc<CoreHandle>, making it cheap to clone and safe to share across concurrent tasks. Each call to run() creates a fresh Session instance, ensuring turn isolation while sharing the underlying runtime resources.

What configuration options are available for headless embeddings?

Developers can disable UI-related services by passing ServiceSet::none() to the builder and restrict domains to the minimal set using DomainSet::harness(). Additional customization includes selecting specific ToolGroups, configuring AutonomySettings for agent permissions, and defining SecurityPolicy constraints—all through the HarnessBuilder interface defined in src/embed/harness/builder.rs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →