# How OpenHuman's DomainGroup System Enables Slim vs. Full Agent Runtimes

> Discover how OpenHuman's DomainGroup system builds slim or full agent runtimes by combining runtime presets and compile-time features. Create minimal harnesses or full desktop apps.

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

---

**OpenHuman's DomainGroup system combines runtime DomainSet presets with compile-time Cargo features to selectively enable only the agent capabilities you need, allowing you to build everything from minimal headless harnesses to full-featured desktop applications.**

The `tinyhumansai/openhuman` repository implements a modular architecture that organizes functionality into logical families called **Domain Groups**. This design solves the engineering challenge of shipping both lightweight embedded agents and comprehensive desktop runtimes without maintaining separate codebases or bloating binaries with unused dependencies.

## Understanding Domain Groups and Domain Sets

At the heart of the system is the **`DomainGroup`** enum defined in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) (lines 91-148). This enum categorizes every controller, tool, store, and subscriber into logical families such as **Agent**, **Memory**, **Web3**, **Voice**, and **Desktop**. Each component in the codebase is explicitly tagged with one of these groups during registration.

Runtime selection happens through the **`DomainSet`** struct, which acts as a filter for which groups remain active. The core builder provides three preset configurations:

- **`DomainSet::full()`**: Activates all 22 domain groups (Agent through Platform), enabling the complete product surface intended for shipping the full desktop application.
- **`DomainSet::harness()`**: Enables only the essential kernel families—**Agent**, **Memory**, **Threads**, **Config**, and **Security**—for embedding the core as a library, running headless bots, or executing CI tests.
- **`DomainSet::embedded()`**: Provides a middle ground used by the Tauri UI that omits heavy optional families while retaining desktop UI capabilities, offering a reduced footprint compared to the full set.

## Runtime Filtering Mechanism

The `CoreBuilder` wires the selected `DomainSet` into the core context during initialization. The dispatch layer automatically filters out any controller or tool whose group is turned off through a centralized mechanism.

In [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) (lines 47-66), the registration helpers **`push`** and **`push_cap`** check the active `DomainSet` before accepting any component. This means the rest of the codebase never needs to check feature flags directly; inactive groups are simply excluded from the runtime registry.

## Compile-Time Optimization with Cargo Features

Beyond runtime filtering, OpenHuman uses **Cargo feature gates** (e.g., `voice`, `web3`, `media`) to remove entire dependency trees at compile time. When a feature is disabled, the corresponding code modules are excluded from the binary entirely. This compile-time pruning combined with the runtime `DomainSet` allows you to ship **"slim"** binaries containing only the code paths you actually use.

## Building a Slim Agent Runtime

To create a minimal headless agent that excludes heavy domains like Web3 or Voice, use the harness preset with no background services:

```rust
use openhuman_core::core::runtime::{DomainSet, ServiceSet};
use openhuman_core::core::Builder as CoreBuilder;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    // Only the essential kernel families are enabled.
    let core = CoreBuilder::new()
        .domains(DomainSet::harness())   // slim domain set
        .services(ServiceSet::none())    // no background services
        .build()
        .await?;

    // Run a turn or invoke RPC as needed…
    Ok(())
}

```

This configuration corresponds to the implementation pattern found in [`src/core/runtime/builder.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/runtime/builder.rs), where `DomainSet::harness()` maps to the minimal set of kernel flags.

## Building the Full Desktop Runtime

For the complete application surface, switch to the full domain set and enable desktop services:

```rust
use openhuman_core::core::runtime::{DomainSet, ServiceSet};
use openhuman_core::core::Builder as CoreBuilder;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    // All domain groups are active – the complete product surface.
    let core = CoreBuilder::new()
        .domains(DomainSet::full())      // full domain set
        .services(ServiceSet::desktop()) // all background services
        .build()
        .await?;

    // The core now serves the full RPC schema, tools, UI, etc.
    Ok(())
}

```

The TUI runner in [`src/tui/runner.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/tui/runner.rs) (lines 118-124) demonstrates this pattern in practice, selecting groups like `DomainGroup::Channels` alongside the full set to power the desktop interface.

## Inspecting Active Domain Groups

You can verify which domains are active at runtime through the core context:

```rust
let active = core.context().domains();   // returns a `DomainSet`
println!("Active groups: {:?}", active.enabled_groups());

```

This is useful for debugging configuration issues or confirming that cargo features and DomainSet presets align correctly.

## Tool Classification and Domain Assignment

Every agent tool in the system is classified into a `DomainGroup` through the **`tool_group`** function in [`src/openhuman/tools/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/ops.rs) (lines 1200-1450). This function maps individual tool implementations—such as blockchain interactions or media processing—to their respective domains, ensuring the runtime filtering applies consistently across the entire tool surface.

## Summary

- **Domain Groups** are logical families (Agent, Memory, Web3, etc.) defined in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) that tag every component in the system.
- **DomainSet presets** (`full()`, `harness()`, `embedded()`) configure runtime availability without code changes.
- **Runtime filtering** occurs centrally in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) via `push`/`push_cap`, keeping feature checks out of business logic.
- **Cargo feature gates** provide compile-time code elimination for dependencies like voice or web3.
- **ServiceSet** (defined in [`src/core/runtime/services.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/runtime/services.rs)) works alongside DomainSet to control background service initialization.

## Frequently Asked Questions

### What is a DomainGroup in OpenHuman?

A DomainGroup is a categorical enum variant defined in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) that classifies functionality into families like Agent, Memory, or Voice. Every controller, tool, and subscriber registers itself with a specific group, allowing the runtime to filter components by category rather than maintaining individual feature flags throughout the codebase.

### How does DomainSet::harness() differ from DomainSet::embedded()?

`DomainSet::harness()` activates only the five kernel families (Agent, Memory, Threads, Config, Security) needed for headless operation, while `DomainSet::embedded()` includes additional groups required for the Tauri desktop UI but still excludes heavy optional domains like full media processing or Web3 support. The harness is intended for library embedding and testing, whereas embedded targets GUI applications with a moderate footprint.

### Can I combine compile-time features with runtime DomainSet selection?

Yes. Compile-time Cargo features (such as `voice` or `web3`) remove the underlying code and dependencies entirely when disabled, while the runtime `DomainSet` filters which registered components receive traffic. You should enable the cargo feature for any domain you might need, then use `DomainSet` to toggle availability dynamically without recompiling.

### Where does the runtime filtering logic live in the codebase?

The filtering occurs in [`src/core/all.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/all.rs) (lines 47-66) within the `push` and `push_cap` registration helpers. These functions check if a component's `DomainGroup` is present in the active `DomainSet` before adding it to the runtime registry, ensuring disabled groups are never invoked.