# How OpenHuman's TinyAgents-Based Agent Orchestrates Multi-Level Sub-Agent Delegation

> Discover how OpenHuman's tinyagents orchestrate multi-level sub-agent delegation using a typed graph engine for compiled pipelines and plan-execute-review loops with human approval.

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

---

**OpenHuman uses a typed graph engine to build compiled delegation pipelines that steer detached sub-agent tasks through plan-execute-review loops with durable checkpointing and human-in-the-loop approval gates.**

The `tinyhumansai/openhuman` repository implements multi-level sub-agent delegation through a three-layer orchestration architecture that combines static graph compilation with dynamic runtime steering. This system allows AI agents to recursively delegate tasks to specialized sub-agents while maintaining crash resilience and human oversight through the tinyagents graph engine.

## The Three-Layer Orchestration Architecture

The delegation system in OpenHuman consists of tightly-coupled layers that handle graph definition, runtime control, and state persistence.

### Graph Definition Layer

The static `CompiledGraph` in [[`src/openhuman/agent/tinyagents/delegation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/tinyagents/delegation.rs)](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/tinyagents/delegation.rs) defines nodes for `plan`, `execute`, `review`, optional `approval`, and `finalize` stages. The `build_delegation_graph` function (line 610) constructs this graph once per delegation run, accepting parameters for revision budgets, cancellation tokens, and approval requirements.

Each node body invokes an injected `run_stage` closure that forwards to the standard agent harness. Conditional routing uses `Command::with_goto([...])` to loop back to `execute` or proceed to `finalize` based on reviewer approval flags and remaining revision counts.

### Runtime Steering and Status Layer

Process-local coordination occurs through the `SteeringRegistry` declared in [[`src/openhuman/agent/tinyagents/orchestration.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/tinyagents/orchestration.rs)](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/tinyagents/orchestration.rs). The `shared_steering_registry` function (line 41) provides a global registry for `SteeringHandle` instances, while `openhuman_steering_handle` creates handles differentiated by `SteeringRunClass`.

Interactive runs (`SteeringRunClass::Interactive`) permit only `InjectMessage` and `Pause` operations. Background sub-agent runs (`SteeringRunClass::Background`) additionally allow `Resume`, `Cancel`, and `Redirect` commands, enabling safe control-flow steering without injecting untrusted transcript text.

### Durable Checkpointing Layer

The `Checkpointer` trait (e.g., `FileCheckpointer`) persists the entire `DelegationState` at every super-step. Functions `run_delegation_durable`, `run_or_resume_delegation`, and `resume_delegation` (lines 84-106 in [`delegation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/delegation.rs)) manage crash recovery and human-approval pauses by reconstructing the compiled graph and resuming from stable checkpoints.

## Graph Construction and State Management

The orchestration begins with graph compilation that type-checks the delegation pipeline:

```rust
let graph = build_delegation_graph(
    config.max_revisions,          // revision budget
    config.cancel.clone(),         // cooperative cancellation token
    config.require_review_approval,// human‑approval gate?
    run_stage,                     // closure that actually runs a sub‑agent stage
)?;

```

The resulting `CompiledGraph<DelegationState, DelegationUpdate>` carries a `ClosureStateReducer` (lines 20-52 of [`delegation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/delegation.rs)) that merges `DelegationUpdate` emissions from each node into a single `DelegationState` struct. This reducer ensures that partial outputs from the planning, execution, and review stages accumulate deterministically across graph traversals.

## Steering Handles and Runtime Control

Every detached sub-agent task registers a `SteeringHandle` in the process-local registry:

```rust
pub(crate) fn shared_steering_registry() -> &'static SteeringRegistry {
    STEERING_REGISTRY.get_or_init(SteeringRegistry::new)
}

```

When initiating a background turn, the system creates and registers the handle:

```rust
let handle = openhuman_steering_handle(SteeringRunClass::Background);
registry.register(task_id.clone(), handle);

```

The registry serves as the lookup seam for the rest of the core, enabling external components to issue steering commands against specific `TaskId` instances without direct coupling to the graph execution.

## Durable Human-Approval Workflows

When `DelegationConfig::require_review_approval` is enabled, the review node routes to an interrupt node named `approval`. On first entry with `ctx.resume == None`, the node returns `NodeResult::Interrupt`, which the tinyagents runtime persists as a checkpoint in `Sync` durability mode. The interrupt payload carries the current reviews, executions, and revision count (lines 71-84 of [`delegation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/delegation.rs)).

The caller receives a `DelegationOutcome` with `pending: Some(PendingApproval { … })`, using the `thread_id` as the resumption key. Resumption rebuilds the identical graph and invokes `CompiledGraph::resume` with a command carrying the approver's decision:

```rust
let command = Command::default().resume = Some(decision);
resume_graph(config, command, run_stage).await?;

```

The `decision_is_approve` function (lines 86-104) accepts stable RPC strings (`"approve_once"`, `"approve_always_for_tool"`, `"deny"`), boolean values, or objects with an `approved` field. If the checkpoint schema is outdated or incompatible, `run_or_resume_delegation` automatically prunes the thread and starts fresh.

## Safety Mechanisms and Observability

The delegation graph implements multiple safety boundaries to prevent runaway execution.

**Cancellation and Bounds.** A `CancellationToken` checked at each node entry triggers an immediate jump to `finalize` with a `Cancelled` update if set. The `RecursionPolicy` enforces `max_visits_per_node = max_revisions + 2` and total step limits, ensuring that non-terminating reviewer loops cannot exhaust resources.

**Observability.** All graph events stream to a `GraphTracingSink` (line 18 of [`orchestration.rs`](https://github.com/tinyhumansai/openhuman/blob/main/orchestration.rs)), forwarding the entire delegation lifecycle to OpenHuman's tracing system for logging and telemetry analysis.

## Implementation Examples

### Running a Simple Delegation

For scenarios without human gates or checkpointing:

```rust
use openhuman::agent::tinyagents::{
    delegation::{run_delegation, DelegationConfig, DelegationStage, DelegationStageOutput},
};

async fn example() {
    // A mock stage worker that just returns static text.
    let mock_stage = |stage: DelegationStage, _state| async move {
        Ok(match stage {
            DelegationStage::Plan => DelegationStageOutput::done("PLAN"),
            DelegationStage::Execute => DelegationStageOutput::done("EXEC"),
            DelegationStage::Review => DelegationStageOutput {
                text: "review‑ok".into(),
                approved: true,
                prompt: None,
            },
        })
    };

    let state = run_delegation(DelegationConfig::default(), mock_stage)
        .await
        .expect("delegation finished");

    println!("Final output: {:?}", state.final_output);
}

```

### Durable Delegation with Human Approval

For production workflows requiring persistence and human oversight:

```rust
use openhuman::agent::tinyagents::delegation::{
    run_delegation_durable, resume_delegation,
    DelegationConfig, DelegationStage, DelegationStageOutput,
};
use tinyagents::graph::checkpoint::FileCheckpointer;
use std::sync::Arc;
use serde_json::json;

#[tokio::main]
async fn main() {
    // Persistent checkpoint directory
    let cp = Arc::new(FileCheckpointer::new("./checkpoints"));

    let cfg = DelegationConfig {
        require_review_approval: true,
        checkpointer: Some(cp.clone()),
        thread_id: Some("my-run".to_string()),
        ..DelegationConfig::default()
    };

    // Run the graph – it will pause on the `approval` interrupt.
    let outcome = run_delegation_durable(cfg.clone(), mock_stage).await.unwrap();
    let pending = outcome.pending.expect("should be paused");
    println!("Paused on node: {}", pending.node);

    // Simulate a human approving the result.
    let decision = json!("approve_once");
    let resumed = resume_delegation(cfg, decision, mock_stage).await.unwrap();

    println!("Final output after approval: {:?}", resumed.state.final_output);
}

// Same mock worker as in the first example.
fn mock_stage(stage: DelegationStage, _state: DelegationState) -> impl Future<Output = Result<DelegationStageOutput, String>> {
    async move {
        Ok(match stage {
            DelegationStage::Plan => DelegationStageOutput::done("PLAN"),
            DelegationStage::Execute => DelegationStageOutput::done("EXEC"),
            DelegationStage::Review => DelegationStageOutput {
                text: "review‑ok".into(),
                approved: true,
                prompt: None,
            },
        })
    }
}

```

### Registering a Steering Handle

To enable external control of background sub-agents:

```rust
use openhuman::agent::tinyagents::orchestration::{
    shared_steering_registry, openhuman_steering_handle, SteeringRunClass,
};
use tinyagents::graph::orchestration::TaskId;

// Create a unique task identifier.
let task_id = TaskId::new("researcher-subagent");

// Obtain a background‑allowed steering handle.
let handle = openhuman_steering_handle(SteeringRunClass::Background);

// Register it so other core components can issue `Cancel`, `Resume`, etc.
shared_steering_registry().register(task_id.clone(), handle);

// Later, cancel the sub‑agent:
if let Some(h) = shared_steering_registry().get(&task_id) {
    h.cancel();
}

```

## Summary

- OpenHuman implements **multi-level sub-agent delegation** through a compiled graph in [`delegation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/delegation.rs) that orchestrates plan-execute-review loops with type-safe state management.
- The **three-layer architecture** separates static graph definition (`build_delegation_graph`), runtime steering (`SteeringRegistry`), and durable checkpointing (`FileCheckpointer`).
- **Human-in-the-loop workflows** pause execution via interrupt nodes, persist `DelegationState` to disk, and resume via `resume_delegation` with structured approval decisions.
- **Safety mechanisms** include cooperative cancellation tokens, recursion bounds per node, and automatic pruning of incompatible checkpoints.
- **Observability** is achieved through `GraphTracingSink`, streaming all graph events to OpenHuman's telemetry systems.

## Frequently Asked Questions

### What is the difference between Interactive and Background steering classes in OpenHuman?

**`SteeringRunClass::Interactive`** allows only `InjectMessage` and `Pause` commands, restricting control for user-facing turns where safety is paramount. **`SteeringRunClass::Background`** permits additional `Resume`, `Cancel`, and `Redirect` operations, granting the orchestration layer full control over detached sub-agent tasks without requiring direct transcript manipulation.

### How does the system handle checkpoint schema migrations?

The `run_or_resume_delegation` function checks the persisted schema version against `CURRENT_SCHEMA_VERSION`. If the checkpoint is outdated or contains incompatible structures (such as legacy `executions: Vec<String>`), the runtime automatically prunes the thread and initiates a fresh delegation run rather than attempting risky deserialization.

### Can sub-agent delegation handle recursive planning loops?

Yes. The graph supports conditional routing from the `review` node back to the `execute` node based on the `approved` flag. The `RecursionPolicy` enforces `max_visits_per_node = max_revisions + 2`, ensuring that iterative refinement loops terminate deterministically even if the reviewer repeatedly requests changes.

### Where is the delegation graph state persisted during a human approval pause?

When the `approval` interrupt node triggers, the tinyagents runtime persists the full `DelegationState` using the configured `Checkpointer` (typically `FileCheckpointer` writing to disk). The `thread_id` specified in `DelegationConfig` serves as the stable key for resumption, allowing the process to crash or restart without losing the delegation context.