How to Use the OpenHuman Harness API to Embed the Agent in a Rust Binary
The OpenHuman Harness API exposes a builder-pattern façade that creates a fully-configured agent runtime, allowing you to embed the OpenHuman agent into any Rust binary with async methods for single-turn prompts and multi-turn conversations.
The tinyhumansai/openhuman repository distributes its core agent logic as a library crate named openhuman. The Harness type—re-exported at the crate root—serves as the primary entry point for programmatic use. Located in src/openhuman/agent/harness/mod.rs, this type provides a minimal, async API that mirrors the runtime used by the official desktop UI.
Understanding the Harness Architecture
The Harness type implements a builder-pattern lifecycle. Calling Harness::builder() returns a HarnessBuilder (defined in src/openhuman/agent/harness/session/builder/mod.rs) that captures configuration for the LLM provider, workspace persistence, and security policy. Once configured, invoking .build().await yields an initialized Harness instance ready to process prompts.
The builder accepts four critical configuration domains:
- Provider selection – Determines the LLM backend and model via
src/openhuman/agent/harness/provider.rs - Workspace handling – Controls where the agent stores its action directory and artifacts via
src/openhuman/agent/harness/workspace.rs - Access tier – Defines autonomy levels (
full,supervised,readonly) viasrc/openhuman/agent/harness/access.rs - Backend URL – Points to the TinyHumans backend for authentication and billing, defaulting to production
Configuring the Provider and Workspace
Selecting an LLM Provider
The Provider enum abstracts multiple LLM backends. Use Provider::openai_compatible() to target OpenAI or any OpenAI-compatible endpoint:
Provider::openai_compatible("https://api.openai.com/v1", "sk-…")
.model("gpt-4o")
This logic lives in src/openhuman/agent/harness/provider.rs. The provider configuration supports custom endpoints, enabling use with local models or alternative cloud providers that adhere to the OpenAI API specification.
Choosing Workspace Persistence
The Workspace enum in src/openhuman/agent/harness/workspace.rs offers three variants:
Workspace::Ephemeral– Creates a temporary directory deleted on process exit, ideal for stateless automationWorkspace::Dir(path)– Pins a persistent location on disk for the action directory and tool outputsWorkspace::Inherit– Uses an existing workspace context
The workspace location determines where sandboxed tools write files and where the agent stores its artifact cache.
Setting Access Tiers
Security policies are enforced via the Access type in src/openhuman/agent/harness/access.rs:
Access::full()– Grants unrestricted tool usage and file system mutationAccess::supervised()– Requires confirmation for destructive actionsAccess::readonly()– Blocks write operations entirely
The selected tier is encoded into the core's SecurityPolicy during build().
Running Single-Turn and Multi-Turn Conversations
Single-Turn Execution
For one-shot prompts, use harness.run(prompt).await, defined in src/openhuman/agent/harness/session/turn/mod.rs. This method initializes a session, sends the prompt, and returns the complete reply.
use openhuman::{Harness, Provider, Workspace, Access};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let harness = Harness::builder()
.provider(
Provider::openai_compatible(
"https://api.openai.com/v1",
std::env::var("OPENAI_API_KEY")?,
)
.model("gpt-4o-mini"),
)
.workspace(Workspace::Ephemeral)
.access(Access::full())
.backend_url("https://api.tinyhumans.ai")
.build()
.await?;
let reply = harness.run("Summarize the OpenHuman architecture.").await?;
println!("Agent reply:\n{}", reply.message);
Ok(())
}
Multi-Turn Conversation Handling
For stateful interactions, harness.turn(prompt).await returns a TurnHandle that persists session context. The handle exposes methods to continue the conversation, inspect the session ID, or retrieve the full transcript.
use openhuman::{Harness, Provider, Workspace, Access, TurnHandle};
#[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")?,
)
.model("gpt-4o"),
)
.workspace(Workspace::Dir("./my_workspace".into()))
.access(Access::full())
.build()
.await?;
let mut turn: TurnHandle = harness.run("You are a helpful assistant.").await?.into();
for user_msg in [
"What is the purpose of the `Harness` builder?",
"Give me a concise example of tool usage.",
] {
turn = turn.turn(user_msg).await?;
println!("Assistant: {}", turn.reply().message);
}
let transcript = turn.transcript().await?;
println!("Full transcript ({} turns):", transcript.len());
for entry in transcript {
println!("> {}", entry.message);
}
Ok(())
}
The transcript retrieval logic resides in src/openhuman/agent/harness/session/transcript.rs, while turn state management is handled in src/openhuman/agent/harness/session/turn/mod.rs.
Enabling Sandboxed Tool Execution
To execute sandboxed tools—such as the python_exec tool—set the OPENHUMAN_SANDBOX_MODE environment variable before building the harness. The sandbox context is managed in src/openhuman/agent/harness/sandbox_context.rs.
use openhuman::{Harness, Provider, Workspace, Access};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
std::env::set_var("OPENHUMAN_SANDBOX_MODE", "sandboxed");
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())
.build()
.await?;
let reply = harness.run(
"Run this Python code and return its output:\n```python\nprint(2 * 7)\n```"
).await?;
println!("Tool output: {}", reply.message);
Ok(())
}
Tool registration occurs in src/openhuman/tools/registry.rs, while result artifacts are processed through src/openhuman/agent/harness/tool_result_artifacts/mod.rs.
Summary
Embedding the OpenHuman agent requires minimal boilerplate:
- Import
openhuman::Harnessfrom the crate root - Chain configuration methods on
Harness::builder()to select providers, workspace type, and access tier - Await
build()to instantiate the runtime - Use
run()for single-turn requests orturn()for multi-turn sessions with transcript persistence - Enable
OPENHUMAN_SANDBOX_MODEenvironment variable before instantiation to allow tool execution
Frequently Asked Questions
What is the difference between run() and turn() methods in the Harness API?
run() executes a single prompt within a new session and returns the final message, making it ideal for one-shot tasks. turn() initiates or continues a multi-turn conversation, returning a TurnHandle that preserves session state across multiple async calls and exposes the transcript history.
How do I persist agent state between process restarts?
Pass Workspace::Dir(path) to the builder instead of Workspace::Ephemeral. According to the implementation in src/openhuman/agent/harness/workspace.rs, this pins the action directory and artifact storage to a specific filesystem location, allowing the agent to resume from existing state on subsequent process launches.
Can I use the OpenHuman Harness API with local LLMs or only cloud providers?
You can use any OpenAI-compatible endpoint. The Provider::openai_compatible() method in src/openhuman/agent/harness/provider.rs accepts a custom base URL, enabling integration with local inference servers (such as Ollama or vLLM) that expose the OpenAI API schema, in addition to commercial cloud providers.
How do I restrict the agent's ability to modify files?
Set the access tier to Access::readonly() or Access::supervised() via the builder method defined in src/openhuman/agent/harness/access.rs. The readonly tier blocks all destructive tool invocations, while supervised requires explicit confirmation before executing write operations, encoding these constraints into the core SecurityPolicy.
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 →