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:
- Configuration – Use
Harness::builder()to construct aHarnessBuilderand specify providers, workspaces, access tiers, and runtime components. - Initialization – Call
.build().awaitto load configuration, spawn the Core runtime viaCoreBuilder, and return a ready-to-useHarness. - Execution – Invoke
.run(prompt).awaitto execute a single conversational turn and receive a structuredTurnResult.
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:
- Creates a lightweight
Sessionwith a local identifier. - Initializes a turn context via
core.turn(session). - Sends the prompt through
turn.send_prompt(). - Returns a
TurnResultpopulated withagent_message,tool_calls, andtranscriptfields.
The TurnResult struct provides structured access to:
agent_message– The final textual response from the language model.tool_calls– A vector ofToolCallobjects 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 publicHarnessstruct, therunmethod,TurnResult, and theHarnessBuilder::buildimplementation that wires the Core runtime.src/embed/harness/builder.rs– Implements the fluentHarnessBuilderstruct 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– UnderlyingCoreBuilderthatHarnessBuilderdelegates to for runtime initialization.
Summary
openhuman_core::Harnessserves 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).awaitto drive turn-by-turn conversations, returning aTurnResultcontaining the agent message, tool calls, and JSON transcript. - Headless deployments minimize overhead by specifying
ServiceSet::none()andDomainSet::harness()to disable unnecessary background services. - All implementation details reside in
src/embed/harness/mod.rsandsrc/embed/harness/builder.rs, with runnable examples available inexamples/run_turn.rsandexamples/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →