How OpenHuman Enforces Privacy Mode at the Rust Core Level
OpenHuman enforces Privacy Mode in its Rust core by intercepting all inference provider instantiation at the dispatcher level, blocking any external network calls when PrivacyMode::LocalOnly is active.
The tinyhumansai/openhuman repository implements a zero-trust privacy architecture that prevents data egress through a centralized enforcement point in its Rust core. Understanding how Privacy Mode is enforced at OpenHuman's Rust core level reveals a design that guarantees local-only inference when configured, regardless of which integrations or tools are invoked.
PrivacyMode Configuration Schema
The privacy contract is defined in src/openhuman/config/schema/privacy.rs as a strongly-typed enum that controls data egress permissions across the entire application.
The Three Privacy Tiers
The PrivacyMode enum defines three distinct operational states:
- LocalOnly — No data may leave the device. All external model calls to cloud services, managed APIs, or CLI-delegated inference are blocked. Only local runtimes such as Ollama, LM Studio, MLX, or locally hosted OpenAI-compatible servers are permitted.
- Standard — The default balanced mode where external models and integrations are allowed as configured. No egress restrictions are applied.
- Sensitive — A reserved variant for future privacy slices that will implement redaction, PII detection, and user-approval flows. Currently, this behaves identically to
Standard.
Serialization and Defaults
The enum serializes to snake_case strings (local_only, standard, sensitive) to match the repository's TOML configuration conventions. When a [privacy] block or mode key is missing from the configuration file, Serde's #[default] implementation automatically falls back to PrivacyMode::Standard, ensuring the application remains functional without explicit user configuration.
Enforcement at the Inference Dispatcher
The critical enforcement point resides in the inference stack within src/openhuman/inference/*, specifically inside the provider resolution logic. Before any network request is issued, the system validates the active privacy mode against the requested provider's locality.
The resolve_provider Gate
The resolve_provider function acts as the single gatekeeper for all inference operations. According to the OpenHuman source code, the logic validates provider locality before instantiation:
use crate::openhuman::config::PrivacyMode;
use crate::openhuman::config::Config;
/// Resolve an inference provider. Returns an error when the
/// privacy mode forbids external calls.
pub fn resolve_provider(config: &Config) -> Result<Box<dyn Provider>, ProviderError> {
match config.privacy.mode {
PrivacyMode::LocalOnly => {
// Only allow providers that run completely locally.
if provider.is_local() {
Ok(provider)
} else {
Err(ProviderError::PrivacyViolation(
"External model calls are blocked by PrivacyMode::LocalOnly".into(),
))
}
}
// Standard and Sensitive currently permit any provider.
PrivacyMode::Standard | PrivacyMode::Sensitive => Ok(provider),
}
}
When PrivacyMode::LocalOnly is active, any attempt to instantiate a remote provider—whether OpenAI, Azure, or other hosted inference services—triggers ProviderError::PrivacyViolation. This check occurs in the core inference stack, ensuring that all code paths capable of causing data egress are guarded by the same privacy-mode gate.
Error Propagation to the RPC Layer
Violations propagate through the RPC layer with explicit error messaging. When a privacy violation occurs, the system returns a structured error response:
{
"error": "External model calls are blocked by PrivacyMode::LocalOnly"
}
This guarantees that clients receive clear, actionable feedback when privacy settings prevent an operation, rather than opaque connection failures or silent drops.
Configuring Privacy Mode in Practice
OpenHuman supports both static configuration through files and dynamic updates via RPC, allowing privacy posture adjustments without restarting the core.
Static Configuration via config.toml
To enforce local-only inference persistently, set the mode in your configuration file:
[privacy]
mode = "local_only" # blocks all outbound model calls
Runtime Updates via RPC
Applications can switch modes dynamically using the Core RPC client. The config_set method updates the active configuration in src/openhuman/config/ops/privacy.rs:
use openhuman_core::api::core::rpc::CoreRpcClient;
// Switch to Standard (default) mode
let _ = client
.call("config_set", json!({ "privacy": { "mode": "standard" } }))
.await?;
Handling Privacy Violations in Clients
Client applications should handle ProviderError::PrivacyViolation explicitly to guide users:
try {
const result = await coreRpcClient.call("inference_predict", {
prompt: "Summarize this document",
});
console.log(result);
} catch (e) {
if (e.message.includes("PrivacyMode::LocalOnly")) {
alert("Your privacy settings prevent remote inference. Switch to Standard mode to use cloud models.");
} else {
console.error(e);
}
}
Architecture and Security Guarantees
Because the privacy check lives in the centralized inference dispatcher—implemented in files such as src/openhuman/inference/provider.rs—the privacy posture cannot be bypassed by adding new integrations. Any new provider must be added to the is_local() predicate or explicitly allowed by a future privacy slice. This creates a single-source-of-truth privacy gate that consistently prevents user data from leaving the device when PrivacyMode::LocalOnly is selected.
The configuration operations in src/openhuman/config/ops/mod.rs expose these settings to the frontend and CLI, ensuring changes are persisted in the Config struct and immediately respected by the enforcement point.
Summary
- PrivacyMode is defined in
src/openhuman/config/schema/privacy.rswith variantsLocalOnly,Standard, andSensitive. - Enforcement occurs at the inference dispatcher level via
resolve_providerbefore any network request is issued. - LocalOnly mode blocks all non-local providers by checking the
is_local()predicate and raisingProviderError::PrivacyViolationfor external services. - Configuration can be set statically in
config.tomlor updated dynamically via RPC calls to the core. - Future-proofing ensures new integrations cannot bypass privacy controls because all providers must pass through the centralized dispatcher validation.
Frequently Asked Questions
What is PrivacyMode::LocalOnly in OpenHuman?
PrivacyMode::LocalOnly is a strict operational mode defined in the Rust core that prevents any data from leaving the local device. When active, it blocks all external model calls—including cloud APIs and managed services—and permits only local inference runtimes like Ollama or LM Studio. This mode is enforced at the provider resolution layer before any network connection is attempted.
How does the Rust core prevent external API calls when Privacy Mode is enabled?
The Rust core prevents external API calls through the resolve_provider function in the inference dispatcher. This function checks config.privacy.mode before instantiating any provider. If the mode is LocalOnly and the provider fails the is_local() check, the system immediately returns ProviderError::PrivacyViolation, stopping the request before network initialization.
Can Privacy Mode be bypassed by new integrations or custom tools?
No, Privacy Mode cannot be bypassed by new integrations because the enforcement point is centralized in the core inference stack. Any new provider must pass through the resolve_provider gate and implement the is_local() predicate. Because this validation occurs in the Rust core rather than individual integration layers, the privacy guarantee holds regardless of which tools or extensions are installed.
What happens when I try to use a cloud model in LocalOnly mode?
When you attempt to use a cloud model in LocalOnly mode, the inference dispatcher detects that the provider is not local and raises ProviderError::PrivacyViolation. This error propagates to the RPC layer, returning a JSON error message stating "External model calls are blocked by PrivacyMode::LocalOnly". Client applications receive this explicit error and can prompt the user to switch to Standard mode if remote inference is required.
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 →