{"slug": "building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk", "title": "Building a self-hosted, AI-native workflow engine in Rust (180 node types, no SDK bloat)", "summary": "A developer built Trigix, an open-source (MIT), self-hostable workflow automation platform with a Rust execution engine and AI nodes that can run against local models. The platform features ~180 node types, each implemented as a variant of a NodeType enum with an async function, and avoids system dependencies at build time by using pure-Rust implementations or runtime shell-outs. The engine supports async DAG scheduling with parallel fan-out/fan-in, retries, timeouts, cancellation, and sub-workflows.", "body_md": "I've spent the last while building ** Trigix** — an open-source (MIT), self-hostable workflow automation platform. Think n8n, but the execution engine is in Rust and the AI nodes can run entirely against local models. This post is about a few engineering decisions I think are worth sharing, not a feature tour.\n\nA workflow is a DAG of typed nodes. Every node is one variant of a `NodeType`\n\nenum and one async function:\n\n``` js\nmatch node.node_type {\n    NodeType::Http     => execute_http(node, ctx, &client).await,\n    NodeType::Agent    => execute_agent(node, ctx, &client, ai_url).await,\n    NodeType::Sqs      => execute_sqs(node, ctx, &client).await,\n    // … ~180 arms\n}\n```\n\nAdding a node type touches a fixed set of places (enum variant, executor impl, dispatch arm, a `node_type → str`\n\nmap, and the frontend palette/config panel). It's mechanical, which is the point: the cost of a new integration is bounded and reviewable, and the compiler tells you if you forgot a touch point.\n\nThe engine itself is the interesting part — async DAG scheduling with parallel fan-out/fan-in, retries, timeouts, cancellation, and sub-workflows — but the node catalog is where most of the surface area lives, so I optimized hard for \"cheap to add, hard to get subtly wrong.\"\n\nMost SaaS/DB/vector-store/cloud nodes are thin HTTP clients that return `{ status, body }`\n\n. The value of a first-class node over \"just use the generic HTTP node\" is the curated config UI and auth handling, not raw capability. That framing kept ~150 of the nodes small and uniform.\n\nFor cloud services I leaned on caller-supplied tokens where possible (e.g. GCS, Vertex AI, BigQuery, Snowflake all take a bearer token) instead of baking in each provider's OAuth dance. Honest trade-off: less magic, but no giant SDK per provider and no credential-exchange code to maintain.\n\nA self-hosted tool has to build everywhere with `cargo build`\n\n, with no \"first install these system libraries\" footnote. That constraint drove a few choices:\n\n**AWS (SQS/SNS/Bedrock).** Instead of pulling in the AWS SDK, I implemented **Signature V4 from scratch** with the crypto crates already in the tree (`sha2`\n\n/`hmac`\n\n/`hex`\n\n). The reassuring part: AWS publishes a SigV4 test suite, so the signer is unit-tested against the canonical `get-vanilla`\n\nvector:\n\n```\n// The signer must reproduce AWS's published signature exactly.\nassert!(auth.ends_with(\n  \"Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31\"\n));\n```\n\nThat single test is worth more than a hundred round-trip mocks — it pins the canonical-request and signing-key derivation to a known-good answer.\n\n**SSH/SFTP.** The obvious crate (`ssh2`\n\n) binds to libssh2 — a system dependency that breaks the build for anyone without the dev headers (and `cmake`\n\n). So I used **russh + russh-sftp**, a pure-Rust SSH implementation. `cargo build`\n\nstays self-contained; password and private-key auth both work.\n\n**SQL Server.** Same reasoning — `tiberius`\n\nis a pure-Rust TDS driver, so the MSSQL node needs no native client.\n\n**OCR.** This one I *couldn't* keep pure-Rust without a heavy native dependency, so instead of linking libtesseract at build time, the node shells out to the `tesseract`\n\nCLI at runtime. The workspace still builds everywhere; OCR just needs the binary present when that node actually runs. Being explicit about that boundary beats a build that fails on a clean machine.\n\nThe theme: a system dependency at **build** time is a tax on every contributor and CI run; a dependency at **runtime** is opt-in and only paid by the people who use that feature.\n\nThe LLM/agent/RAG nodes speak the OpenAI-compatible wire format, so you can point them at a local **Ollama** or **vLLM** and run the whole AI side offline. RAG retrieval runs on your own Postgres/pgvector with hybrid (vector + full-text) search, optional reranking, and an HNSW index. Cloud providers are optional, not assumed — which matters if you're self-hosting precisely to avoid sending data out.\n\n```\ndocker compose -f docker-compose.poc.yml up -d --build\n```\n\nThat brings up the console/API, Postgres+pgvector, Redis, and an optional AI runtime. There's also a Helm chart on GHCR and a one-click GitHub Codespaces devcontainer if you want to poke at it before committing a VM.\n\n**Honest status:** it's young and I'm the primary author; 600+ tests and a v1.3.0 release, but treat it accordingly. And full transparency since it's relevant on this platform — I used AI coding assistants while building it; it's a real, tested codebase, not a one-shot generated repo.\n\nRepo: [https://github.com/bj-qizhi/trigix](https://github.com/bj-qizhi/trigix) — feedback on the engine design and the node model especially welcome.", "url": "https://wpnews.pro/news/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk", "canonical_source": "https://dev.to/_34d3c9ee969f97a6c811fb/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk-bloat-266b", "published_at": "2026-06-16 18:03:59+00:00", "updated_at": "2026-06-16 18:18:13.882868+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "ai-infrastructure", "ai-agents"], "entities": ["Trigix", "Rust", "Ollama", "vLLM", "Postgres", "pgvector", "AWS", "Snowflake"], "alternates": {"html": "https://wpnews.pro/news/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk", "markdown": "https://wpnews.pro/news/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk.md", "text": "https://wpnews.pro/news/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk.txt", "jsonld": "https://wpnews.pro/news/building-a-self-hosted-ai-native-workflow-engine-in-rust-180-node-types-no-sdk.jsonld"}}