Introduction
flowG: The flowG FunctionGraph IR: types, codegen, runtime, OpDispatch backends, energy receipts.
This is the official documentation for flowG. The full source code lives in the private -core mirror; the public release surface is at openIE-dev/flow-g.
What you'll find here
- Install: get the
flowgbinary on your machine - Hello, flowG: first program in 30 seconds
- Tutorial: a 30-minute hands-on guided tour
- Reference: every feature, every flag, every API
- Cookbook: task-oriented recipes
- Design: why flowG exists and how it fits with the rest of openIE-dev
The openIE-dev ecosystem
flowG is one of five public openIE-dev projects. All five share a common substrate (flowG) and energy-metering layer (substrate-energy):
- flow-g: the IR + runtime substrate
- lux-lang: reactive language compiling to flowG
- jmax: math-native language
- joule-lang: energy-budgeted compiled language
- jouledb: energy-metered database
License
flowG binaries are distributed under BSL-1.1. Documentation under CC-BY-4.0. Examples under Apache-2.0.
Install
flowg is published to crates.io and to GitHub Releases.
Fastest: cargo binstall
cargo binstall flowg
cargo-binstall fetches the prebuilt binary for your platform from GitHub Releases without compiling anything.
If you don't have cargo-binstall yet:
cargo install cargo-binstall
From source: cargo install
cargo install flowg
This compiles the source. Slower; useful if your platform isn't in our prebuilt list.
Direct download
curl -fsSL -o flowg.tar.gz \
https://github.com/openIE-dev/flow-g/releases/latest/download/flowg-$(uname -s)-$(uname -m).tar.gz
tar xzf flowg.tar.gz
mv flowg-*/flowg /usr/local/bin/
Verify
flowg --version
Hello, flowG
The minimum example. See the source in examples/hello/.
For a richer walkthrough, see the tutorial.
Tutorial
A 30-minute guided tour of flowG from install to a working program.
Tutorial chapters coming with v0.2.0. For now see examples/ for runnable code.
Reference
flowG's kernel is small: 22 universal primitives and 11 wire kinds: a
closed, fixed vocabulary for every programming pattern. This reference documents
the FunctionGraph IR that realizes them; the Lux/compute projection extends the
22 with tensor and aggregate nodes (TensorLiteral, StructCreate, …) and an
Custom(op) extension point for kernels.
For the embedding API (the Rust flowg crate), see
docs.rs/flowg.
Core types
| Type | What it is |
|---|---|
| FunctionGraph | The IR. A DAG of nodes and wires with a name, an output node, and a return type. ProgramGraph bundles functions, an entry point, and per-function effect-allow declarations. |
| GraphNode | The node kinds: Param, Literal, TensorLiteral, Apply{op}, Select, WhileLoop, Call, Match, CodeBlock, plus capability and concurrency nodes. |
| OpKind | The operation an Apply performs: arithmetic / comparison / logic primitives, plus Custom(String): the open extension point every kernel hooks (matmul, ssm_scan, rms_norm, …). |
| WireKind | Edge semantics: Move (default), Borrow, MutBorrow, Copy, Channel, Shared, Weak, Stream, Error, Lazy, Feedback. Ownership, generalized. |
| TensorLiteralData | A shaped, typed constant. Weights stay out of band in a safetensors sidecar and are reattached by name. |
| CapabilityRef | A gated call: capability id + version + slot + method + effects. No ambient authority; effects are checked at dispatch. |
Targets
The same graph dispatches across targets through OpDispatch, addressed by
(op, dtype, layout, target):
| Target | Backing |
|---|---|
| CPU | reference kernels + BLAS (Accelerate / OpenBLAS / MKL) |
| Apple Silicon | Metal / MPS fused kernels |
| NVIDIA | CUDA (cuBLAS) |
| Portable GPU | WGPU (Vulkan / Metal / DX12) and the browser (WASM + WebGPU) |
| AMX | Apple matrix coprocessor |
Uncovered ops fall through to the CPU reference path, so a graph always runs.
Energy receipts
Every dispatch carries an EnergyEstimate { picojoules, measured }. Placement
prefers measured calibration (IOReport on Apple Silicon, NVML on NVIDIA, RAPL
on x86_64 Linux) over the analytical prior. A run can emit a per-op receipt,
see the energy-receipt example.
Emitters
flowG can lower the same graph to source for other ecosystems (WGSL, WASM,
ONNX, StableHLO, MLIR-linalg, Triton) and to its own .fg binary format. See
the wgsl-codegen example.
See also
- Install · Hello, flowG
- Examples: runnable programs per backend
- docs.rs/flowg: embedding API
Cookbook
Task-oriented recipes.
Cookbook recipes coming with v0.2.0.
Why flowG
flowG makes three choices, each chosen for the value it returns, in time, energy, and cost.
1. A program is a typed graph: text is one view of it
flowG's IR is a FunctionGraph: a typed dataflow graph of nodes and wires, not an AST or a flat token stream. Functions are first-class graph nodes with typed signatures. Control flow, data flow, ownership, concurrency, and capability gating are all edges in the same graph.
Storing code as what it actually is, a graph, means the structure a compiler normally has to recover from text is already present. Analysis, rewriting, and dispatch operate on the graph directly.
2. One graph, many silicons: heterogeneous by default
Kernels are addressed by (op, dtype, layout, target) tuples through the
OpDispatch backend. The same FunctionGraph runs on CPU, Apple-silicon
Metal, WGPU, and AMX. The runtime selects the kernel that fits the target.
There is no "GPU port": you dispatch the same graph at a different target, and
the device-resident path is the same typed object the CPU ran.
This is what lets a model runtime, a numerical kernel, and a compiled application share one substrate instead of one stack per device.
3. Energy is a first-class output
Every op carries a measured picojoule cost, IOReport-backed on Apple Silicon, NVML on NVIDIA, RAPL on x86_64 Linux. The runtime can pick the lowest-joule kernel that matches a dispatch, and every run can emit an energy receipt: a per-op accounting of what the work actually cost.
Energy stops being invisible. It becomes something you can budget at compile time, measure at run time, and optimize against, the same way you'd optimize for latency or memory.
What that buys you
- flowG is the omni-language. It isn't a fixed number of languages. Its own surfaces (lux, JMax, Joule) and any language with a tree-sitter grammar (Rust, Python, Go, Haskell, C, Swift, …) are the same graph wearing different syntax. The graph is canonical; every language is a projection.
- Materialize to any of them. Emitting source is a deterministic graph→text function, roundtrip-tested, no model in the loop, so the projections never drift.
- Lower to many silicons. CPU, Metal, WGPU, AMX share the IR; the compute emitters target WGSL, WASM, ONNX, StableHLO, MLIR-linalg, Triton, and .fg.
- Meter every operation. Picojoule receipts, first-class.
flowG is the substrate the openIE-dev language family compiles to. See How flowG fits the ecosystem.
The math under the graph
▶ Interactive version: flowg-lang.dev/math: the same five results with live diagrams.
flowG's claims aren't aesthetic. They fall out of five well-understood results, from information theory, computation theory, type theory, and physics. Here is the reasoning, including where a claim is a theorem and where it's an empirical bet.
01 · Information theory: the graph is the structure text represents
A program is a typed graph G = (V, E): nodes are operations and values, edges
carry how those values relate. Writing it to a file is a serialization
s : G → Σ* onto a one-dimensional string. Compiling is the inverse p : Σ* → G.
the round trip a compiler runs on every build:
source text ──parse──▶ tokens
──name resolution──▶ bindings (which definition does this name mean?)
──type inference────▶ types (what is the type of this expression?)
──flow analysis─────▶ data & control edges
──borrow / lifetime─▶ ownership (who owns, who borrows)
= G (the graph the author already had in mind)
Two properties make the graph the natural shared form. First, text is
redundant: many strings denote the same graph (whitespace, ordering, names form
equivalence classes with no semantic content), so s is not injective in reverse.
Second, text is structure-implicit: bindings, types, ownership, and flow are
not written down, so the compiler re-derives them every build, and that re-derivation
is the reconstruction of G.
flowG stores G, the canonical, structure-explicit form, and derives text on
demand. The re-derivation every build repeats becomes a one-time, reusable fact, so
the whole toolchain shares one source instead of rebuilding it from text.
02 · Computation theory: a closed kernel of 22 primitives
The structured program theorem (Böhm–Jacopini, 1966) showed all computable control flow reduces to sequence, selection, iteration. flowG extends that spine across the other axes a real program needs and closes the set at 22:
| Category | Primitives |
|---|---|
| Computation (10) | Bind, Apply, Mutate, Branch, Iterate, Match, Sequence, Compose, Abstract, Import |
| Resource (3) | Acquire, Release, Observe |
| Error (2) | ErrorPropagate, CodeBlock |
| Concurrency (4) | Spawn, JoinAwait, YieldSuspend, Listen |
| Data / State (2) | Transact, TypeDefine |
| Temporal (1) | FeedbackDelay |
Theorem vs. bet, said plainly: Turing-completeness from a small set is trivial
and proves nothing interesting. The real claim is ergonomic completeness: that
these 22 express every pattern across paradigms without awkward encodings. That
is an empirical bet, not a theorem, and the evidence for it is the omni-language
round trip: parse real code in any language with a tree-sitter grammar into these
primitives, and materialize it back. (The kernel is
inv-ai-codegraph::flowg::FlowgNodeKind, pinned at 22 by test.)
03 · Determinism: materialization is a pure function
Emitting a language is a referentially transparent function of the graph and the target, with no hidden state, no sampling, no model in the loop:
emit : Graph × Language → Text
- Deterministic: same graph, same output, byte for byte. No temperature, no seed.
- Idempotent: re-materializing changes nothing; there is nothing to "regenerate."
- Drift-free: all N projections are
emit(G, Lᵢ)of oneG, so they cannot disagree.
"Zero drift across languages" is therefore not a process discipline you maintain;
it's a property of pure functions. Change G; every projection follows by
construction. (This documentation set and the website are built the same way: one
canonical source, every page a projection of it.)
04 · Type theory: wires are a substructural algebra
Each of the 11 wire kinds is a typing rule on how a value passes from producer to consumer, the same substructural type theory (Girard's linear logic; Wadler, "linear types can change the world") that underlies Rust's ownership, lifted onto the edge itself.
| Wire | Discipline |
|---|---|
| Move | linear, consumed exactly once |
| Borrow | non-consuming read; source retained |
| MutBorrow | exclusive, at most one at a time |
| Copy | unrestricted, freely duplicable |
| Shared / Weak | counted ownership; cycle-breaking |
| Stream / Lazy / Feedback | temporal & deferred discipline |
Whole bug classes become structurally impossible:
- Use-after-move: a
Moveconsumes the source; it has no output port to wire from. - Data race:
MutBorrowis exclusive; a second mutable edge is rejected at edit time, not run time. - Deadlock: circular
Acquirechains are caught by cycle detection (Kahn's topological sort, 1962).
05 · Physics: energy is a first-class cost
Every operation carries a picojoule cost, modeled as a linear function of the work it does and fit from measured silicon. Data movement dominates arithmetic by orders of magnitude (Horowitz, 2014):
E(op) ≈ a·flops + b·bytes + c with b ≫ a
Placement is then an optimization that routes each op to the backend minimizing estimated joules, preferring measured calibration over the analytical prior, and the receipt is the sum:
place(op) = argmin_backend Ê(op, backend)
receipt = Σ E(op)
This is not theory on a slide. On real hardware, a resident decode reported a
whole-SoC receipt of ~445 mJ/token, and the linear coefficients above were fit
by ordinary least squares from measured joules, confirming, as the model predicts,
that weight movement (the b·bytes term) dominates the energy.
Five results, one object
The graph is canonical, the kernel is closed, materialization is pure, the wires are typed, and every op is costed in joules. None of these are bolted together; they're five views of a single structure. That's why flowG is a substrate and not a feature.
See also: History · Why flowG · Reference.
History: an idea the field has been building toward
▶ Interactive version: flowg-lang.dev/history: the same lineage with a live interaction-net reducer you can poke at.
"Code is structure" is one of computing's oldest and most beautiful ideas, explored by brilliant people for fifty years, each generation advancing it and each right for its time. flowG doesn't claim to have invented it. It builds on all of it, and the moment is finally right: parallel silicon everywhere, compute in the browser, and energy worth measuring.
Text built the modern world (1945)
When von Neumann described the stored-program computer, the teletype made text the natural way to write and read code, and it was exactly right. For eighty years a whole civilization of wonderful tools grew on it: editors, parsers, formatters, diffs, version control. flowG keeps all of that. Text stays the surface people love; the graph it represents becomes shared too.
Everything else became a graph (today)
The silicon is parallel. The computation is a parallel graph. The intelligence we built on top (attention) is graph-structured. At every layer the world is relational and multidimensional. flowG lets the source code share that shape too, working at the structure directly, while text stays the surface you read and write.
The lineage: six threads, fifty years
flowG is a synthesis, not a bolt from the blue. Each of these communities found a piece of it; the contribution is connecting them, and adding energy as the spine.
01 · Dataflow & visual programming (1970s →)
Jack Dennis & Arvind (MIT dataflow) · LabVIEW "G" (1986) · Prograph · Max/MSP · Pure Data · Simulink · Node-RED · Enso. The first machines and languages where computation is a graph of operations that fire when their inputs are ready. Lesson: graphs win where the work is dataflow (signal, instrumentation, control, ETL). They stalled on branchy, stateful control. That was a UX problem, not a theory one.
02 · Graph reduction & interaction nets (1990 →)
Lévy & Lamping (optimal reduction) · Yves Lafont (interaction nets 1990, combinators 1997) · HVM / Bend. The most rigorous form of "the graph is the program": computation is local graph rewriting that is inherently parallel. Lesson: a reduction model maps onto parallel silicon more naturally than a sequential one ever could.
03 · Content-addressed code (2010s →)
Unison (Paul Chiusano, Rúnar Bjarnason) · cousins: Git, Nix, IPFS. Every definition is identified by the hash of its syntax tree; names are labels, so there are no merge conflicts, perfect caching, trivial code mobility. Lesson: the closest existing answer to "let a machine mutate code without breaking the build."
04 · Projectional & structural editing (1981 →)
Cornell Program Synthesizer (Teitelbaum, 1981) · Intentional Programming (Simonyi, MSR) · JetBrains MPS · Hazel (typed holes) · Lamdu. Edit the tree, not the characters, so a program is never syntactically broken. Simonyi's "intentional tree with text as one projection" is almost exactly flowG's thesis, thirty years early. Lesson: people rightly loved text. It is fast to write, and the whole toolchain speaks it. flowG keeps text as a first-class surface and adds the graph beneath, so people and machines each work in the form that suits them. That is why the idea is ready now.
05 · ML graph IRs (2015 →)
Theano / TF1 · PyTorch & JAX (jaxpr) · ONNX · MLIR (Lattner, 2019) · XLA / StableHLO · TVM · IREE · Triton · GGML · MLX. Machine learning rebuilt all of this for tensors: trace a program into a graph, lower one graph to many backends. JAX is explicit: Python is a frontend to a graph. Lesson: one-graph-many-silicons is table stakes for tensors. flowG's contribution is generalizing it beyond tensors, to all code, with resource-typed wires and energy as a first-class unit.
06 · The energy basis (2014 →)
Mark Horowitz, "Computing's Energy Problem" (ISSCC 2014). The much-cited table putting hard picojoule numbers on primitive operations: an 8-bit add costs a sliver of a pJ; a DRAM access, hundreds to thousands of times more. Data movement, not arithmetic, is where the joules go. Lesson: flowG operationalizes that table as a placement pass that routes each op to the lowest-joule silicon, and hand back a receipt.
The evidence: the field keeps rediscovering the substrate
Recent research keeps finding, empirically, that under the syntax of every language there is a shared, language-agnostic structure, and that operating on it works better. These aren't flowG's results; they're the ground it's built on.
| Work | Where | Finding |
|---|---|---|
| LACE | IBM, NAACL 2024 (arXiv:2310.16803) | Code embeddings contain separable syntax and language-agnostic semantics. |
| Semantic Hub | 2024 (arXiv:2411.04986) | LLMs develop a shared representation across languages and modalities. |
| IRCoder | UKP Lab, ACL 2024 (arXiv:2403.03894) | Forcing models through a shared IR gives consistent multilingual gains. |
| ProGraML | ETH Zürich, ICML 2021 (arXiv:2003.10536) | Language-agnostic graphs reach 94% F1 on compiler analysis across six languages. |
| CodeGRAG | 2024 (arXiv:2405.02355) | Control-/data-flow graphs from one language improve generation in another. |
| UniCoder | ACL 2024 (arXiv:2406.16441) | Routing through a universal pseudocode improves generation. Even a naïve substrate helps. |
Each validated a piece in isolation: embeddings, intermediate representations, read-only graphs, pseudocode. The remaining work was to make the graph the source of truth, give it resource-typed wires, and meter it in joules.
Why now: the moment is right
Text earned its place: people write it fast, and the whole toolchain (diff, review, blame, the terminal) speaks it beautifully. flowG keeps every bit of that and adds a shared graph beneath, so people keep their surface while every language and every chip gain one too. What's new is the timing: parallel silicon everywhere, WebGPU putting compute in the browser, and energy finally something we can measure and save.
So this is not a claim of novelty. It's a claim of timing, and of cause. We're building the thing fifty years of brilliant work has been circling, in the open, because energy-efficient compute is worth building. Stand on the shoulders; carry it the last step.
See also: The math under the graph · Why flowG.
How flowG fits the openIE ecosystem
Five public projects share a common substrate:
lux-lang jmax joule-lang
\ | /
\ | /
▼ ▼ ▼
flow-g ← ← ← jouledb (metered persistence)
▲
│
substrate-energy
(joules)
flowG is the substrate
Everything else is a surface over, or a consumer of, the same typed FunctionGraph IR. That is the whole point: one substrate, many fronts, one energy model.
- lux-lang: a general-purpose, reactive language. Lux source compiles to flowG; the graph is what runs.
- jmax: a math-native language for numerical and scientific work, lowered to flowG so the same kernels and the same energy model apply.
- joule-lang: an energy-budgeted, self-hosted language: energy limits are part of the program, enforced through flowG's metered dispatch.
- jouledb: the energy-metered database. It stores graphs and records inference receipts, closing the loop between what ran and what it cost.
- substrate-energy: the joule-accounting layer underneath flowG: IOReport on Apple Silicon, NVML on NVIDIA, RAPL on x86_64 Linux. Every op's picojoule cost flows from here.
Why a shared substrate
Each language above could have shipped its own compiler, its own runtime, and its own per-device backends. Instead they target one IR, which means:
- One set of kernels. A matmul, an SSM scan, an attention op is written once against OpDispatch and is available to every surface, on every target.
- One energy model. A Lux program, a JMax computation, and a model runtime are all metered the same way, in the same units, against the same receipts.
- One heterogeneous story. CPU / Metal / WGPU / AMX support is shared, not re-implemented per language.
flowG itself is the public release surface (openIE-dev/flow-g); the full source is the private mirror (openIE-dev/flow-g-core).