# Workspace Architecture in OpenHuman: Action Directory, Workspace Directory, and the Two-Path-Root Security Invariant

> Explore OpenHuman's workspace architecture with action_dir, workspace_dir, and the two-path-root security invariant. Learn how OpenHuman isolates agent operations and protects core state.

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

---

**OpenHuman enforces a strict two-path-root security invariant that isolates agent operations in `action_dir` (the sandbox) while protecting core state in `workspace_dir`, ensuring no file system access spans both roots.**

OpenHuman implements a rigorous workspace architecture that separates agent filesystem access from internal core state. By dividing the filesystem into two distinct roots—`action_dir` for agent tools and `workspace_dir` for core internals—the platform prevents privilege escalation and data tampering. This design is enforced throughout the codebase in the `tinyhumansai/openhuman` repository through a strict security invariant implemented in the `SecurityPolicy` struct.

## The Two-Path-Root Design

OpenHuman’s workspace architecture relies on two separate directory roots that serve fundamentally different purposes. This separation is defined in [`src/openhuman/config/schema/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/config/schema/types.rs) within the `Config` struct and enforced at runtime by the `SecurityPolicy` implementation.

### action_dir: The Agent Sandbox

The **`action_dir`** serves as the read/write sandbox for all agent tools. Located by default at `~/OpenHuman/projects/` (derived from the user’s `$HOME` environment variable), this directory is where agents execute file operations, spawn shells, and store temporary outputs.

According to the source code in [`src/openhuman/config/schema/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/config/schema/types.rs), this path populates the `Config.action_dir` field and is subsequently stored in the `SecurityPolicy` struct. When agents invoke tools like the shell implementation in [`src/openhuman/tools/impl/system/shell.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/impl/system/shell.rs), the working directory resolves against `self.security.action_dir`. Any attempt to access paths outside this root triggers a security rejection.

### workspace_dir: Core Private State

The **`workspace_dir`** contains internal core state that only the OpenHuman core may access. Located at `~/.openhuman/users/<user-id>/workspace/`, this directory houses sensitive resources including the memory database, approval files, and session artifacts.

Unlike `action_dir`, agents are **never** permitted to read from or write to this location. The `Config.workspace_dir` field, also defined in [`src/openhuman/config/schema/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/config/schema/types.rs), establishes this boundary. Core services such as `MemoryClient` use this path exclusively, ensuring that internal state remains isolated from potentially untrusted agent code.

## The Two-Path-Root Security Invariant

OpenHuman enforces an invariant that **every file system access must be scoped to either `action_dir` *or* `workspace_dir`, never both**. This prevents path traversal attacks and ensures complete isolation between agent capabilities and core internals.

The core-side `SecurityPolicy` in [`src/openhuman/security/policy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy.rs) implements two critical validation functions:

1. **`is_workspace_internal_path`** – Returns `true` only for paths residing under `workspace_dir`. These paths are explicitly blocked for agent tools, guaranteeing that internal data cannot be tampered with from the agent side.

2. **`is_action_dir_path`** – Validates that a requested path falls under `action_dir`. If a tool attempts to access a location outside this root, the operation is denied with the error message **"write rejected: forbidden path outside action_dir"** as generated in [`src/openhuman/tools/status/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/status/ops.rs) at line 368.

This invariant is exercised throughout the codebase. Shell tools resolve their working directory via `self.security.action_dir` in [`src/openhuman/tools/impl/system/shell.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/impl/system/shell.rs), while file-write operations reject any path falling outside the action directory. Tests in [`tests/harness_embed.rs`](https://github.com/tinyhumansai/openhuman/blob/main/tests/harness_embed.rs) (lines 124‑125) assert that `action_dir` never starts with the `workspace_dir` prefix, ensuring the directories maintain proper separation even under configuration edge cases.

## Implementation in Code

The security boundary manifests in concrete implementation patterns across the Rust codebase.

Creating a `SecurityPolicy` from user configuration:

```rust
// src/openhuman/config/schema/types.rs
let cfg = Config::load_or_init()?;
let security = SecurityPolicy {
    action_dir: cfg.action_dir.clone(),
    workspace_dir: cfg.workspace_dir.clone(),
    // …other fields omitted
};

```

A tool validating write access against the action directory:

```rust
// Conceptual implementation based on src/openhuman/tools/status/ops.rs logic
fn write_file(security: &SecurityPolicy, path: &Path) -> Result<()> {
    // Enforce the two‑path‑root invariant
    if !security.is_action_dir_path(path) {
        return Err(anyhow!("write rejected: forbidden path outside action_dir"));
    }
    // Normal write logic …
}

```

Core-only code accessing workspace internals:

```rust
// Core services access workspace_dir directly
fn load_memory(security: &SecurityPolicy) -> Result<MemoryClient> {
    let db_path = security.workspace_dir.join("memory.db");
    // This path is guaranteed never to be reachable by agents
    MemoryClient::open(db_path)
}

```

The invariant is verified by test assertions:

```rust
// tests/harness_embed.rs lines 124‑125
#[test]
fn action_dir_not_inside_workspace() {
    let harness = Harness::builder().build().await.unwrap();
    assert!(!harness.action_dir().starts_with(&harness.workspace_dir()),
            "action_dir must not sit inside the workspace");
}

```

## Summary

- **OpenHuman workspace architecture** strictly separates agent filesystem access into two distinct roots: `action_dir` for agent operations and `workspace_dir` for core internals.
- **`action_dir`** defaults to `~/OpenHuman/projects/` and serves as the sandbox where agents read and write files, execute shells, and operate without accessing sensitive system data.
- **`workspace_dir`** defaults to `~/.openhuman/users/<user-id>/workspace/` and contains core state such as the memory database and session artifacts; agents are explicitly prohibited from accessing this root.
- **The two-path-root security invariant** enforces that no single file operation can span both directories, with `is_workspace_internal_path` and `is_action_dir_path` checks in [`src/openhuman/security/policy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy.rs) providing the enforcement mechanism.
- **Violation consequences** include immediate rejection of file operations with the error "write rejected: forbidden path outside action_dir" when agents attempt to traverse outside their sandbox.

## Frequently Asked Questions

### What is the difference between action_dir and workspace_dir in OpenHuman?

**`action_dir`** is the agent's sandbox where tools read and write files, execute commands, and perform work, defaulting to `~/OpenHuman/projects/`. **`workspace_dir`** is the core's private storage for internal state like the memory database and approval files, located at `~/.openhuman/users/<user-id>/workspace/` and completely inaccessible to agents. This separation ensures agents cannot corrupt system state or access sensitive user data.

### How does OpenHuman prevent agents from accessing workspace_dir?

OpenHuman implements the **`is_workspace_internal_path`** check in [`src/openhuman/security/policy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy.rs) that returns `true` only for paths under `workspace_dir`. Agent tools are configured to reject any operation where this check returns `true`, while core services use this same check to verify they are operating in the correct context. The `SecurityPolicy` struct maintains both paths and validates every file system request against these boundaries.

### Where is the two-path-root security invariant enforced in the codebase?

The invariant is enforced in multiple locations: **[`src/openhuman/security/policy.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/security/policy.rs)** defines the validation logic through `is_workspace_internal_path` and `is_action_dir_path`; **[`src/openhuman/tools/status/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/status/ops.rs)** (line 368) generates the forbidden path error message; **[`src/openhuman/tools/impl/system/shell.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/impl/system/shell.rs)** resolves working directories against `action_dir`; and **[`tests/harness_embed.rs`](https://github.com/tinyhumansai/openhuman/blob/main/tests/harness_embed.rs)** (lines 124‑125) contains unit tests asserting that `action_dir` never resides within `workspace_dir`.

### What happens if an agent tries to write outside action_dir?

The operation is immediately rejected with the error message **"write rejected: forbidden path outside action_dir"**. This error originates from the tool operation logic in [`src/openhuman/tools/status/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/tools/status/ops.rs) when the `is_action_dir_path` check fails. The invariant ensures that agents cannot perform path traversal attacks to escape their sandbox or access system directories outside their designated `action_dir` root.