cd /news/ai-agents/workflows-a-host-agnostic-rust-engin… · home topics ai-agents article
[ARTICLE · art-69078] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

workflows: a host-agnostic Rust engine for agentic workflows (open source)

A developer has released Workflows, an open-source Rust engine for agentic workflows that is host-agnostic and never hard-codes vendors. The engine models automations as directed graphs, supports human-in-the-loop approval as a primitive, and provides reliability features like per-node error handling and bounded retry.

read5 min views1 publishedJul 22, 2026

Workflows is a Rust library crate (not a hosted service; the crate name on crates.io/GitHub is tinyflows) that models an automation as a WorkflowGraph: a directed graph of typed nodes and edges. You build or generate that graph, it gets structurally validated, compiled into an opaque CompiledWorkflow, and lowered — once per run — onto tinyagents, a state-graph execution engine, via engine::run.

model::WorkflowGraph -> validate -> compiler::compile -> engine::run

(typed graph) (structural) (validated handle) (lowers onto

                                                              tinyagents,

                                                              drives to done)

Run state is a single JSON value shaped like { "run": { "trigger": … }, "nodes": { "": { "items": [ … ] } } }. A merge reducer folds each node's output under its own id, so independent branches never collide — which is what keeps parallel fan-out deterministic.

The node catalog

Kind

What it does

trigger

Entry node that starts the workflow (exactly one per graph); firing mode is host-driven

agent

Runs an LLM agent turn, with optional chat-model / memory / tool / output-parser sub-ports

tool_call

Invokes one specific integration action deterministically, no LLM involved

http_request

Outbound HTTP request

code

Sandboxed user code (JavaScript or Python)

output_parser

Parses/validates an upstream agent's output into a structured shape

sub_workflow

Runs another workflow as a nested sub-graph and returns its output

condition

Two-way IF, emits on true/false

switch

Multi-way branch keyed by an expression result

merge

Fan-in barrier — waits for every wired predecessor before running

split_out

Fan-out — emits one item per element of a list

transform

Pure, expression-based field mapping over the run state

Data flows between nodes as arrays of items shaped { json, binary?, paired_item? } — closer to n8n's item-based model than a plain function-composition DAG — and node config can reference the run scope with =-prefixed expressions like =item.name.

The part I actually want to talk about: host-agnosticism

Every place this engine would normally have to make a decision about who it's talking to — which LLM, which integration provider, how HTTP requests actually go out, where state gets persisted — is instead a Rust trait the embedding application implements:

LlmProvider

ToolInvoker

HttpClient

CodeRunner

StateStore

The crate itself never hard-codes a vendor and never makes a real network call on its own. For testing (and for the hello_workflow example below), a mock cargo feature ships deterministic in-memory implementations of all five traits.

This matters for two reasons beyond the obvious "don't vendor-lock the library" one. First, credentials never touch the crate at all — connections are opaque connection_ref values that only the host resolves into real secrets, so a bug in Workflows can't leak a token it never had. Second, it means the exact same compiled workflow can run against mocks in CI and against real capabilities in production, with no branching logic in the workflow definition itself.

Human-in-the-loop as a primitive, not a callback you bolt on

A node can be marked requires_approval. When the engine hits one, the run s and shows up in RunOutcome::pending_approvals — the host can surface that however it wants (a UI diff, a Slack message, whatever), and engine::resume picks the run back up once a human approves it.

We built this because "the agent drafts it, a person approves it, then it actually sends" is the whole trust model of the product feature this powers — it needed to be a real -and-resume in the execution model, not something the host application fakes by re-running the workflow from the top.

Reliability, per node

on_error policy: stop, continue, or route a failure to a dedicated error output port, so you can build an actual recovery sub-graph instead of just failing the run.

Bounded retry.

Observability via tracing, plus a RunObserver hook and Run/ExecutionStep records if you want to build your own run inspector on top.

Try it

[dependencies]

tinyflows = "0.1"

use serde_json::{Value, json};

use tinyflows::caps::mock::mock_capabilities;

use tinyflows::compiler::compile;

use tinyflows::engine::run;

use tinyflows::model::{Edge, Node, NodeKind, WorkflowGraph};

async fn main() {

let graph = WorkflowGraph {

    nodes: vec![

        Node {

            id: "t".into(),

            kind: NodeKind::Trigger,

            type_version: 1,

            name: "start".into(),

            config: Value::Null,

            ports: vec![],

            position: None,

        },

        Node {

            id: "greet".into(),

            kind: NodeKind::Transform,

            type_version: 1,

            name: "greet".into(),

            config: json!({ "set": { "greeting": "=item.name" } }),

            ports: vec![],

            position: None,

        },

    ],

    edges: vec![Edge {

        from_node: "t".into(),

        from_port: "main".into(),

        to_node: "greet".into(),

        to_port: "main".into(),

    }],

    ..Default::default()

};

let compiled = compile(&graph).expect("compile");

let outcome = run(&compiled, json!({ "name": "Ada" }), &mock_capabilities())

    .await

    .expect("run");

println!("{}", serde_json::to_string_pretty(&outcome.output).unwrap());

}

That's the hello_workflow example in the repo — cargo run --example hello_workflow --features mock.

What's done, and what honestly isn't

Done (Phase A): the full node catalog, structural validation, per-run compilation, item-based data flow with =-expressions, linear/conditional/parallel-fan-out/merge-barrier routing, per-node error handling, human-in-the-loop approval gating, tracing observability, opaque credential references, and a versioned wire format (schema_version + per-node type_version) with a migrate framework for upgrades. It's #![forbid(unsafe_code)], MSRV 1.85, Rust 2024 edition, and runs end-to-end against the mock capabilities behind a reference-workflow e2e suite.

Not yet, and we'd rather say so than let you find out the hard way:

A real jq/jaq-style expression engine — right now a minimal dotted-path evaluator handles the =item.name style expressions, as an interim.

Retry backoff timing and per-node timeouts.

Durable, checkpointed super-step replay — resume currently re-executes deterministically rather than resuming from a saved mid-run checkpoint.

Visual and agent-first authoring tools (that's a host-side concern — it's what the OpenHuman product layer does on top of this).

The OpenHuman host integration itself — the piece that actually wires this engine to real LLMs and real integrations — is Phase B and lives in a separate repo that isn't public yet.

License

GPL-3.0-or-later. Worth knowing up front if you're evaluating it for something you plan to ship closed-source.

If you build workflow/automation engines, or you're the kind of person who has opinions about where the "capability trait" boundary should sit in a system like this, I'd genuinely like to hear where you think we got it wrong: Workflows on GitHub.

── more in #ai-agents 4 stories · sorted by recency
── more on @workflows 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/workflows-a-host-agn…] indexed:0 read:5min 2026-07-22 ·