Understanding `action_dir` vs `workspace_dir` in OpenHuman: Security Boundaries Explained

OpenHuman's action_dir serves as a sandboxed directory where AI agents can read and write files, while workspace_dir acts as a protected vault storing encrypted credentials and core state, with the core enforcing strict isolation to prevent agents from accessing sensitive data.

The tinyhumansai/openhuman repository implements a dual-directory security model in its Rust core to separate agent operations from confidential system data. Understanding the distinction between action_dir and workspace_dir is critical for deploying secure AI workflows, as these paths define the boundary between untrusted agent code and sensitive user credentials stored in the core workspace.

Core Concepts: The Agent Sandbox vs. The Core Vault

action_dir: The Agent Read/Write Root

The action_dir represents the filesystem root that tools and agents may access for all file operations. According to the source code in src/openhuman/security/policy.rs, this directory defaults to $HOME/OpenHuman/projects (or the OPENHUMAN_ACTION_DIR environment variable) and serves as the anchor for all relative paths supplied to tools.

When an agent executes file operations—such as file_read, file_write, or shell commands—the core resolves these against action_dir. For example, in src/openhuman/tools/impl/system/shell.rs, the shell tool resolves its current working directory to security.action_dir, ensuring all command execution occurs within the sandbox.

workspace_dir: The Protected Core Workspace

Conversely, the workspace_dir functions as an internal store for OpenHuman's persistent state, including the SQLite key-ring, encrypted OAuth tokens, and session caches. Located at $HOME/.openhuman by default (overridable via OPENHUMAN_WORKSPACE_DIR), this directory is never exposed to agent tools or implementations.

As implemented in the configuration schema, the core uses this path exclusively for internal persistence mechanisms like core_state, keyring, and credential_store. The strict confidentiality boundary ensures that private keys and authentication data remain inaccessible to potentially untrusted agent code.

Security Implications and Enforcement Mechanisms

Isolation Through Path Validation

The core enforces that agents cannot escape the action_dir sandbox. In src/openhuman/tools/status/ops.rs (line 368), the implementation checks that any target path starts with the action_dir prefix before allowing file writes. If a tool attempts to access a path outside this boundary, the core returns a "forbidden path outside action_dir" error, preventing directory traversal attacks.

The Subdirectory Invariant

A critical security policy prevents action_dir from being a subdirectory of workspace_dir. The test in tests/harness_embed.rs (lines 124-125) asserts this invariant, verifying that the agent's working directory never starts with the workspace path. This prevents configuration mistakes that would grant agents indirect access to encrypted credentials stored in the workspace.

Violating this rule would allow malicious or buggy agents to read or modify private data, making the check a hard security guard that fails at compile-time during testing.

Configuring OpenHuman Directories

You can override these paths when constructing the core:

use openhuman_core::{CoreBuilder, Config};
use std::path::PathBuf;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let core = CoreBuilder::new()
        .config(Config {
            action_dir: PathBuf::from("/tmp/agent-sandbox"),
            workspace_dir: PathBuf::from("/var/lib/openhuman/private"),
            ..Default::default()
        })
        .build()
        .await?;
    
    Ok(())
}

When implementing custom tools, always validate paths against the security policy:

use std::path::Path;
use openhuman_core::security::SecurityPolicy;

fn write_agent_file(
    security: &SecurityPolicy, 
    rel_path: &Path, 
    data: &[u8]
) -> Result<(), std::io::Error> {
    let dest = security.action_dir.join(rel_path);
    
    // Enforce the action_dir boundary
    if !dest.starts_with(&security.action_dir) {
        return Err(std::io::Error::new(
            std::io::ErrorKind::PermissionDenied,
            "forbidden path outside action_dir"
        ));
    }
    
    std::fs::write(dest, data)
}

Summary

  • action_dir acts as a public sandbox for agent file operations, defaulting to $HOME/OpenHuman/projects, with all paths validated against this root via checks in src/openhuman/tools/status/ops.rs.
  • workspace_dir serves as a private vault for core secrets and state, defaulting to $HOME/.openhuman, and remains completely isolated from agent access according to the SecurityPolicy in src/openhuman/security/policy.rs.
  • The core enforces isolation at runtime through path prefix checks that reject any file operation attempting to escape the action directory.
  • Compile-time tests in tests/harness_embed.rs guarantee that action_dir can never reside inside workspace_dir, preventing credential leakage through misconfiguration.
  • Both directories are configurable via environment variables (OPENHUMAN_ACTION_DIR, OPENHUMAN_WORKSPACE_DIR) or programmatically via CoreBuilder.

Frequently Asked Questions

Can I set action_dir inside workspace_dir?

No. The core's security policy explicitly forbids this configuration. The test suite in tests/harness_embed.rs validates that action_dir never starts with the workspace_dir path. Placing the agent directory inside the workspace would violate the confidentiality boundary, potentially exposing encryption keys and OAuth tokens to agent processes.

What happens if an agent tries to access files outside action_dir?

The core rejects the operation with a permission error. In src/openhuman/tools/status/ops.rs, the system validates that all target paths start with the action_dir prefix before executing file operations. Any attempt to traverse upward or access absolute paths outside the sandbox results in a "forbidden path outside action_dir" error.

How do I configure these directories using environment variables?

Set OPENHUMAN_ACTION_DIR to override the default sandbox location and OPENHUMAN_WORKSPACE_DIR to change the core workspace path. These values are parsed during configuration initialization and stored in the SecurityPolicy struct defined in src/openhuman/security/policy.rs.

Why does OpenHuman separate these directories instead of using a single location?

The separation maintains a clear trust boundary between untrusted agent code and sensitive core data. The action_dir contains user-controlled project files that agents can freely modify, while the workspace_dir houses the SQLite key-ring and encrypted credentials that only the core should touch. This architecture prevents agents from accidentally or maliciously corrupting authentication data while allowing safe file operations in the sandbox.

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 →