How the OpenHuman Skills Runtime Executes SKILL.md Workflows with Node and Python Clients

The OpenHuman Skills runtime converts SKILL.md files into running processes by discovering workflow metadata, resolving language-specific runtimes through Node and Python clients, spawning child processes with JSON inputs, and tracking execution via run IDs and log files.

The Skills runtime is the execution engine within the OpenHuman repository that transforms static workflow descriptions into live automation tasks. It bridges the gap between declarative SKILL.md files and concrete process execution, managing everything from environment setup to log collection across Node.js and Python ecosystems.

Discovering Workflow Metadata

Before execution begins, the runtime must locate and validate the target workflow. The catalog module in src/openhuman/skills/catalog/ops.rs handles the discovery phase, parsing the installed SKILL.md file to extract critical metadata including input schemas, declared language runtimes, script entry points, and resource requirements.

The registry at src/openhuman/skills/registry.rs maintains a centralized index of all installed skills. When a user invokes a workflow by its ID, the runtime queries this registry to resolve the skill's location and configuration before proceeding to the execution phase.

Resolving Node and Python Runtimes

Once the workflow metadata is loaded, the runtime must prepare the appropriate execution environment. The system delegates this responsibility to specialized client crates that handle language-specific setup.

Node Client Resolution

The Node client resides in the runtime_node crate (src/openhuman/runtime/node/mod.rs). Its primary function is to locate the node, npm, and npx binaries on the host system, inject custom PATH variables, and ensure missing packages are installed before execution.

Python Client Resolution

The Python client lives in the runtime_python crate (src/openhuman/runtime/python/mod.rs). It resolves the Python interpreter path, creates virtual environments when necessary, and validates that required packages are available in the target environment.

Both clients expose the function resolve_runtime(runtime: RuntimeKind) -> Result<RuntimeInfo> which returns the absolute binary path and environment variables required for execution. The Skills runtime calls this from src/openhuman/skills/runtime/ops.rs when a workflow declares runtime: "node", runtime: "python", or "all" to allow either interpreter.

Spawning Workflow Processes

The actual process creation logic lives in src/openhuman/skills/runtime/run_machinery.rs. The async function spawn_workflow_run_background orchestrates the execution pipeline:

pub async fn spawn_workflow_run_background(
    skill_id: &str,
    inputs: serde_json::Value,
    runtime: RuntimeKind,
) -> Result<RunHandle> {
    // 1️⃣ Resolve the runtime (Node / Python)
    let runtime_info = resolve_runtime(runtime).await?;
    // 2️⃣ Build the command
    let mut cmd = std::process::Command::new(runtime_info.binary);
    cmd.args(&runtime_info.args);
    // 3️⃣ Pipe the serialized inputs
    cmd.stdin(std::process::Stdio::piped());
    // 4️⃣ Launch the child process
    let child = cmd.spawn()?;
    // 5️⃣ Track the run via a RunHandle (log path, IDs, status)
    // ...
}

For Node workflows, the runtime invokes runtime_node::node::spawn_process to construct a std::process::Command with the resolved binary, inject the skill's working directory, append npm arguments, and forward JSON-encoded inputs via stdin.

For Python workflows, runtime_python::python::spawn_process performs equivalent steps with the resolved Python binary, optionally activating a virtual environment before passing inputs to the script.

Tracking Execution and Collecting Results

Every workflow execution receives a unique run ID and dedicated log file written to <workspace>/skill_runtime/logs/. When a process launches, the runtime emits a WorkflowRunStarted event (defined in run_machinery.rs) containing the run_id, workflow_id, and log path.

A background task monitors the child process, streaming stdout and stderr to the log file and posting progress events on the internal event bus (src/core/event_bus/). Upon completion, the await_run_outcome function (also in run_machinery.rs) captures the exit status, parses any JSON result emitted by the script, and publishes a WorkflowRunCompleted event.

Users can query recent executions via skill_runtime recent_runs or inspect specific logs with skill_runtime view_log.

RPC Interface and Skill Executor Agent

The Skill Executor agent at src/openhuman/skills/runtime/agent/skill_executor/mod.rs exposes the runtime functionality through RPC calls. This embedded agent registers the skill_runtime namespace within the core process (listed in src/core/all.rs), handling requests such as skill_runtime run, skill_runtime cancel, and skill_runtime recent_runs through the high-level operation handlers in src/openhuman/skills/runtime/ops.rs.

Practical Usage Examples

CLI Execution

List installed workflows and resolve available runtimes:


# Display all installed SKILL.md workflows

openhuman skill_runtime list

# Verify Node and Python runtime availability

openhuman skill_runtime resolve_runtimes --runtime all

Execute specific skills with JSON inputs:


# Run a Node-based skill

openhuman skill_runtime run --skill_id git-helper \
    --inputs '{"repo":"my-repo","branch":"main"}'

# Run a Python-based skill

openhuman skill_runtime run --skill_id data-cleaner \
    --inputs '{"path":"./data.csv"}' \
    --runtime python

Inspect execution history:


# Show the ten most recent runs

openhuman skill_runtime recent_runs --limit 10

# Stream logs for a specific execution

openhuman skill_runtime view_log --run_id 2024-08-24-01-23-45-abcdef

Programmatic Execution

Trigger workflows from Rust code using the public API exported from src/openhuman/skills/runtime/mod.rs:

use openhuman_core::skills::runtime::{run_skill, RuntimeKind};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Execute a Node workflow
    let handle = run_skill(
        "git-helper",
        serde_json::json!({ "repo": "my-repo", "branch": "main" }),
        RuntimeKind::Node,
    )
    .await?;

    // Await completion and retrieve output
    let result = handle.await_result().await?;
    println!("Skill finished with output: {}", result);
    Ok(())
}

Summary

Frequently Asked Questions

How does the Skills runtime locate the correct Node or Python interpreter?

The runtime delegates resolution to the runtime_node and runtime_python crates. The function resolve_runtime(runtime: RuntimeKind) in src/openhuman/skills/runtime/ops.rs queries these helpers to find absolute binary paths, check for npm/npx availability, create Python virtual environments, and return the environment variables required for execution.

What happens to the JSON inputs provided to a SKILL.md workflow?

Inputs are serialized as JSON and passed directly to the spawned process via stdin. In src/openhuman/skills/runtime/run_machinery.rs, the spawn_workflow_run_background function pipes serde_json::Value into the child process before execution begins, allowing scripts to read and parse the configuration immediately upon startup.

Where does OpenHuman store logs and execution metadata for workflow runs?

Each execution receives a unique run ID and writes logs to <workspace>/skill_runtime/logs/. The runtime records metadata through WorkflowRunStarted and WorkflowRunCompleted events posted to the internal event bus (src/core/event_bus/), while the await_run_outcome function in run_machinery.rs finalizes the run status and parses result data.

How can I programmatically trigger a skill execution from Rust code?

Import the runtime module from src/openhuman/skills/runtime/mod.rs and call the run_skill() function with the skill ID, JSON inputs, and RuntimeKind::Node or RuntimeKind::Python. This returns a RunHandle that allows you to await completion and retrieve the final output through handle.await_result().await.

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 →