How OpenHuman's Privacy Mode Prevents Inference Data from Leaving the Machine
OpenHuman's privacy mode enforces a runtime LocalOnly policy that atomically blocks every outbound network request, discards cloud-bound audio segments, and disables remote chat bridges before any inference data can egress the local machine.
OpenHuman, maintained by tinyhumansai, is an open-source framework that balances local inference with optional cloud-connected features. OpenHuman's privacy mode guarantees that prompts, audio, and model outputs remain on-device by gating all potential egress paths through a single live-policy lock. Because the mode is hot-swappable via RPC, users can switch to LocalOnly instantly without restarting the core.
Privacy Mode Architecture and Live Policy
The privacy setting originates in the user configuration (config.privacy.mode) and is injected into a global SecurityPolicy when the core initializes.
In src/openhuman/security/policy/types.rs, the policy struct holds the mode:
pub struct SecurityPolicy {
// ...,
pub privacy_mode: PrivacyMode,
}
At startup, the core copies this value into a process-wide RwLock managed by the live-policy layer in src/openhuman/security/live_policy.rs:
let mut guard = state.privacy_mode.write()?;
*guard = policy.privacy_mode;
This live_policy guard allows every component to read the active mode without reloading the entire configuration. When a user changes the setting through the openhuman.config_set_privacy_mode RPC handler defined in src/openhuman/config/rpc.rs, the system creates a new SecurityPolicy that differs only in privacy_mode and atomically replaces the locked value. This hot-swap design means the policy survives unrelated configuration reloads and remains effective until explicitly changed.
Network Egress Enforcement Points
Every tool that could transmit data off-device checks live_policy::current_privacy_mode() immediately before the actual network operation. If the active mode is LocalOnly, the operation aborts.
HTTP Request Guard
The generic HTTP tool in src/openhuman/tools/impl/network/http_request.rs blocks outbound requests before building an egress descriptor:
if matches!(live_policy::current_privacy_mode(), PrivacyMode::LocalOnly) {
tracing::debug!(target: "[http-request]", "blocked: local-only privacy mode");
return Err(Error::PrivacyMode);
}
This check prevents REST API calls, telemetry pings, and remote model inference from leaving the machine.
Web Fetch Tool
The async web-fetch implementation in src/openhuman/tools/impl/network/web_fetch.rs applies the identical gate:
if matches!(live_policy::current_privacy_mode(), PrivacyMode::LocalOnly) {
// block the fetch
}
Because both the synchronous HTTP tool and the async fetch tool enforce the same rule, no remote download can occur while privacy mode is active.
Voice Processing Pipeline
In src/openhuman/voice/always_on.rs, the always-on audio pipeline inspects the privacy flag before transmitting long-running segments:
if privacy_mode_is_enabled {
// drop audio segment and reset the processor
}
If privacy mode is on, the segment is discarded entirely, ensuring intermediate audio data never reaches a cloud transcription or inference service.
Web Chat Progress Bridge
The progress bridge in src/openhuman/web_chat/progress_bridge.rs contains a storage-level privacy gate that disables forwarding captured content to the backend:
// Storage-level privacy gate (#4454): capture_content (off by default)
With this bridge disabled, chat history and captured content remain purely local.
How to Toggle and Verify Privacy Mode
Users and developers can interact with the privacy mode through the RPC surface without restarting OpenHuman.
Query the Current Mode
In src/tui/controls.rs, the TUI queries the live state:
let privacy = runtime.invoke("openhuman.config_get_privacy_mode", json!({}));
match privacy {
Ok(mode) => { /* display current mode */ }
Err(_) => { /* handle error */ }
}
Set the Mode at Runtime
To atomically switch to LocalOnly, invoke the setter RPC:
runtime.invoke(
"openhuman.config_set_privacy_mode",
json!({ "mode": "LocalOnly" })
);
This call updates the RwLock in src/openhuman/security/live_policy.rs, and all subsequent egress checks immediately see the new value.
Add Privacy Checks to Custom Tools
Third-party tools can reuse the same gate by importing the live-policy module:
use openhuman::security::live_policy;
fn maybe_send_request() -> Result<()> {
if matches!(live_policy::current_privacy_mode(), PrivacyMode::LocalOnly) {
tracing::debug!("privacy mode active – aborting outbound request");
return Err(Error::PrivacyMode);
}
// normal request logic ...
Ok(())
}
For configuration reloads that need to refresh the policy without an RPC call, use the reload helper:
use openhuman::security::live_policy::reload_privacy;
fn apply_new_mode(new_mode: PrivacyMode) -> Result<()> {
reload_privacy(new_mode)?;
Ok(())
}
Summary
- OpenHuman's privacy mode is stored in
config.privacy.modeand injected into a globalSecurityPolicyat startup. - A process-wide
RwLockinsideopenhuman::security::live_policyholds the activePrivacyMode, allowing atomic, runtime hot-swaps. - The
openhuman.config_set_privacy_modeRPC updates the lock without restarting the core. - Every potential egress point—including HTTP requests, web fetches, voice audio segments, and web-chat bridges—reads
live_policy::current_privacy_mode()and aborts ifLocalOnlyis active. - Custom tools can import the same live-policy module to enforce consistent privacy guarantees.
Frequently Asked Questions
What happens to inference requests when OpenHuman's privacy mode is set to LocalOnly?
All outbound inference requests are blocked at the network layer. Both the HTTP request tool and the web fetch tool check live_policy::current_privacy_mode() before opening any connection and return Error::PrivacyMode immediately if LocalOnly is active.
Can I switch privacy modes without restarting OpenHuman?
Yes. The live-policy layer uses an RwLock that is atomically updated through the openhuman.config_set_privacy_mode RPC. As soon as the lock is written, every component sees the new mode, so no restart is required.
Does privacy mode affect local inference performance?
No. OpenHuman's privacy mode is purely an egress gate; it does not alter local model execution or throttle compute. It only prevents data from leaving the machine by blocking network operations and discarding audio segments destined for cloud services.
How does the voice pipeline handle audio when privacy mode is enabled?
In src/openhuman/voice/always_on.rs, long-running audio segments are dropped and the processor resets when the privacy flag is active. This ensures no audio buffer is queued for remote transcription or cloud inference.
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 →