How TOML Config Flows into ConfigStruct with Environment Variable Overrides in OpenHuman

OpenHuman loads workspace TOML settings, merges them with built-in defaults, and applies OPENHUMAN_ environment variables to produce the final Config struct, with env vars taking precedence.*

The OpenHuman repository implements a deterministic configuration pipeline that transforms static TOML files into a runtime Config struct. This system allows developers to override any setting through environment variables using a predictable naming convention. Understanding this flow is essential for customizing OpenHuman deployments without modifying source code.

The Three-Stage Configuration Pipeline

The loading process follows a strict precedence order: TOML → Defaults → Environment Variables. Each stage is handled by specific modules in src/openhuman/config/schema/.

Stage 1: Parsing the TOML File

In src/openhuman/config/schema/load/impl_load.rs, the loader uses the toml crate to parse the workspace's openhuman.toml. The parsed document converts into internal schema types (SchemaDefs) representing the configuration structure before any merging occurs.

Stage 2: Merging with Defaults

After parsing, the system calls merge_with_defaults from src/openhuman/config/schema/helpers.rs. This function walks every field of the schema and fills missing values using hard-coded defaults defined in src/openhuman/config/schema/defaults.rs. This ensures the configuration is complete even when the TOML file omits optional settings.

Stage 3: Applying Environment Variable Overrides

The env_overlay module in src/openhuman/config/schema/load/env_overlay.rs inspects process environment variables matching the OPENHUMAN_<SECTION>_<KEY> pattern (consistent with the .env.example file convention). For each match, it parses and injects the value, overriding both TOML and default settings. This overlay occurs before final Config struct construction, guaranteeing that environment variables always take precedence.

ConfigStruct Definition and Public API

The fully populated data wraps in the Config struct defined in src/openhuman/config/schema/types.rs. This type is re-exported through src/openhuman/config/mod.rs as openhuman::config::Config, serving as the canonical API for the rest of the system. Components retrieve values via methods like config.voice_server() or config.proxy(), which delegate to the merged underlying data.

Runtime Loading and Error Handling

The orchestration happens in src/openhuman/config/ops/loader.rs during core initialization. The configuration loads once and caches for subsequent access, avoiding repeated file I/O.

If an environment variable cannot be parsed into the expected type, the loader records a warning but does not abort the process. The fallback value—either from the TOML file or the built-in defaults—is preserved, maintaining system robustness against malformed env entries.

Accessing Configuration at Runtime

Once the core initializes, access the Config instance through the core handle:

use openhuman::config::Config;

// Core builder implicitly loads the config
let core = openhuman::core::CoreBuilder::new()
    .domains(openhuman::core::DomainSet::full())
    .build()
    .await?;

// Access a concrete setting – e.g., the HTTP proxy URL
let proxy_url = core.config().proxy().url();
println!("Proxy: {}", proxy_url);

Overriding Values with Environment Variables

Set variables following the OPENHUMAN_<SECTION>_<KEY> pattern before starting the core:

// Assuming the environment contains:
// OPENHUMAN_PROXY_URL=https://my-proxy.example.com

let cfg: &Config = core.config();
assert_eq!(cfg.proxy().url(), "https://my-proxy.example.com");

Summary

  • TOML parsing occurs in impl_load.rs, converting openhuman.toml into SchemaDefs.
  • Default merging happens via merge_with_defaults in helpers.rs using values from defaults.rs.
  • Environment overlays are applied by env_overlay.rs, matching variables like OPENHUMAN_PROXY_URL.
  • The final Config struct is defined in types.rs and re-exported via mod.rs.
  • Error resilience ensures that invalid environment variables trigger warnings without crashing the system.
  • Lazy initialization in loader.rs loads the configuration once during core startup.

Frequently Asked Questions

How does OpenHuman determine the precedence of configuration sources?

OpenHuman applies a fixed three-layer precedence: parsed TOML values serve as the base, hard-coded defaults fill any missing fields, and environment variables override both previous layers. This hierarchy is enforced sequentially during the loading pipeline in src/openhuman/config/ops/loader.rs.

What naming convention must environment variables follow to override config values?

Environment variables must match the pattern OPENHUMAN_<SECTION>_<KEY>, mirroring the structure defined in the .env.example file. For example, to override the proxy URL, set OPENHUMAN_PROXY_URL. The env_overlay.rs module maps these names to specific schema paths during initialization.

What happens if an environment variable contains an invalid value?

The system emits a warning log but continues execution using the fallback value from either the TOML file or the built-in defaults. This design prevents a single malformed environment variable from crashing the entire OpenHuman core, as implemented in the error handling logic of env_overlay.rs.

Where is the Config struct defined and how do I import it?

The Config struct is defined in src/openhuman/config/schema/types.rs and publicly re-exported through src/openhuman/config/mod.rs. Import it using use openhuman::config::Config; to access the fully populated configuration after core initialization.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →