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

> Explore OpenHuman's command permission model. Learn how it classifies requests, evaluates autonomy tiers, and enforces Allow, Prompt, or Block decisions for secure command execution.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: deep-dive
- Published: 2026-08-28

---

**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`](https://github.com/tinyhumansai/openhuman/blob/main/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`.

```rust
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`](https://github.com/tinyhumansai/openhuman/blob/main/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`](https://github.com/tinyhumansai/openhuman/blob/main/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.

```rust
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`](https://github.com/tinyhumansai/openhuman/blob/main/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.

```toml

# ~/.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`](https://github.com/tinyhumansai/openhuman/blob/main/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

- The command permission model classifies all requests via `classify_command` in [`src/openhuman/security/command_classification.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/command_classification.rs) into coarse-grained `CommandClass` variants
- The `gate_decision` function in [`src/openhuman/security/policy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy.rs) evaluates classified commands against the current `AutonomyTier` and blocked path lists
- Three autonomy tiers—**readonly**, **supervised**, and **full**—define capability boundaries in [`src/openhuman/config/schema/autonomy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/config/schema/autonomy.rs)
- Decisions result in `Allow`, `Prompt`, or `Block` states, with interactive approval handled by [`src/openhuman/security/approval.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/approval.rs)
- Hard-blocked paths in [`src/openhuman/security/blocked_paths.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/blocked_paths.rs) override tier permissions to protect sensitive system resources

## 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`](https://github.com/tinyhumansai/openhuman/blob/main/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`](https://github.com/tinyhumansai/openhuman/blob/main/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.