How Agents Are Managed and Executed Within the OpenHuman Rust Core
The OpenHuman Rust core implements agents as data-driven sub-processes defined by TOML specifications, indexed in a global singleton registry, and executed through the spawn_subagent meta-tool which creates isolated turn loops that collapse their interaction history into singular tool results.
In the OpenHuman framework, agents are not monolithic external services but composable, sandboxed sub-processes governed by declarative definitions. Understanding how agents are managed and executed within the OpenHuman Rust core reveals a lightweight architecture that enables dynamic tool filtering, prompt customization, and secure resource inheritance without spawning separate OS processes. The system leverages the AgentDefinitionRegistry and a dedicated sub-agent runner to orchestrate these workflows using the same Tokio-based turn machinery that powers parent agents.
Agent Definitions and the Global Registry
At the heart of the system lies the AgentDefinition struct located in src/openhuman/agent/harness/definition.rs. This structure encapsulates everything required to configure a sub-agent: its identifier, system prompt, target model, tool whitelist, runtime limits, and flags that control which parts of the parent prompt are omitted.
Built-in agent definitions are stored as TOML files within src/openhuman/agent/registry/agents/…/agent.toml and loaded at startup by the definition_loader in src/openhuman/agent/registry/agents/loader.rs. Users can extend the system by placing custom definitions under $OPENHUMAN_WORKSPACE/agents/*.toml, which the loader discovers and ingests during initialization.
All definitions are indexed in the AgentDefinitionRegistry, a singleton accessible via AgentDefinitionRegistry::global(). This registry populates at core startup through AgentDefinitionRegistry::init() and enables runtime validation of agent_id requests across the entire system.
// Load a custom agent definition at runtime
let registry = AgentDefinitionRegistry::global().unwrap();
let my_def = registry
.list()
.iter()
.find(|d| d.id == "researcher")
.expect("definition missing");
The spawn_subagent Meta-Tool
The harness constructs the parent agent’s tool list from the core tool catalog in src/openhuman/tools/mod.rs. Among these tools, the meta-tool SpawnSubagentTool (defined in src/openhuman/agent/orchestration/tools/spawn_subagent.rs) serves as the entry point for agent delegation.
When a parent turn invokes this tool, the implementation performs several critical operations:
- Registry Lookup: Validates the requested
agent_idagainst the global registry. - Tool Filtering: Intersects the parent’s available tools with the sub-agent’s
toolswhitelist, excluding any listed indisallowed_tools. - Prompt Construction: Generates a narrow system prompt for the child based on the
AgentDefinitionconfiguration.
// Invoke a sub-agent from a parent turn
let tool = SpawnSubagentTool::new();
let args = json!({
"agent_id": "researcher",
"prompt": "Summarise the latest research papers on Rust async patterns.",
"blocking": true
});
let result = tool.execute(args).await?;
println!("Sub-agent answer: {}", result.output());
Sub-Agent Execution Flow
Execution is handled by the sub-agent runner located in src/openhuman/agent/harness/subagent_runner/. The entry point run_subagent receives the definition, prompt, optional context, and the parent’s provider, then determines the execution mode.
Inline Execution: Runs on the same Tokio task, suitable for simple, blocking operations.
Async Worker Execution: Creates a reusable worker (default) that persists beyond the initial call, enabling stateful interactions addressed via a task_key.
The dispatch flow follows this explicit path through the codebase:
src/openhuman/agent/harness/session/turn/core.rscollects the tool callSpawnSubagentTool::executeinitiates the requestrun_subagentdelegates tosubagent_runner/ops/runner.rssubagent_runner/ops/graph.rsbuilds the sub-agent’s turn graphsubagent_runner/ops/runner.rsexecutes the graph- Results are packaged into a
ToolResultand returned to the parent
The sub-agent’s entire interaction loop—model calls, tool invocations, and policy checks—runs exactly like a normal turn, but its history collapses into a single result object.
// Create a reusable async worker addressable by task_key
let args = json!({
"agent_id": "code_executor",
"prompt": "Write a function that computes Fibonacci numbers.",
"task_key": "fib_generator",
"fresh": false // reuse existing worker if present
});
let _ = tool.execute(args).await?;
Security and Resource Boundaries
Sub-agents inherit the parent’s security gate (src/openhuman/agent/tinyagents/host/security_gate.rs) and budget gate, ensuring that sandboxing policies propagate downstream. However, sub-agents also respect their own specific limits defined in AgentDefinition:
max_iterations: Caps the number of reasoning stepstimeout_secs: Hard limit on execution durationmax_result_chars: Restricts output payload size
The iteration_policy field, including iteration_policy::Extended, allows longer workflows when the default constraints prove too restrictive for complex tasks.
Lifecycle and Persistence Management
The registry populates during core initialization and remains immutable during runtime. Sub-agent lifecycle management depends on the invocation mode:
- Blocking calls: State exists only for the duration of the turn; in-memory history is discarded immediately after result delivery.
- Reusable workers: When invoked with a
task_keyandfresh: false, the worker persists in memory and can be addressed later viasrc/openhuman/agent/orchestration/tools/spawn_worker_thread.rs.
This architecture ensures that agents remain pure data objects—composable, observable, and subject to the same logging and policy layers that protect the parent turn.
Summary
- AgentDefinition structs in
src/openhuman/agent/harness/definition.rsstore complete sub-agent specifications as TOML-driven data objects. - The AgentDefinitionRegistry singleton provides global access to agent definitions at runtime via
AgentDefinitionRegistry::global(). - SpawnSubagentTool in
src/openhuman/agent/orchestration/tools/spawn_subagent.rsfilters parent tools and initiates sub-agent execution. - The sub-agent runner reuses the core turn machinery in
src/openhuman/agent/harness/subagent_runner/while isolating execution contexts. - Sub-agents inherit parent security gates but respect their own
max_iterations,timeout_secs, andmax_result_charslimits. - Reusable async workers persist via
task_keyreferences, while blocking executions clean up immediately after result return.
Frequently Asked Questions
How do I register a custom agent definition in OpenHuman?
Place a TOML file following the AgentDefinition schema in $OPENHUMAN_WORKSPACE/agents/*.toml. The definition_loader in src/openhuman/agent/registry/agents/loader.rs automatically discovers and registers these files during core startup, making them available through AgentDefinitionRegistry::global().
What is the difference between blocking and reusable sub-agent execution?
Blocking execution runs the sub-agent inline on the same Tokio task and discards its state immediately after returning the result. Reusable execution creates an async worker that persists in memory, allowing subsequent calls to reference the same state via a task_key, as implemented in src/openhuman/agent/orchestration/tools/spawn_worker_thread.rs.
How does the parent agent's tool set get filtered for sub-agents?
The SpawnSubagentTool::execute method intersects the parent’s available tools from src/openhuman/tools/mod.rs with the sub-agent’s tools whitelist, then removes any tools specified in disallowed_tools. This ensures sub-agents operate with the minimal necessary capability surface.
Where are sub-agent execution limits enforced?
Limits defined in AgentDefinition—including max_iterations, timeout_secs, and max_result_chars—are enforced by the sub-agent runner in src/openhuman/agent/harness/subagent_runner/ops/runner.rs. Additionally, the parent’s security and budget gates from src/openhuman/agent/tinyagents/host/security_gate.rs wrap the sub-agent execution context.
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 →