Understanding the OpenHuman Command Permission Model: From classify_command to Autonomy Tiers

OpenHuman enforces security through a three-stage command permission model that classifies incoming requests into coarse-grained categories, evaluates them against configurable autonomy tiers, and returns explicit Allow, Prompt, or Block decisions before execution.

The tinyhumansai/openhuman repository implements a robust command permission model that governs how AI agents execute tools, filesystem operations, and network requests. This security framework maps raw RPC calls to structured permission classes and validates them against user-defined autonomy boundaries configured in ~/.openhuman/config.toml. The implementation spans three core Rust modules that handle command classification, policy evaluation, and tier-based capability enforcement.

The Three Stages of the Permission Pipeline

The command permission model operates through a sequential pipeline that inspects every command before execution. Each stage transforms the raw request into a concrete security decision based on static analysis and runtime configuration.

Command Classification via classify_command

Every incoming request—whether a JSON-RPC call, CLI invocation, or internal tool execution—first passes through the classification layer. In src/openhuman/security/command_classification.rs, the classify_command function inspects the command name and arguments to assign a CommandClass variant.

The classifier recognizes five primary categories: Read, Write, Network, Install, and Destructive. For example, a call to /rpc/agent/execute_tool that targets the filesystem returns CommandClass::Write, while a network fetch operation returns CommandClass::Network.

use openhuman::security::command_classification::classify_command;
use openhuman::security::CommandClass;

let cmd_name = "/rpc/agent/execute_tool";
let args = json!({ "tool_name": "write_file", "path": "/tmp/foo.txt" });

let class: CommandClass = classify_command(cmd_name, &args);
assert_eq!(class, CommandClass::Write);

Policy Evaluation with gate_decision

Once classified, the command enters the policy engine defined in src/openhuman/security/policy.rs. The gate_decision function accepts the CommandClass and the current AutonomyTier, then computes a GateDecision—either Allow, Prompt, or Block.

The function first consults hard-coded security constraints in src/openhuman/security/blocked_paths.rs, which lists always-forbidden directories like system credential stores. If the command targets these paths, it is immediately blocked regardless of tier. Otherwise, the function applies tier-specific logic to determine whether the operation proceeds silently, requires user approval, or is denied.

use openhuman::security::policy::{gate_decision, GateDecision};
use openhuman::config::schema::autonomy::AutonomyTier;
use openhuman::security::CommandClass;

let tier = AutonomyTier::Supervised;                // read from Config
let class = CommandClass::Install;                  // from classify_command

let decision: GateDecision = gate_decision(&tier, class);
match decision {
    GateDecision::Allow => println!("Proceed"),
    GateDecision::Prompt => println!("Show approval UI"),
    GateDecision::Block => println!("Reject"),
}

Autonomy Tier Enforcement

The final layer enforces capabilities defined in src/openhuman/config/schema/autonomy.rs. OpenHuman supports three distinct autonomy tiers that determine the agent's operational boundaries:

  • readonly: Permits only Read and optionally Network operations; all writes and installations are blocked
  • supervised: Allows Read and Write operations, but escalates Destructive or Install commands to Prompt status requiring user approval
  • full: Grants blanket Allow status to all command classes except those explicitly listed in the always-forbidden table

Users configure their tier via the TOML configuration file, where optional flags like allow_network further refine the capability set.


# ~/.openhuman/config.toml

[autonomy]
tier = "supervised"          # options: "readonly", "supervised", "full"

allow_network = true         # optional, defaults to false for readonly

Runtime Enforcement and Decision Handling

The command permission model enforces decisions once per turn, preventing agents from bypassing gates mid-interaction. When gate_decision returns:

  • Allow: The runtime immediately executes the command
  • Prompt: The UI layer presents an approval card through the logic in src/openhuman/security/approval.rs, suspending execution until the user accepts or rejects
  • Block: The system aborts the command and returns a permission error to the caller

This ensures that destructive operations cannot proceed without explicit human oversight when running in supervised or readonly modes.

Summary

Frequently Asked Questions

How does OpenHuman determine which CommandClass to assign?

The classify_command function inspects the RPC method name and argument structure to categorize operations. File write operations return CommandClass::Write, network requests return CommandClass::Network, and package installations return CommandClass::Install. This classification is deterministic and occurs before any policy evaluation.

What is the difference between the supervised and full autonomy tiers?

The supervised tier allows standard read and write operations but requires user approval for destructive changes and software installations. The full tier grants automatic permission to all command classes except those targeting explicitly blocked paths like credential stores. Supervised mode is recommended for autonomous agents operating in production environments.

Can I customize which paths are always blocked?

Yes. While the default hard-blocked paths are defined in src/openhuman/security/blocked_paths.rs, the policy engine checks this list before evaluating autonomy tiers. Administrators can modify the source to include additional protected directories, or future versions may expose these restrictions via configuration files.

What happens when a command receives a Prompt decision?

When gate_decision returns GateDecision::Prompt, the runtime invokes the approval workflow in src/openhuman/security/approval.rs. This pauses execution and displays an interactive card in the UI detailing the requested operation, allowing the user to approve or deny the specific command instance before it proceeds.

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 →