# How the Command Permission Model Interacts with Autonomy Tiers in OpenHuman

> Discover how OpenHuman's command permission model interacts with autonomy tiers. Understand access control decisions for every command.

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

---

**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`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/command.rs) defines five distinct categories:

- **`Read`** – Operations that only retrieve information without side effects
- **`Write`** – Modifications to files or state (default fallback for unmatched commands)
- **`Network`** – Outbound connections and remote resource fetching
- **`Install`** – Package installation and tool deployment
- **`Destructive`** – Irreversible operations like `rm -rf` or 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`](https://github.com/tinyhumansai/openhuman/blob/main/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`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/dispatch.rs), the permission system evaluates the request through a deterministic three-step pipeline:

1. **Command Classification** – The system calls **`classify_command`** on the incoming method name to determine its `CommandClass`
2. **Tier Retrieval** – The current session's **`Autonomy`** value is fetched from the core context via `ctx.autonomy()`
3. **Gate Decision** – The **`gate_decision(class, tier)`** function applies enforcement rules to return `Allow`, `Prompt`, or `Block`

The gate applies specific logic based on the command class and tier combination:

- **`Read`** commands are generally permitted for all autonomy levels
- **`Write`** commands require at least `supervised` autonomy; `full` autonomy permits writes without prompting
- **`Network`** and **`Install`** operations need the `allow_tool_install` flag or `full` tier, otherwise prompting or blocking occurs
- **`Destructive`** commands are blocked unless the tier is `full` **and** 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`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/command.rs):

```rust
// 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:

```tsx
// 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`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/command.rs)** – Contains the `classify_command` function and `gate_decision` logic that implements the interaction between command classes and autonomy tiers
- **[`src/openhuman/security/autonomy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/autonomy.rs)** – Defines the `Autonomy` struct, tier constants (`readonly`, `supervised`, `full`), and helper methods for flag checking
- **[`src/core/dispatch.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/core/dispatch.rs)** – Entry point where incoming RPC calls are routed through the permission gate before execution
- **[`AGENTS.md`](https://github.com/tinyhumansai/openhuman/blob/main/AGENTS.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`), with `Write` serving as the conservative default for unknown commands
- **Autonomy Tiers** define session trust levels through the `Autonomy` struct, supporting base tiers (`readonly`, `supervised`, `full`) combined with feature flags like `allow_tool_install`
- The **`gate_decision`** function in [`src/openhuman/security/command.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/command.rs) mediates between these systems, returning `Allow`, `Prompt`, or `Block` based on the command class and current tier
- System-level protections like **`is_always_forbidden`** provide 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 `Prompt` decision

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