Skip to content

Tech stack

Flow is a Rust orchestration core with a single React UI delivered through several shells. This page maps the stack for anyone working on or extending the platform.

LayerTechnology
Orchestration coreRust - domain types, executor, adapters, credential custody, model runtime bridge
Desktop shellTauri 2 (native WebView, OS credential-manager integration)
UIReact + TypeScript, built with Vite
Visual editorReact Flow (@xyflow/react)
Shared contracts@flow/shared-types - TypeScript mirrors of the Rust domain types
Local inferenceManaged llama.cpp llama-server subprocess
StorageSQLite (execution history, schedules), JSON settings, OS keyring for secrets
apps/frontend the mono React UI (+ src-tauri desktop shell)
apps/shared-types TypeScript contracts shared with any host
apps/website this marketing + docs site
crates/* the Rust platform modules
flow-domain pure types
├─ flow-security keyring, PII sanitizer, sandbox profiles
├─ flow-storage SQLite store
├─ flow-execution executor, EventSink trait, adapter registry
├─ flow-adapter-ai AI provider registry (local + cloud HTTP)
├─ flow-adapter-* shell / fs / cli / utility action dispatch
├─ flow-application FlowApp - the orchestrator owning all of the above
└─ shells Tauri desktop, flow-server (HTTP/SSE), flow-cli

Two crates sit outside the chain. flow-dsl is an independent, pure parser/serializer with no I/O. flow-spec is build-time only, and it feeds the spec pipeline below. flow-models-server owns the managed llama-server lifecycle and is reused by every edition.

The Tauri shell does three things. It registers command wrappers, manages a single FlowApp instance, and forwards events. All real logic lives in the shared core, which is exercised by integration tests without any Tauri dependency. This separation matters because it lets the same core run headless in the CLI and behind the server’s HTTP API. Keep new business logic out of the shell.

Every edition renders the same React app and drives the same core. A host facade in the frontend routes each call to the active transport, which is selected at runtime. The transport is either Tauri IPC for the desktop with an in-process core, or HTTP/SSE for the browser with flow-server. All IPC call sites are consolidated in one services directory by convention, and components never invoke the backend directly.

Four event streams cross the frontend/core boundary:

EventPayload
flow:executionThe tagged execution-event union (node lifecycle, logs, summaries)
models:install_progress{ stage, current, total, message } download/engine progress
models:registeredA model id, from the boot scan
models:scan_completeBoot scan finished

The DSL reference is generated, not hand-edited. A build script runs the spec crate’s descriptor dump and concatenates the hand-authored grammar and examples with the generated node and adapter references into one compiled spec file. That file feeds two consumers: the application core embeds it as the flow-generator system prompt, and the sibling model-training repository syncs it as training data. Sync direction is one-way, from this repository outward.

Two invariants protect this pipeline:

  • The DSL has exactly five node types with scalar-only bodies.
  • serialize(parse(s)) is a canonical-form fixed point, and it is preserved in every DSL change.