How OpenHuman Privacy Mode Guarantees Local-Only Inference
OpenHuman Privacy Mode enforces a LocalOnly setting that blocks cloud inference providers and prevents any external data transmission by running pure-function checks before any network I/O occurs.
The tinyhumansai/openhuman project implements a privacy-first architecture that separates privacy policy from agent autonomy, ensuring that when OpenHuman Privacy Mode is activated, no user data can leave the local machine. This guarantee is enforced through a two-layer validation system that intercepts both model inference requests and external network calls before they execute.
The Architecture: Separating Policy from Autonomy
In the OpenHuman codebase, privacy policy determines whether user data may leave the device, while autonomy controls what actions the agent may take. This separation allows the system to restrict data flow without limiting the agent's internal reasoning capabilities. The PrivacyMode enum defined in src/openhuman/config/schema/privacy.rs provides three states: LocalOnly, Standard, and Sensitive, with LocalOnly representing the strictest guarantee.
Layer 1: Enforcing Local-Only Inference Providers
Before any model inference occurs, the provider factory validates the current privacy mode. Located in src/openhuman/inference/provider/factory.rs, this factory contains the local_only_violation and enforce_local_only_inference logic that reads the process-global policy via live_policy::current_privacy_mode().
When LocalOnly is active, the factory maintains an allowlist of pure-local runtimes including Ollama, LM Studio, MLX, and local OpenAI-compatible servers. Any attempt to instantiate a cloud-hosted provider triggers an early bail! that aborts the turn before any network connection is established.
// src/openhuman/inference/provider/factory.rs
match provider {
// Only allow local runtimes when privacy mode is LocalOnly
Provider::Ollama | Provider::LmStudio | Provider::Mlx => { /* OK */ }
_ => {
if mode == PrivacyMode::LocalOnly {
bail!("Local-only privacy mode is active – external provider blocked");
}
}
}
Layer 2: Blocking Unauthorized Data Egress
Even if inference is local, tools and integrations might attempt external network calls. OpenHuman prevents this through the egress enforcement system in src/openhuman/security/egress/enforce.rs. Every network-bound operation constructs an EgressDescriptor that classifies the request type and destination.
The enforce_egress function calls local_only_blocks(mode, desc) to evaluate whether the operation should proceed. If the mode is LocalOnly and the descriptor indicates an external transfer (desc.is_external) that is not a control-plane request (such as sign-in or billing), the system rejects the call with a clear error message.
// src/openhuman/security/egress/enforce.rs
let desc = EgressDescriptor {
provider_slug: "http".into(),
service: "api.example.com".into(),
reason: EgressReason::Integration,
is_external: true,
// …other fields…
};
if let Err(e) = enforce_egress(&desc) {
// The request is aborted; the error message explains why
return Err(e);
}
This check occurs in local_only_tool_block and related functions, ensuring that data-sending operations cannot bypass the inference gate through alternative routes.
The Live Policy System
Both enforcement layers rely on the process-global live policy defined in src/openhuman/security/live_policy.rs. This module maintains the current privacy mode in a thread-safe RwLock<PrivacyMode>, allowing instant propagation of policy changes to all subsequent checks.
When users modify settings through the UI, RPC handlers in src/openhuman/config/ops/privacy.rs—specifically config_get_privacy_mode and config_set_privacy_mode—update the policy atomically.
// Accessing the current privacy mode anywhere in the codebase
use openhuman::security::live_policy::current_privacy_mode;
let mode = current_privacy_mode(); // PrivacyMode::LocalOnly, Standard, or Sensitive
The React Settings UI invokes these handlers via the core RPC client:
import { coreRpcClient } from "@/services/coreRpcClient";
async function setPrivacyMode(mode: "local_only" | "standard") {
await coreRpcClient.invoke("openhuman.config_set_privacy_mode", { mode });
}
Changes take effect immediately for all new operations, while in-flight requests complete under their original policy.
Fail-Closed Design and Thread Safety
OpenHuman Privacy Mode implements a fail-closed philosophy: any unknown or future egress route is treated as user data and therefore blocked under LocalOnly. Because the validation functions are pure functions that execute before any network I/O, the guarantee holds even for code running on separate threads.
Network tools in src/openhuman/tools/impl/network/mod.rs check current_privacy_mode before executing, ensuring consistent enforcement across the entire tool ecosystem. End-to-end tests in app/test/playwright/specs/settings-privacy-mode.spec.ts verify that the UI correctly reflects and enforces these policy changes.
Summary
- Two-layer validation: OpenHuman Privacy Mode enforces
LocalOnlyat both the inference provider selection (factory.rs) and external egress enforcement (enforce.rs) layers. - Pure-local inference: Only Ollama, LM Studio, MLX, and compatible local servers are permitted; cloud providers trigger immediate rejection via
bail!. - Egress blocking: All external data transfers are blocked unless they are control-plane operations (sign-in, billing), evaluated via
EgressDescriptorinspection inlocal_only_blocks. - Atomic updates: The live policy system in
live_policy.rspropagates mode changes instantly viaRwLock, with RPC handlers inconfig/ops/privacy.rsmanaging persistence. - Fail-closed safety: Unknown routes are blocked by default, and checks run as pure functions before network I/O, ensuring thread-safe, local-only operation.
Frequently Asked Questions
What is OpenHuman Privacy Mode?
OpenHuman Privacy Mode is a configuration setting that determines whether user data may leave the local device. When set to LocalOnly as defined in src/openhuman/config/schema/privacy.rs, the system enforces strict local-only operation by blocking all cloud inference providers and external data transfers through the provider factory and egress enforcement layers.
How does OpenHuman Privacy Mode differ from Standard mode?
Standard mode allows the agent to use cloud-hosted inference providers and external tools that transmit data to third-party services. In contrast, when Privacy Mode is set to LocalOnly, the enforce_local_only_inference function in src/openhuman/inference/provider/factory.rs and the local_only_blocks function in src/openhuman/security/egress/enforce.rs reject any operation that would transmit data off-device, restricting inference to local runtimes like Ollama or MLX.
Can network tools still function in LocalOnly mode?
Network tools that attempt to send user data to external services are blocked by the local_only_tool_block logic in src/openhuman/security/egress/enforce.rs. However, control-plane requests such as authentication or billing verification may still be permitted if explicitly classified as non-external in the EgressDescriptor. Standard web-fetching or API-calling tools will fail with a clear error message when LocalOnly is active.
How is the privacy mode setting persisted and synced?
The current privacy mode is stored in the process-global LivePolicy struct protected by an RwLock in src/openhuman/security/live_policy.rs. When changed via the Settings UI, the config_set_privacy_mode RPC handler in src/openhuman/config/ops/privacy.rs updates this value atomically. All subsequent inference and egress checks read from this global state via current_privacy_mode(), ensuring immediate synchronization across threads without requiring application restarts.
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 →