How the TinyFlows Workflow Engine Integrates with the OpenHuman Orchestrator

The TinyFlows workflow engine integrates with the OpenHuman orchestrator as an optional domain family that registers RPC controllers and agent tools, enabling the orchestrator to invoke graph-based workflows through standard tool dispatch mechanisms.

The TinyFlows engine provides comprehensive workflow orchestration to the OpenHuman agent runtime. In the tinyhumansai/openhuman repository, this integration operates through a modular domain system where the engine registers its controllers and tools with the core orchestrator, allowing AI agents to execute complex multi-step workflows defined in YAML or JSON.

Integration Architecture

Domain Registration

The integration begins at startup when the Flows domain group conditionally registers its components. In src/core/all.rs, the orchestrator pushes TinyFlows controllers into the global dispatcher only when the flows feature flag is enabled. This registration exposes RPC endpoints such as run_workflow and await_workflow through the DomainGroup::Flows implementation.

When constructing a DomainSet::full() instance, the orchestrator automatically includes the Flow namespace, making the workflow engine available to agent harnesses. This modular approach allows minimal builds to exclude the entire workflow system by disabling the feature flag during compilation.

Tool Registration

Beyond RPC controllers, TinyFlows exposes its functionality through agent tools defined in src/openhuman/tools/ops.rs. The all_tinyflows_agent_tools() function generates tool entries prefixed with tinyflows_* that wrap individual workflow nodes including conditions, loops, and sub-flows.

During turn execution, when a language model requests to run a workflow, the orchestrator's tool-dispatch system (tinyagents::harness::tool_calling) resolves these tinyflows_* tool calls. The dispatcher validates requests against the tool schema before invoking the TinyFlows executor, treating workflow execution identically to standard tool calls like http_request or shell.

Execution Runtime

At the core of the integration, src/openhuman/flows/tinyflows/engine.rs parses workflow definitions into an internal abstract syntax tree representing a directed acyclic graph (DAG). The executor walks this graph, invoking dependent tools through the core's tool dispatcher while respecting the dependency chain defined in the workflow file.

The orchestrator monitors workflow execution through the FlowTriggerSubscriber registered in src/core/jsonrpc.rs. This subscriber listens for flow-related events on the global event bus, allowing the runtime to re-hydrate paused workflows and stream execution results back into the turn transcript.

Implementation Examples

Initializing the Harness with TinyFlows Support

use openhuman_core::Harness;
use openhuman_core::provider::Provider;

// Build a harness that includes the Flow domain
let harness = Harness::builder()
    .provider(Provider::openai_compatible(
        "https://api.openai.com/v1".into(), 
        "MYKEY".into()
    ).model("gpt-4o-mini"))
    .domains(openhuman_core::core::runtime::DomainSet::full())
    .access(openhuman_core::access::Access::full())
    .build()
    .await?;

// Execute a prompt that triggers workflow execution
let result = harness
    .run("Run the workflow `my_flow.yaml`.")
    .await?;

println!("Workflow finished: {:?}", result);

This example from src/openhuman/agent/harness.rs demonstrates how the DomainSet::full() configuration automatically loads the TinyFlows domain, exposing workflow tools to the agent.

Defining a TinyFlows Workflow


# my_flow.yaml

name: "Demo workflow"
steps:
  - id: fetch
    type: http_request
    args:
      method: GET
      url: https://api.example.com/data
  - id: process
    type: shell
    args:
      cmd: "jq .value"
    depends_on: [fetch]
  - id: reply
    type: reply
    args:
      message: "The value is {{process.stdout}}"
    depends_on: [process]

The engine in src/openhuman/flows/tinyflows/engine.rs processes this YAML into a DAG where each step becomes a tinyflows::engine::Node. The executor handles dependency resolution, ensuring fetch completes before process begins, while src/openhuman/flows/tinyflows/mod.rs serves as the public entry point re-exporting these internal components.

Subscribing to Flow Events

use openhuman_core::core::event_bus::{DomainEvent, EventBus};

// Register the Flow trigger subscriber at start-up
EventBus::global().subscribe_global(
    "flows.trigger",
    |event: DomainEvent| {
        if let DomainEvent::FlowTriggered { flow_id, .. } = event {
            tracing::info!("Flow {} triggered", flow_id);
        }
    },
);

This pattern from src/core/jsonrpc.rs shows how the orchestrator tracks workflow lifecycle events through the FlowTriggerSubscriber, enabling observability and conditional logic based on workflow state changes.

Summary

  • The TinyFlows engine integrates as a conditional domain family activated via the flows feature flag in src/core/all.rs.
  • Tool registration occurs through all_tinyflows_agent_tools() in src/openhuman/tools/ops.rs, exposing workflow capabilities as standard agent tools.
  • The execution engine in src/openhuman/flows/tinyflows/engine.rs parses YAML/JSON workflows into DAGs and orchestrates step execution through the core tool dispatcher.
  • Event-driven monitoring via FlowTriggerSubscriber in src/core/jsonrpc.rs allows the orchestrator to track and manage long-running workflow instances.

Frequently Asked Questions

How do I enable TinyFlows support in a minimal OpenHuman build?

Enable the flows feature flag when compiling the core crate. In src/core/all.rs, the Flow controllers are conditionally compiled using #[cfg(feature = "flows")], ensuring the workflow engine only loads when explicitly requested. Without this flag, the DomainSet::full() method will exclude TinyFlows controllers and tools from the runtime.

Can TinyFlows workflows invoke other agent tools?

Yes. The workflow engine delegates step execution to the orchestrator's standard tool dispatcher. When a workflow step specifies type: http_request, type: shell, or custom skill types, the TinyFlows executor in src/openhuman/flows/tinyflows/engine.rs invokes these through the same interface used by direct agent tool calls, maintaining consistent sandbox and permission checks.

What file formats does the TinyFlows engine support?

The engine accepts both YAML and JSON workflow definitions. The parser in src/openhuman/flows/tinyflows/engine.rs deserializes these into an internal AST representation (tinyflows::engine::Workflow), constructing a dependency graph that respects the depends_on relationships defined between steps.

How does the orchestrator handle asynchronous workflow execution?

The orchestrator treats workflow execution as an asynchronous tool call. The FlowTriggerSubscriber in src/core/jsonrpc.rs monitors the event bus for FlowTriggered events, allowing the system to manage paused workflows and stream partial results back to the agent transcript without blocking the main execution thread.

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 →