# Common Pitfalls When Embedding OpenHuman as a Library Using the Harness API

> Avoid runtime failures when embedding OpenHuman as a library with the Harness API. Learn about common pitfalls including identity, backend URLs, and workspace isolation.

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

---

**Embedding OpenHuman via the `Harness` API requires careful configuration of product identity, backend URLs, access tiers, and workspace isolation to avoid runtime failures ranging from silent header omissions to process singleton collisions.**

OpenHuman's Rust core exposes a powerful embedding interface through the `Harness` builder defined in [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs). While this API enables deep integration of agentic capabilities into external applications, several architectural constraints can trigger subtle failures if ignored. Understanding these pitfalls ensures reliable operation when embedding OpenHuman as a library.

## Missing Product Identity Causes Silent Header Omissions

The backend SDK in [`src/api/product.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/api/product.rs) relies on a global `ProductIdentity` to tag outgoing requests with the `x-sdk-name` header. If you instantiate a `BackendOAuthClient` before calling `set_product_identity`, the header remains unset, preventing the backend from attributing requests to your application.

**How to avoid it:** Set the product identity immediately at application startup, before any client construction:

```rust
use openhuman::api::{set_product_identity, ProductIdentity};

// Must occur before BackendOAuthClient creation
set_product_identity(ProductIdentity::new("myapp").unwrap());

```

## Backend URL Misconfiguration Triggers Session Expired Errors

Many core operations—including credential refresh and analytics pings—hit the TinyHumans backend regardless of your inference provider. If `backend_url` is omitted or unreachable, these calls fail with `SessionExpired` errors even when the primary LLM provider is operational.

**Configuration location:** [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs)

Always specify a reachable backend during harness construction:

```rust
let harness = Harness::builder()
    .backend_url("https://api.tinyhumans.com".into())
    // ... additional config
    .build()
    .await
    .expect("Failed to init Harness");

```

## Access and Autonomy Misconfiguration Blocks Operations

The `Access` struct in [`src/embed/harness/access.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/access.rs) defines permission tiers, but the accompanying `Autonomy` settings determine whether the core treats the current turn as originating from a trusted source. Default configurations or missing `Autonomy` settings result in the approval gate refusing writes, network calls, or tool installations.

**The fix:** Explicitly configure both components:

```rust
use openhuman::embed::harness::{Access, Autonomy};

let harness = Harness::builder()
    .access(Access::full())
    .autonomy(Autonomy::default())  // Ensures trusted root behavior
    // ...
    .build()
    .await?;

```

## Default Workspace Directories Leak Credentials

The `Workspace` controller in [`src/embed/harness/workspace.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/workspace.rs) determines where OpenHuman stores persistent state, credentials, and keyring data. Using the default path (typically under `~/.openhuman`) while expecting an isolated environment leads to unexpected credential sharing between distinct application instances.

**Isolation strategies:**

- **Ephemeral runs:** Use `Workspace::Ephemeral` for stateless, one-off executions
- **Dedicated directories:** Use `Workspace::Dir(PathBuf::from("./my_workspace"))` for persistent but isolated storage

## Provider Gate Failures Without Session Activation

Configuring a `Provider` in [`src/embed/harness/provider.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/provider.rs) sets the endpoint and credentials, but the core additionally verifies that the session is "active" via `verify_session_active`. If you specify the provider but omit the session initialization, the gate rejects operations.

**Complete provider setup:**

```rust
use openhuman::embed::harness::{Provider, Session};

let harness = Harness::builder()
    .provider(Provider::openai_compatible(
        "https://api.openai.com/v1".into(),
        "sk-my-key".into(),
    ).model("gpt-4o"))
    .session(Session::local("my-embed"))  // Required for gate verification
    // ...
    .build()
    .await?;

```

## Neglected MCP Configuration Breaks Tool Calls

MCP servers are optional components defined in [`src/embed/harness/mcp.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/mcp.rs). If your application enables tools that rely on a local MCP server but you never start the server (or forget to add it to the builder), RPC calls return `UNKNOWN_METHOD` errors rather than graceful degradation.

## Singleton Constraint Prevents Multiple Harness Instances

OpenHuman maintains process-wide singletons for the keyring master key, RPC bearer token, and event bus. Attempting to create a second `Harness` instance via `Harness::builder().build()` yields `HarnessError::AlreadyRunning` as defined in [`src/embed/harness/error.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/error.rs).

**Pattern for reuse:** Maintain a single static instance throughout the application lifecycle:

```rust
use std::sync::OnceCell;

static HARNESS: OnceCell<Harness> = OnceCell::new();

async fn get_harness() -> &'static Harness {
    HARNESS.get_or_init(|| async {
        Harness::builder()
            .provider(/* ... */)
            .backend_url(/* ... */)
            .build()
            .await
            .expect("Failed to create harness")
    }.await)
}

```

## Tokio Runtime Stack Overflow Risks

Background services and tool timeout mechanisms in [`src/embed/call.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/call.rs) spawn Tokio tasks. Using the default `#[tokio::main]` configuration without adjusting `AGENT_WORKER_STACK_BYTES` can cause stack overflow during nested sub-agent calls.

**Environment configuration:**

```bash
export AGENT_WORKER_STACK_BYTES=4194304  # 4MB or larger for deep recursion

```

Then launch your application within this configured runtime.

## Cargo Feature Gate Omissions Remove Tools Silently

OpenHuman uses Cargo feature gates (e.g., `voice`, `web3`, `flows`) defined in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) to conditionally compile domain controllers. Relying on a tool that lives behind a disabled feature gate results in the tool being omitted from the binary entirely, without runtime error indication.

**Dependency configuration:** Enable required features in your [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml):

```toml
[dependencies]
openhuman = { git = "https://github.com/tinyhumansai/openhuman", features = ["flows", "web3"] }

```

## Complete Working Example

The following demonstrates a properly configured harness that avoids the common pitfalls:

```rust
use openhuman::embed::harness::*;
use openhuman::api::{set_product_identity, ProductIdentity};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Set product identity before any client construction
    set_product_identity(ProductIdentity::new("myapp").unwrap());
    
    // 2. Configure stack size if using nested sub-agents
    std::env::set_var("AGENT_WORKER_STACK_BYTES", "4194304");
    
    // 3. Build harness with all required guards
    let harness = Harness::builder()
        .provider(Provider::openai_compatible(
            "https://api.openai.com/v1".into(),
            "sk-my-key".into(),
        ).model("gpt-4o"))
        .backend_url("https://api.tinyhumans.com".into())
        .workspace(Workspace::Dir("./isolated_workspace".into()))
        .access(Access::full())
        .autonomy(Autonomy::default())
        .session(Session::local("my-embed"))
        .services(ServiceSet::desktop())
        .domains(DomainSet::full())
        .build()
        .await?;
    
    // 4. Execute turn
    let reply = harness
        .run("Analyze this codebase structure.")
        .await?;
    
    println!("Result: {}", reply.content);
    
    // 5. Reuse harness for subsequent operations (do not rebuild)
    let follow_up = harness
        .turn("List any security issues found.")
        .session(&reply.session_id)
        .send()
        .await?;
    
    println!("Follow-up: {}", follow_up.content);
    
    Ok(())
}

```

## Summary

- **Initialize early:** Call `set_product_identity` before any `BackendOAuthClient` instantiation to ensure proper request attribution
- **Configure completely:** Specify `backend_url`, `Provider`, `Session`, `Access`, and `Autonomy` to prevent gate failures
- **Isolate state:** Use `Workspace::Ephemeral` or dedicated directories to avoid credential leakage
- **Respect singletons:** Maintain only one `Harness` instance per process; reuse via static references
- **Size the runtime:** Set `AGENT_WORKER_STACK_BYTES` appropriately when using nested sub-agents
- **Enable features:** Explicitly declare required Cargo features (`flows`, `web3`, etc.) in [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml)

## Frequently Asked Questions

### What happens if I forget to set the product identity before creating the harness?

The `x-sdk-name` header remains unset in backend requests, causing the TinyHumans API to reject or fail to attribute analytics calls. This manifests as authentication or tracking failures in [`src/api/product.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/api/product.rs) because the global `ProductIdentity` is read once at client construction time.

### Can I create multiple Harness instances for different users in the same process?

No. The OpenHuman core maintains process-wide singletons for the keyring, RPC bearer, and event bus as enforced in [`src/embed/harness/error.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/error.rs). Attempting a second `build()` call yields `HarnessError::AlreadyRunning`. You must reuse a single instance and manage multi-tenancy through session management rather than separate harnesses.

### Why do I get `SessionExpired` errors when my API key is valid?

This typically indicates a missing or unreachable `backend_url`. Even when using third-party providers like OpenAI, OpenHuman requires communication with the TinyHumans backend for credential refresh and session management, as implemented in [`src/embed/harness/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/embed/harness/builder.rs). Ensure the URL is reachable and correctly configured.

### How do I prevent tools from being silently unavailable?

Verify that the Cargo features required for your tools are enabled in your [`Cargo.toml`](https://github.com/tinyhumansai/openhuman/blob/main/Cargo.toml). Features like `flows`, `web3`, and `voice` gate the inclusion of domain controllers in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs). Without the feature enabled, the tool code is omitted at compile time, causing runtime `UNKNOWN_METHOD` errors when the agent attempts to invoke them.