FloMorphic
Contract-Driven AI
Today's AI systems are powerful, but difficult to control. They reason, choose tools, and take actions — often hiding critical decisions inside prompts, code, or agent runtimes. FloMorphic introduces a different approach.
Experts define the process, the valid states, the allowed transitions, the policies, and the approvals. AI contributes judgment within those boundaries.
Business processes govern how AI operates
The prevailing model puts an autonomous agent in charge of a business process. FloMorphic inverts it. The process is defined first — its valid states, its allowed transitions, its policies, its approval points — and the model operates inside that definition.
The result is AI that remains visible, controllable, auditable, and adaptable while still benefiting from modern reasoning models. Judgment is what you want from a model. Control is what you want from the system around it.
LLM
│
┌─────┴─────┐
│ │
tools decisions
│ │
└─────┬─────┘
│
outcomeThe model owns the process. You see the result, not the path that produced it.
Process
│
┌────┼────┬────────┐
│ │ │ │
policy LLM human tools
│ │ │ │
└────┼────┴────────┘
│
outcomeThe process owns the outcome. The model is one participant, bounded by the contract.
Instead of autonomous agents controlling business processes, business processes govern how AI operates.
A smart contract for AI-powered systems
The same idea a smart contract applies to value, FloMorphic applies to behavior: the rules are declared up front, they are enforced by the runtime rather than by good intentions, and what happened is inspectable afterwards.
This is not a metaphor
Contract is one of the six primitives the runtime actually executes. A Rule node compiles to one: its logic — JavaScript or an OPA/Rego policy — runs against the scoped context and returns a set of tags, and the engine follows only the transitions whose tags match. The thing that decides which paths are permitted is named Contract, is deterministic, and is evaluated outside the model.
What the design commits to
Explicit processes
Over hidden agent behavior. What the system does is composed and readable, not emergent from a prompt.
Composable primitives
Over specialized abstractions. Capabilities are compositions of a small closed set, not features the platform grants you.
Context as a first-class artifact
Not an implementation detail. The working document of a process is the central object, not state threaded through callbacks.
Governance and control
Over blind autonomy. Policy, limits and approval are steps in the process, evaluated outside the model.
Human and AI in one workflow
Collaboration inside the same process, not a separate escalation system bolted alongside it.
Integration, not replacement
Existing systems are reached and extended. Nothing has to be migrated into the platform to participate.
Stated plainly
A workflow-centric runtime for building AI-powered systems from explicit primitives.
- A no-code automation tool.
- A collection of pre-built integrations.
- A black-box agent framework.
Six primitives, and nothing reserved
FloMorphic is a product layer on the Inflowenger runtime. Its canvas nodes speak the language of what you are building; the runtime underneath knows only six node types. Every node records which one it lowers to — and that annotation is visible in the product, not buried in a compiler.
Void
voidStructure — start markers, joins, barriers, dead ends.
Code
codeComputation — run JavaScript or OPA/Rego against the scoped context.
Contract
contractDecision — evaluate a rule, emit tags, fire the matching branches.
Extrinsic
extrinsicCall a service you own, over one request/reply subject.
Plugin
pluginA live external process — the open-ended escape hatch. Never compiles away.
GoTo
gotoComposition — jump into another flow and return.
Five of the six are compiled artifacts. Plugin is the exception — it never compiles away, because it is a real external process with its own connections, its own background loops and its own configuration form. That is why a model call, an MCP client and a field-mapper can all be plugin nodes without the runtime knowing what any of them mean.
From canvas to execution
- AuthorCompose nodes on the canvas, configure them, connect their handles.
- SaveThe raw editor graph is persisted verbatim. No translation happens in the browser.
- CompileA per-node hook reads each node's configuration and builds the matching primitive; edges become transitions.
- ExecuteA Fractal fetches that node map and walks it, asking the backend for flows and context as it goes.
The hook is the only place product-specific knowledge lives — which is why a different palette on the same primitives requires no runtime change. See the full reduction →
Thirteen nodes, grouped by intent
Each one annotated with the primitive it becomes on compile.
Flow
VoidThe entry marker. Exactly one per process.
VoidA synchronisation barrier — holds until every inbound parallel branch finishes, then merges their results into the shared context.
ExtrinsicPark the run and resume it at a delay or an absolute time.
GoToJump into another flow like a subroutine, and come back.
AI & Logic
PluginOne turn of a model conversation held on the node's scope, streamed to the canvas. Bound functions become output ports.
PluginAn MCP client — call a single tool with no model, or drive a model bound to the server's tools.
ContractEvaluate JavaScript or Rego over the scope and route by tag. Branching, policy and validation.
CodeA JavaScript step over the scoped context; the result is written to the node's key.
CodeA Rego policy over the scope, with condition data available alongside it.
Stores
ExtrinsicRead or write documents in a referenced Document memory store.
ExtrinsicIndex or search a referenced Vector store — top-k neighbours, with an optional partition namespace.
PluginBuild a value by mapping each key of a store's schema to a static value or a JSONPath resolved at run time.
Human
ExtrinsicPause the process for a person. Poses questions, records a task, resumes when the answers arrive.
Three fields on every node
titleThe label.keyWhere this node's output is written into the context.scopeThe JSONPath slice of context this node may read and write.That last pair is context engineering with teeth: what a node — including a model — may see and may write is an explicit contract on the node, enforced by the runtime rather than left to prompt discipline.
One vocabulary, composed from the same parts
What the field treats as distinct capabilities, and the composition each one is here.
What is not in that list is a runtime feature invented for any single row. Composable primitives over specialized abstractions is a design commitment, and this is what it buys.
The model routes the diagram
The model node's bound functions are outbound ports on the canvas. You declare a function — approve, escalate, search_docs — and it renders as a port you can draw an edge from.
At run time those functions are handed to the model as tools. When the model answers with a tool call, the runtime fires only the matching port. No tool call, and the flow takes its default route.
The model's decision is a visible edge in the diagram, not a hidden branch inside an agent's control loop.
Every route the model is permitted to take — and everything downstream of each one — is inspectable before it runs. Behavior is bounded by construction rather than by prompt. And the "function" never has to be implemented as a function: it is a routing tag, and its implementation is whatever you compose after it.
Context as a first-class system artifact
Context
Every run carries a Context: one live JSON document that is the working memory of the process. Nodes read a scope of it, write their result to a key in it, and the engine persists each mutation back through the backend as the run moves.
It is not state threaded through callbacks as an implementation detail. It is the central object — listed, opened, and editable as a tree or as raw JSON.
The model conversation lives here too. The prompt template seeds the messages on the first run; once the scope carries a message array, the template is ignored and the persisted conversation is used as-is. That one rule is what makes iteration work.
Stores
Contexts are per-run. Memory stores are not. A Document store declares a table and column schema and holds structured documents you can query. A Vector store declares an embedding model, dimensions and a distance metric — and creating one provisions a real vector index sized to it.
The store nodes reference one by id, and the store is resolved server-side, so the request never gets to choose which table it touches.
Retrieval-augmented generation is not a subsystem here. It is a Vector Store read node composed into a model node's scope.
Reasoning that happens outside the model
A Rule node evaluates JavaScript or an OPA/Rego policy against the scoped context and routes by tag. Its rule returns a list of tags; the engine follows only the transitions whose tags match. Three outcomes — accept, retry, reject — is one Rule with three tagged handlers, not three node types.
Place one after a model call and you have deterministic control over what that model produced, before anything downstream observes it. Validation, policy, retry limits, escalation thresholds and cost ceilings become explicit steps — evaluated outside the model, visible on the canvas, and changeable without redeploying the system around them.
Patterns, not special-purpose nodes
The behaviors other platforms ship as dedicated features are compositions here. Two examples carry most of the weight.
There is no Loop node
┌───────────────────────────────────────────────┐
│ no │
▼ │
[ LLM ] ─────► [ Rule: is the task satisfied? ] ───┘
│
└── yes ──► [ next step ]The model node appends to the message stack on the context. The Rule node checks whether the task is done. If not, an edge routes back. That cycle is the loop — with every iteration observable, every exit condition explicit, and a human review step insertable anywhere inside it.
There is no Observer node
[ LLM ] draft ──► [ LLM ] observer / critique ──► [ Rule ] accepted?
│ │
┌── no ──────────────────┘ └── yes ──► [ continue ]
▼
back to draftAn observer is a model node reading another node's output against explicit criteria, with a Rule deciding what happens next. It is a pattern composed from primitives, not an abstraction the platform provides — which is precisely why you can change what "acceptable" means without waiting for the platform to support your definition.
Wait for All
When a node fans out, the runtime runs every branch in parallel. This barrier holds until all of them finish, merges their results into the shared context, and continues once.
Continue After
Park the run and resume it later — now + delay, or an absolute time. Long-running work is an execution primitive, not a queue you operate beside it.
Goto
Jump into another flow like a subroutine and come back. Sub-flows are how composition and reuse across processes are expressed.
Integration with existing systems, not replacement
FloMorphic ships no catalogue of branded connectors, and that is deliberate. A connector catalogue is a maintenance liability whose value decays with every upstream API change. What a process actually needs is a small number of general ways to reach outward.
MCP
client nodeThe MCP node connects to any MCP server, loads its tools into the editor, and either calls one directly or binds them to a model. The tool ecosystem is maintained by whoever owns the tool — not by this project.
The system speaks MCP, or an MCP server can be placed in front of it.
Plugin
processA standalone process speaking inflowv1, built with the Go or Node/TypeScript SDK — wire-identical, so you pick the language, not a different protocol. It runs where you deploy it and appears as a node with its own configuration form.
A REST API, a database, a message bus, a gateway, an internal service. The SDKs' own worked example is an HTTP call node.
Extrinsic
primitiveA request/reply against a NATS subject your own backend registered. Your handler's reply becomes the node's output, and one wildcard registration can serve a whole family of operations.
A backend that imports the SDK and exposes its existing domain operations as subjects.
The Extrinsic primitive is how the runtime reaches a service you own: a request/reply against a subject your backend registered, where your handler's response becomes the node's output. It is the mechanism FloMorphic's own storage, approval and scheduling nodes are built on — one wildcard registration can back a whole family of operations.
The system around the process
The entities a real deployment needs beside the canvas.
Contexts
The run documents themselves — listed, opened, and edited as a tree or as raw JSON.
Memory
Vector and Document store definitions, and a browser for the data inside them.
Prompts
A reusable prompt-template library with declared variables and placeholder substitution.
Node settings
Named configuration profiles bound to a node kind — one provider profile per environment — referenced by id, so credentials never live on the graph.
Processes
Every run: status, duration, error, and a jump straight to the context it carried.
Human tasks
The queue the review node feeds — open a task, answer it, or close it out.
Extensions
Register a plugin from a Git repository so it joins the ecosystem and contributes nodes to the palette.
Four actors, talking over NATS
FloMorphic's backend never executes a flow. It answers the engine's questions — what is this flow, what is this run's context — and runs the domain logic a node calls out to. Fractals do the traversal. Plugins live on their own isolated accounts with narrowly-scoped credentials, able to publish and subscribe only on the subjects they own.
┌────────────────────┐ REST: creds, accounts, resources ┌────────────────────────┐
│ Infra │◄────────────────────────────────────►│ FloMorphic API │
│ control plane │ │ imports inflow-fusion │
│ NATS + registry │ NATS: get flow / get, set context │ owns the data │
└─────────┬──────────┘◄────────────────────────────────────►└───────────┬────────────┘
│ registered engines │ HTTP + WebSocket
▼ ▼
┌────────────────────┐ NATS: flow + context, svc.* calls ┌────────────────────────┐
│ Fractal (engine) │─────────────────────────────────────►│ FloMorphic canvas │
│ walks the graph │ │ the browser │
└─────────┬──────────┘ └────────────────────────┘
│ NATS on an isolated, scoped plugin account
▼
┌────────────────────────────────────┐
│ Plugin nodes: llm · mcp · … │
└────────────────────────────────────┘Every event the engine emits is streamed to the canvas over a WebSocket and traced back onto the nodes and edges that produced it — so a run is observed on the same diagram it was composed on, with its process row recording status, duration and error. Full architecture →
From a laptop to a cluster
The same artifact runs at every size. Nothing about a process changes as the deployment grows — only how many processors are attached to it.
Standalone
The web app persists to browser storage with no backend at all; the API runs CRUD-only when no infra is configured. Enough to compose, save and review real processes offline.
Single box
One compose network, and a database that is a file. This is already a complete, executing system — not a demo mode.
Scaled out
Fractals register themselves with Infra; new processes are load-balanced across the registered pool round-robin. Fractals carry tags, so work can be steered to the right class of processor.
Scaling is adding processors, not re-architecting. The graph, the context model and the node semantics are identical at every stage — so the process you composed on day one is the thing that runs in production, not a sketch of it.
Open source, and open at the seams
Being readable is the easy half. FloMorphic is open where it matters — at the joints you would reach for to build something of your own.
The palette is data plus a hook
Adding a node kind is a catalog entry on the frontend and a case in the compiler — not a runtime change. Fork the palette, keep the runtime.
The model nodes are ordinary plugins
The LLM and MCP nodes are standalone binaries with no privileged access, each pinning its own SDK version. Whatever you build gets exactly the contract they do.
The backend is storage-agnostic
Controllers depend only on repository interfaces. SQLite is one registered driver; another is a new package that registers itself.
Nothing is reserved
FloMorphic uses the same primitives, subjects and credentials any other system on Inflowenger would. It is the proof, not the exception.
Build systems you can understand
As AI becomes part of critical business processes, the challenge is no longer generating intelligent responses. The challenge is understanding, governing, and evolving the systems that produce them. FloMorphic helps you build those systems.
Pre-1.0 and moving. Per-repository licence files are being finalised as the projects are published — until a repository carries a LICENSE, do not assume a permissive licence for that component.