How the Command Permission Model Interacts with Autonomy Tiers in OpenHuman
OpenHuman combines a command classification system with session-based autonomy tiers to enforce fine-grained access control, where every incoming command is classified into a CommandClass and then evaluated against the current Autonomy tier to produce an Allow, Prompt, or Block decision.
In the tinyhumansai/openhuman repository, the interaction between the command permission model and autonomy tiers forms the core security architecture that protects the host environment. This system classifies every RPC method and tool invocation into risk categories, then evaluates each operation against configurable trust levels to determine whether execution proceeds silently, requires user approval, or is forbidden entirely.
Command Classification and Autonomy Tiers Overview
The security model relies on two orthogonal concepts that work together at runtime: Command Classes that categorize operations by risk, and Autonomy Tiers that define session-wide trust boundaries.
CommandClass Categories
Every incoming command is classified into a specific CommandClass based on its potential impact on the system. The core implementation in src/openhuman/security/command.rs defines five distinct categories:
Read– Operations that only retrieve information without side effectsWrite– Modifications to files or state (default fallback for unmatched commands)Network– Outbound connections and remote resource fetchingInstall– Package installation and tool deploymentDestructive– Irreversible operations likerm -rfor workspace deletion
Any command that does not match the classification patterns automatically falls back to Write, ensuring conservative permissions by default. Additionally, system-level directories such as credential stores are always blocked via the is_always_forbidden guard, regardless of classification.
Autonomy Tier Structure
The Autonomy struct, defined in src/openhuman/security/autonomy.rs, represents the session's trust level through a matrix of tiers and modifier flags:
- Base tiers:
readonly,supervised,full - Modifier flags:
workspace_only,trusted_roots,allow_tool_install
These tiers are stored in the core context and consulted by the permission gate for every operation. A session running with full autonomy plus the allow_tool_install flag, for example, can execute network and installation commands without interruption, while supervised autonomy requires explicit confirmation for potentially dangerous operations.
The Three-Step Permission Flow
When the core receives an RPC call in src/core/dispatch.rs, the permission system evaluates the request through a deterministic three-step pipeline:
- Command Classification – The system calls
classify_commandon the incoming method name to determine itsCommandClass - Tier Retrieval – The current session's
Autonomyvalue is fetched from the core context viactx.autonomy() - Gate Decision – The
gate_decision(class, tier)function applies enforcement rules to returnAllow,Prompt, orBlock
The gate applies specific logic based on the command class and tier combination:
Readcommands are generally permitted for all autonomy levelsWritecommands require at leastsupervisedautonomy;fullautonomy permits writes without promptingNetworkandInstalloperations need theallow_tool_installflag orfulltier, otherwise prompting or blocking occursDestructivecommands are blocked unless the tier isfulland the session is explicitly marked as trusted
Core Implementation Details
The permission gate is implemented in the security module with clear separation between classification logic and tier management. The following Rust pseudo-code illustrates the decision flow used in src/openhuman/security/command.rs:
// Core logic from src/openhuman/security/command.rs
fn handle_incoming_rpc(method: &str, ctx: &CoreContext) -> Result<RpcOutcome, RpcError> {
// 1️⃣ Classify the command
let cmd_class = classify_command(method);
// 2️⃣ Get the session's autonomy tier
let tier = ctx.autonomy();
// 3️⃣ Decide whether the command may proceed
match gate_decision(cmd_class, tier) {
Decision::Allow => run_the_command(method, ctx),
Decision::Prompt => request_user_approval(method, ctx),
Decision::Block => Err(RpcError::Forbidden),
}
}
The gate_decision function implements the matrix of rules that maps CommandClass and Autonomy combinations to enforcement actions. When the decision is Allow, execution proceeds immediately. A Prompt decision triggers a user approval request through the UI, while Block immediately returns an RpcError::Forbidden to the caller.
Frontend Integration
When the permission gate returns Decision::Prompt, the frontend renders an approval card that allows the user to approve or deny the specific operation. The React component handling this interaction communicates with the core RPC client to finalize the decision:
// Frontend approval prompt component
function ApprovalRequestCard({ request }: { request: ApprovalRequest }) {
const { approve, deny } = useCoreRpcClient();
return (
<Card>
<p>{request.description}</p>
<Button onClick={() => approve(request.id)}>Allow</Button>
<Button onClick={() => deny(request.id)}>Deny</Button>
</Card>
);
}
This separation ensures that the core security logic remains agnostic of the UI implementation while maintaining strict enforcement of the autonomy constraints.
Key Source Files
The permission system spans multiple files across the OpenHuman codebase:
src/openhuman/security/command.rs– Contains theclassify_commandfunction andgate_decisionlogic that implements the interaction between command classes and autonomy tierssrc/openhuman/security/autonomy.rs– Defines theAutonomystruct, tier constants (readonly,supervised,full), and helper methods for flag checkingsrc/core/dispatch.rs– Entry point where incoming RPC calls are routed through the permission gate before executionAGENTS.md– High-level documentation describing the command permission model and autonomy tier configuration options
Summary
- Command Classes categorize operations by risk level (
Read,Write,Network,Install,Destructive), withWriteserving as the conservative default for unknown commands - Autonomy Tiers define session trust levels through the
Autonomystruct, supporting base tiers (readonly,supervised,full) combined with feature flags likeallow_tool_install - The
gate_decisionfunction insrc/openhuman/security/command.rsmediates between these systems, returningAllow,Prompt, orBlockbased on the command class and current tier - System-level protections like
is_always_forbiddenprovide hard boundaries that override tier permissions for sensitive directories - The architecture separates core enforcement logic from UI concerns, with the frontend only rendering approval prompts when the core explicitly requests them via the
Promptdecision
Frequently Asked Questions
What happens when a command doesn't match any known CommandClass?
When classify_command cannot match an incoming method name to a known pattern, it conservatively falls back to the Write classification. This ensures that unknown commands are treated as potentially state-modifying operations and must pass the stricter permission checks required for write access, rather than being implicitly allowed as read-only operations.
Which autonomy tier is required for network operations?
Network commands require either the full autonomy tier or the presence of the allow_tool_install flag on the session's Autonomy struct. If these conditions are not met, network operations will trigger a Prompt decision (requiring user approval) or be Blocked entirely, depending on the specific implementation of the gate rules in the security module.
How does OpenHuman handle destructive commands differently?
Destructive commands receive special treatment as the highest-risk category. Unlike Write operations that may be allowed under supervised autonomy, destructive commands are **Block**ed unless the session has full autonomy and is explicitly marked as trusted. This dual requirement prevents accidental data loss even in high-autonomy sessions that haven't been vetted for dangerous operations.
Where is the permission gate entry point in the codebase?
The permission gate is invoked in src/core/dispatch.rs, which serves as the central router for all incoming RPC calls. This file retrieves the command classification, fetches the current Autonomy tier from the CoreContext, and passes both values to gate_decision before determining whether to execute the command, request approval, or return a permission error.
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 →