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
- The Skills runtime discovers
SKILL.mdworkflows throughsrc/openhuman/skills/catalog/ops.rsand the central registry atsrc/openhuman/skills/registry.rs. - Node and Python runtimes are resolved via dedicated crates that locate binaries, manage virtual environments, and prepare execution contexts via
resolve_runtime()insrc/openhuman/skills/runtime/ops.rs. - Process spawning occurs in
src/openhuman/skills/runtime/run_machinery.rsthroughspawn_workflow_run_background, which pipes JSON inputs viastdinand returns aRunHandlefor tracking. - Execution lifecycle events (
WorkflowRunStarted,WorkflowRunCompleted) and logs are managed through the internal event bus and written to<workspace>/skill_runtime/logs/. - The Skill Executor agent exposes all functionality through the
skill_runtimeRPC namespace, registered insrc/core/all.rs.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →