How Cargo Feature Gates Compose with Runtime DomainSet in OpenHuman
Cargo feature gates control compile-time code inclusion while DomainSet filters runtime domain activation, creating a two-layer system where features must be compiled in before they can be toggled at runtime.
OpenHuman employs a sophisticated two-axis configuration model that separates compile-time optimization from runtime flexibility. This architecture ensures minimal binary size through Cargo feature gates while maintaining operational versatility via the DomainSet axis. Understanding how these mechanisms compose allows developers to customize OpenHuman deployments across desktop, headless, and embedded environments without unnecessary recompilation.
The Two-Axis Configuration Model
OpenHuman's configuration system operates on distinct compile-time and runtime layers. Each layer controls different aspects of the system's behavior and resource utilization.
Compile-Time Feature Gates in Cargo.toml
Compile-time configuration is driven by Cargo feature gates defined in the root Cargo.toml under the [features] table and enumerated in scripts/ci/product-features.txt for production builds. These gates determine which code families and their transitive dependencies are included in the final binary.
When a feature such as web3, voice, or documents is disabled, the corresponding module is excluded from compilation entirely. This elimination extends to native dependencies like bitcoin, libgit2-sys, or cpal, ensuring zero binary-size cost for unused capabilities. According to the architecture documentation in AGENTS.md, this approach defines both a minimal kernel profile and a full product profile based on which gates are active during the build process.
Runtime DomainSet in the Core Builder
Runtime configuration is managed by the DomainSet type implemented in src/core/runtime/builder.rs. This axis determines which domain families are active during process execution, controlled through the CoreBuilder::domains() method.
The DomainSet filters which controllers appear in the JSON-RPC dispatcher, which tools are advertised to agents, and which stores and event-subscribers are instantiated. Even when a domain's code is compiled into the binary, the runtime set can hide it from the RPC surface or disable its background services. The mapping of DomainGroup variants to runtime flags lives in src/core/all.rs, where each variant corresponds to a specific functional domain like Web3 or Voice.
Composition Rules: How the Axes Interact
The relationship between compile-time feature gates and runtime DomainSet follows strict dependency rules. Feature gates act as the primary filter, while DomainSet provides secondary runtime filtering.
Feature gates are the mandatory first layer. If a Cargo feature is disabled at compile-time, the corresponding DomainGroup variant cannot be instantiated at runtime because the underlying code does not exist in the binary. This hard dependency guarantees that no binary-size or native-dependency cost is incurred for disabled features.
DomainSet is the optional second layer. When a feature is enabled at compile-time, the domain's code is present, but DomainSet can still disable it for a specific process. In this state, the binary retains the code but behaves as if the domain never existed. This allows a single compiled binary to run in different modes—such as a full desktop application versus a minimal headless harness—without recompilation.
The axes are orthogonal but inter-dependent. If a feature is off at compile-time, the runtime DomainSet flag is irrelevant. Conversely, if a feature is on but the runtime set disables the domain, the code remains dormant in the binary.
Implementation Details from the OpenHuman Source Code
The composition logic is implemented through guarded code patterns in the core runtime builder. In src/core/runtime/builder.rs, the CoreBuilder accepts a DomainSet that is applied during construction:
// In src/core/runtime/builder.rs
pub fn domains(mut self, set: DomainSet) -> Self {
self.context.domains = set;
self
}
// Runtime check during domain registration
if self.context.domains.contains(DomainGroup::Web3) {
// register web3 controllers, tools, stores…
}
The DomainGroup enum variants are declared in src/core/all.rs, where each variant is matched in the domain registration block. This file serves as the central registry that connects compile-time features to runtime domain groups.
Practical Configuration Examples
Building a Minimal Binary
To create a lightweight binary with only specific domains, disable default features and select onlyrequired capabilities at compile-time:
# Cargo.toml snippet – disabling heavy features at compile-time
[features]
default = ["voice", "web3", "documents"] # product profile
# To build a minimal binary:
# cargo build --no-default-features --features "flows"
Runtime Domain Selection
Once compiled, the same binary can operate in different modes by specifying the DomainSet at launch:
use openhuman_core::embed::CoreBuilder;
use openhuman_core::core::runtime::{DomainSet, ServiceSet};
// Full desktop mode: activate all compiled-in domains
let core = CoreBuilder::new()
.domains(DomainSet::full()) // runtime: enable every compiled domain
.services(ServiceSet::desktop()) // start HTTP RPC, socket.io, etc.
.build()
.await?;
// Headless harness mode: only core kernel domains
let core = CoreBuilder::new()
.domains(DomainSet::harness()) // only Agent, Memory, Threads, Config, Security
.services(ServiceSet::none()) // no background services
.build()
.await?;
Environment-Based Runtime Override
The binary can read domain configuration from environment variables or CLI arguments:
# Launching with a runtime domain set override
OPENHUMAN_DOMAIN_SET=harness ./target/release/openhuman-core
Why OpenHuman Separates Compile-Time and Runtime Configuration
This dual-axis design serves two critical engineering requirements. Binary size control is achieved through feature gates that eliminate heavy native dependencies entirely when not needed. Operational flexibility is provided by DomainSet, allowing the same artifact to function as a full desktop application, a headless CLI harness, or a minimal test fixture through runtime flags alone.
The separation ensures that CI/CD pipelines can build a single product binary defined in scripts/ci/product-features.txt while deployment scripts can fine-tune behavior per-environment using DomainSet::full(), DomainSet::harness(), or DomainSet::none() presets.
Summary
- Compile-time gates in
Cargo.tomldetermine code inclusion and native dependency linking; disabled features remove their correspondingDomainGroupvariants entirely from the runtime registry. - Runtime DomainSet in
src/core/runtime/builder.rsfilters domain activation after compilation, controlling RPC visibility and tool availability without binary modification. - Composition order is strict: features must be enabled at compile-time before DomainSet can toggle them at runtime.
- Practical benefit is the ability to ship one optimized binary that adapts to desktop, server, or test environments through configuration rather than recompilation.
Frequently Asked Questions
What happens if I enable a domain in DomainSet but disabled its feature at compile-time?
The domain will not be available. If the Cargo feature is disabled, the corresponding code is not compiled into the binary, making the DomainGroup variant unavailable for runtime instantiation. The DomainSet check will silently skip registration because the underlying modules do not exist in the artifact.
Where are the product feature sets defined for OpenHuman releases?
Production feature configurations are defined in scripts/ci/product-features.txt and the [features] table of the root Cargo.toml. These files specify the default feature set shipped with the desktop application, while the DomainSet presets like DomainSet::full() and DomainSet::harness() are implemented in src/core/runtime/builder.rs.
Can I change the active domains without recompiling OpenHuman?
Yes. As long as the features were enabled at compile-time, you can switch between DomainSet::full(), DomainSet::harness(), or custom domain combinations at runtime by passing different values to CoreBuilder::domains() or setting the appropriate environment variables before launching the binary.
How does DomainSet affect JSON-RPC controller registration?
When a domain is excluded from the DomainSet, its controllers are omitted from the JSON-RPC dispatcher in src/core/all.rs. This results in unknown-method errors for RPC calls targeting that domain, effectively hiding the functionality from API consumers while keeping the underlying code present in the binary for potential future activation.
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 →