# How SKILL.md Files Are Discovered and Executed by the OpenHuman Skill Runtime

> Learn how the OpenHuman skill runtime discovers SKILL.md files by scanning file systems and executes them using the run workflow RPC tool for secure skill execution.

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

---

**The OpenHuman skill runtime discovers SKILL.md bundles by scanning hierarchical filesystem scopes in [`src/openhuman/skills/ops_discover.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/ops_discover.rs), enforcing trust via `.openhuman/trust` markers, and executes them through the `run_workflow` RPC tool that launches a sandboxed `skill_executor` agent.**

The `tinyhumansai/openhuman` repository implements a deterministic two-phase pipeline for skill management. The **discovery** phase locates and validates SKILL.md bundles across multiple filesystem roots, while the **execution** phase runs the resolved workflows in an isolated agent environment. This architecture ensures that only trusted, non-symlinked skill manifests are loaded and that profile-local skills remain private to their owner.

## SKILL.md Discovery Mechanism

The discovery process is orchestrated by [`src/openhuman/skills/ops_discover.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/ops_discover.rs), which implements a hierarchical scanner that respects four distinct scopes with defined precedence rules.

### Root Categories and Scope Hierarchy

Discovery examines two root kinds—**Skill** roots and **Workflow** roots—across four scopes. The enum `RootKind`, defined in [`src/openhuman/skills/ops_types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/ops_types.rs), distinguishes these categories, while the `WorkflowScope` type tracks provenance. The runtime scans in this order:

- **User scope** (`~/.openhuman/skills/`, `~/.agents/skills/`) — Always scanned for global user capabilities.
- **Project scope** (`<workspace>/.openhuman/skills/`, `<workspace>/.agents/skills/`) — Scanned only if the workspace contains the trust marker file `.openhuman/trust`.
- **Legacy scope** (`<workspace>/skills/`) — Included for backward compatibility when full discovery is requested.
- **Profile-local scope** (`<workspace>/personalities/<id>/skills`) — Optional root passed via `discover_workflows_with_profile` (lines ≈121-130).

### Trust Verification and Security Checks

Before loading project-level skills, the runtime verifies workspace trust via `is_workspace_trusted` (lines ≈332-337), which checks for the existence of `.openhuman/trust`. Additionally, `is_safe_manifest` validates that discovered manifests are regular files—not symlinks—preventing directory traversal attacks.

### Collision Resolution and Precedence

When multiple bundles share the same display name or directory slug, the `absorb` function (lines ≈223-286) merges discovery maps and applies precedence rules. The precedence ladder (lines ≈388-395) ranks scopes as: `Legacy < User < Project < Profile`. Later-scanned scopes override earlier ones, with warnings logged for discarded entries.

### Bundle Loading and Manifest Parsing

Each candidate directory is processed by `load_skill_dir` (lines ≈438-470), which detects manifests in priority order:

1. **WORKFLOW.md** (current format, defined in [`ops_types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/ops_types.rs))
2. **SKILL.md** (legacy markdown format)
3. **SKILL.json** (legacy JSON format)

The helper invokes `load_from_workflow_md` for markdown manifests or `load_from_legacy_manifest` for JSON, returning a `Vec<Workflow>` via the public entry point `load_workflow_metadata` (lines ≈66-71).

## Skill Execution Runtime

Once discovered, skills are executed through a secure RPC-mediated pipeline that maintains isolation between the caller and the skill logic.

### RPC Tool Registration and Skill Resolution

The `run_workflow` tool is registered in [`src/openhuman/skills/runtime/tools.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/runtime/tools.rs). When invoked via JSON-RPC, the runtime resolves the requested skill using `load_workflow_metadata_for_profile` (lines ≈84-92), ensuring profile-local bundles are honored and that private skills are only accessible by their owner.

### The Skill Executor Agent

Resolved workflows execute within the `skill_executor` agent defined in `src/openhuman/skills/runtime/agent/skill_executor/`, coordinated by [`src/openhuman/skills/runtime/run_machinery.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/runtime/run_machinery.rs). This pipeline reads the skill's manifest and resources via `read_workflow_resource` (lines ≈506-666), streams prompt templates to the LLM, processes tool calls, and returns the final output through the RPC response channel.

### Secure Resource Access

The `read_workflow_resource` function enforces strict sandboxing: it validates symlinks to prevent directory traversal, enforces size limits, and guarantees UTF-8 compliance before returning file contents from the bundle directory.

## Practical Code Examples

### Listing Discovered Skills

To enumerate available skills while respecting workspace trust boundaries:

```rust
use std::path::Path;
use openhuman::skills::ops_discover::{load_workflow_metadata, is_workspace_trusted};

fn list_skills(workspace: &Path) {
    // Projects without .openhuman/trust will only show user-scope skills
    let trusted = is_workspace_trusted(workspace);
    let skills = load_workflow_metadata(workspace);
    for skill in skills {
        println!("✅ {} ({:?}) – {}", skill.name, skill.scope, skill.description);
    }
}

```

### Reading Skill Bundle Resources

Access files within a specific skill bundle using the hardened resource reader:

```rust
use std::path::Path;
use openhuman::skills::ops_discover::read_workflow_resource;

fn read_resource(workspace: &Path, skill_id: &str, relative_path: &Path) {
    match read_workflow_resource(workspace, skill_id, relative_path) {
        Ok(content) => println!("📄 {relative_path:?} →\n{content}"),
        Err(err)   => eprintln!("❌ Failed to read resource: {err}"),
    }
}

// Example: Read references/note.md from the "mail-helper" skill
read_resource(&workspace_dir, "mail-helper", Path::new("references/note.md"));

```

### Executing Skills via JSON-RPC

Trigger skill execution through the runtime's RPC interface:

```json
{
  "jsonrpc": "2.0",
  "id": "run-42",
  "method": "openhuman.run_workflow",
  "params": {
    "skill_id": "mail-helper",
    "input": "Fetch the latest unread emails and summarize them."
  }
}

```

## Summary

- **Hierarchical discovery** scans User, Project, Legacy, and Profile scopes in [`src/openhuman/skills/ops_discover.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/ops_discover.rs), with precedence rules ensuring Profile-local skills override global ones.
- **Trust enforcement** requires the `.openhuman/trust` marker for project-level skills, while `is_safe_manifest` blocks symlink attacks during manifest loading.
- **Flexible parsing** supports [`WORKFLOW.md`](https://github.com/tinyhumansai/openhuman/blob/main/WORKFLOW.md), [`SKILL.md`](https://github.com/tinyhumansai/openhuman/blob/main/SKILL.md), and [`SKILL.json`](https://github.com/tinyhumansai/openhuman/blob/main/SKILL.json) formats via `load_skill_dir`.
- **Secure execution** occurs through the `run_workflow` RPC tool, which resolves skills via `load_workflow_metadata_for_profile` and isolates execution in the `skill_executor` agent coordinated by [`run_machinery.rs`](https://github.com/tinyhumansai/openhuman/blob/main/run_machinery.rs).
- **Resource sandboxing** via `read_workflow_resource` prevents unauthorized filesystem access through symlink validation and size constraints.

## Frequently Asked Questions

### What file names does the OpenHuman runtime recognize for skill manifests?

The runtime recognizes three manifest filenames in priority order: **WORKFLOW.md** (current standard), **SKILL.md** (legacy markdown), and **SKILL.json** (legacy JSON). The `load_skill_dir` function in [`src/openhuman/skills/ops_discover.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/skills/ops_discover.rs) checks for these files sequentially and invokes the appropriate parser for each format.

### How does OpenHuman prevent unauthorized execution of project-level skills?

The runtime requires a trust marker file—`.openhuman/trust`—to be present in the workspace root before scanning project-scope skill directories. The `is_workspace_trusted` function (lines ≈332-337) performs this check, ensuring that untrusted repositories cannot execute arbitrary code from `.openhuman/skills/` directories.

### What determines which skill bundle takes precedence when names collide?

The `absorb` function implements a precedence ladder where **Profile** > **Project** > **User** > **Legacy**. When two bundles share the same display name or directory slug, the bundle from the higher-precedence scope overrides the lower one, with the runtime logging warnings for any discarded duplicate entries.

### Can skills access arbitrary files outside their bundle directory?

No. Skills must access resources through the `read_workflow_resource` helper (lines ≈506-666), which enforces strict sandboxing. This function validates that requested paths are regular files within the bundle directory (not symlinks), enforces size limits, and validates UTF-8 encoding, preventing directory traversal attacks and unauthorized filesystem access.