← All posts

The Model Proposes, the Graph Decides

Here is a question worth sitting with before the demo starts.

Where does control over an AI system actually live?

Most people answer: in the prompt. Some answer: in the model you picked, or in the guardrails you bolted on afterwards. Those answers are why AI keeps failing the audit.

You can tell someone what to do, or you can build the corridor they walk down. Prompts are orders. A process is a corridor. Orders get interpreted — that is what makes a language model powerful, and it is exactly what makes an order an unreliable control. Corridors don't get interpreted. They are either there or they aren't.

Almost the entire industry is currently trying to govern AI by writing better orders.


The polite no

Ask an insurance company to put a language model in charge of claim adjudication and you will get a polite no. Ask a hospital to let one triage patients, or a bank to let one decline credit, and you will get the same answer. Not because the model is not capable enough — in many of these tasks it already outperforms the checklist it would replace — but because of a question nobody in the room can answer:

On what basis was this decision made, and where is the record?

That question is not pedantry. It is the job. A claims decision has to survive a regulator, an appeal, and sometimes a courtroom. A clinical recommendation has to be traceable to the evidence that produced it. And in a modern AI system, the answer is almost always some version of: it is in the prompt somewhere, or in the agent's control loop, or in the model's weights. All three are places you cannot audit, cannot version meaningfully, and cannot hand to a compliance officer.

This is the gap I built FloMorphic to close.


The decisions are hiding in the wrong places

Look at where control actually lives in a typical AI application today.

Some of it is in the prompt — "if the claim exceeds $10,000, escalate to a human." That is a business rule, written in prose, enforced by hope.

Some of it is in the application code — a switch statement over the model's output, buried three layers deep in a service, changeable only by an engineer with a deploy pipeline.

And some of it is inside the agent runtime — the model chose a tool, the tool returned something, the model chose again. That loop ran a dozen times and produced an outcome. You have the outcome. You do not have the path.

Each of those places is opaque to a different audience. The prompt is invisible to the auditor. The code is invisible to the domain expert. The agent loop is invisible to everyone, including the person who wrote it.

The word the industry has settled on for the missing piece is harness — the structure you put around a model so that its power becomes usable in a system that has consequences. I think that word is right, but most implementations of it are still a thin wrapper: some validation on the output, some logging, some retries. That is a seatbelt, not a harness.

A real harness has to answer a stronger claim: every path this system could take was drawn before it ran, including the ones the model gets to choose.


The inversion

The prevailing design puts an autonomous agent in charge of a business process. The agent has goals, tools, and latitude; the process is whatever the agent ends up doing.

FloMorphic inverts that.

The process is defined first — its valid states, its allowed transitions, its policies, its approval points. The model operates inside that definition, as one participant among several. Judgment is what you want from a model. Control is what you want from the system around it, and there is no reason those two things have to come from the same place.

Concretely: a claims flow declares that a claim can move from received to assessed to approved or escalated. A model can look at the documents and argue for approved. It cannot invent a state called auto-paid, because that state was never drawn. It cannot skip the policy check, because the policy check is a node on the path, not a suggestion in a prompt.

A corridor is not a leash. Building the walls does not make the walker dumber — it is what makes it safe to let the walker be clever. Inside that claims flow the model can read every document, weigh contradictory evidence, and reason as freely as it is able. Bounding where the reasoning can lead is precisely what lets you stop bounding the reasoning itself. Most teams do the opposite: they leave the paths open and then spend their time trying to constrain the thinking with ever more elaborate prompts. That trade is backwards, and it is expensive in both directions — you get a duller model and a system you still can't defend.


The contract pattern

Here is the idea the whole thing rests on, and the reason I call it a contract.

A smart contract does three things with value: the rules are declared up front, they are enforced by the runtime rather than by good intentions, and what happened is inspectable afterwards. FloMorphic applies exactly that shape to behavior.

Four mechanisms carry it:

1. Tags on transitions. Every node emits tags when it finishes its turn. Every outgoing edge declares, at compile time, which tags it will accept. The runtime fires only the transitions whose tags match. So the route is chosen at run time — but the set of routes that could ever fire was drawn on a canvas by a human being. This is not owned by any node type. A rule node emits tags from a JavaScript or Rego evaluation. A model node emits them from the function the model picked. A call into your own backend emits them from your service's reply. Same enforcement, different decider.

2. Scope on every node. Each node declares the slice of the working context it is allowed to read and write. That includes model nodes. What the model may see and what it may change is a boundary the runtime enforces — not an instruction you wrote in the system prompt and hoped it followed. This is context engineering with teeth.

3. Tool calls as visible ports. When you bind a function to a model node — approve, escalate, search_docs — it appears as an outbound port on the diagram. At run time the model gets those as tools; when it calls one, only that port fires. The model's decision becomes an edge you can see, not a hidden branch inside a control loop. It selects among the routes; it cannot invent one. And the "function" never has to be implemented as a function — it is a routing tag, and its implementation is whatever you draw after it.

This is the corridor made concrete. The doors out of a room are drawn before anyone enters it. The model decides which door to walk through — that is real judgment, exercised at run time on evidence nobody could have anticipated at design time — but the set of doors was settled by a person, in the open, in advance.

4. Reasoning is a composition, not a node. The deterministic nodes — JavaScript, OPA/Rego — are not where the reasoning lives. They polish data, map between shapes, enforce a threshold, and route by tag. Useful, and not the interesting part.

The reasoning is what the shape does. A model's output can be routed into a sub-process that critiques it, retrieves counter-evidence, calls a plugin, consults a second model — and then appends what it found back into the message stack of the very node that produced the original answer. That is mid-process, not a second pass over a finished result: the model gets another turn, now holding instructions it did not have when it started. Loop that composition and it keeps going until a condition you wrote says it is done.

So reflection, debate, verification, staged escalation, self-critique — none of these is a feature anyone implemented. Each is a shape, built from the same parts, and each one is drawn where a person can read it. Which is also why the thresholds inside them change without a redeploy: a limit is a value in a node on a visible path, not a branch buried three layers into a service.

The one-line version: the model proposes; the graph decides.


"So it's n8n with an LLM node?"

The resemblance is real, and the answer is not "no, it can't do that."

It can. Scheduled jobs, data collection, cleaning and enrichment pipelines, moving records between systems — all of that is well within what the runtime executes, and people will build exactly those things on it. You could go further: the automation-builder shape itself is buildable here. Inflowenger ships a runtime and six primitives; FloMorphic is one palette drawn on top of them. A developer who wants the trigger-and-connector shape authors that palette on the same runtime and ships it, without touching the engine, because a node in a palette is a configuration of a primitive rather than a feature someone implemented in the executor.

So the distinction is not capability. It is intention.

FloMorphic is a platform for building agents — and the palette is drawn for that. Every design decision in it optimizes for one thing: that an agent's behavior is visible before it runs and traceable after it. Which states are valid, which transitions are permitted, where policy is evaluated, where a human signs off, and exactly how far the model's discretion extends. Automation falls out of that. Transparency is what it was built for.

That intention shows up in what is deliberately absent. There is no catalog of branded connectors — a connector catalog is a maintenance liability that decays with every upstream API change, and it is the wrong thing to optimize when the goal is legibility rather than assembly speed. Instead there are three general ways to reach outward: MCP for anything that speaks it, plugin processes for anything that does not, and a request/reply primitive for the backend you already own.

The palette also assumes you already speak the vocabulary. What fits in a context window and what belongs outside it. Why an embedding lands in a vector store and comes back by similarity. What a tool call costs, and where a model's judgment should stop. FloMorphic exposes those things rather than smoothing them away — retrieval is a node, model scope is a boundary you draw, policy is a contract you write. Hiding them is precisely what it refuses to do. If your goal is connecting a mailbox to a chat channel in two clicks, that is a good goal and a different palette. If your goal is an agent whose every possible path was drawn before it ran, this is the one.


The loop, the harness, and the orchestration are one artifact

"AI harness" is usually sold as a wrapper: something you put around an agent while the agent's interior stays opaque. That is not what this is. The loop inside the agent, the harness around it, and the orchestration across several of them are the same artifact, drawn at the same level, observed on the same diagram.

The loop. There is no loop node in the palette, and that is deliberate. A loop is not a primitive — it emerges from connections: something appends to the message stack on the context, something checks whether the task is satisfied, and an edge routes back if it is not. That cycle is the agent loop. What sits inside it is open — a second model reviewing the first, a plugin fetching evidence, a sub-process that runs its own graph and returns, a deterministic check, a person. Whatever the body, every iteration is observable, every exit condition is explicit, and a human review step can be inserted anywhere inside it. Reflection, self-critique, planning, retry with backoff, approval chains, data-quality passes — same shape, different body.

The harness. Which means the harness is not wrapped around a black box, because there is no black box left to wrap. The interior of the agent — the thing that in most frameworks is a while loop you cannot see into — is drawn on the canvas alongside everything else. Policy sits inside the loop, not merely at its boundary. A cost ceiling, an escalation threshold, a retry limit: each is a node the loop passes through on every pass, evaluated outside the model, changeable without redeploying anything.

The orchestration. Multi-agent systems are a composition, not a separate feature. An agent is a flow; a flow can be jumped into like a subroutine and returned from; branches fan out and run genuinely in parallel; a barrier holds until every branch finishes and merges their results into the shared context. So a supervisor coordinating three specialists is a graph calling three sub-graphs — with real concurrency in the runtime, rather than one process pretending to be several inside a single loop. And the same event stream that traces one agent traces all of them, back onto the nodes and edges that produced each step.

Which gives you the consequence that matters: the thing you compose on day one is the thing that runs in production and the thing you audit afterwards. Not three different representations of it — one artifact, read by the domain expert, the engineer, and the auditor.


What this replaces

If you have built with agent frameworks, you have assembled these pieces yourself, in code, as separate concerns. Here they are compositions of the same small set of parts:

The conceptWhat it actually is here
RAGa vector store read node wired into a model node's scope
Context engineeringscope + key on every node, enforced by the runtime
Working memorythe run's context — one live JSON document the flow reads and mutates
Long-term memorydocument and vector stores, resolved server-side
Tool usevirtual functions as outbound ports
Agent loopa cycle in the graph, with whatever you need inside it
Guardrailsa rule node before or after the model, in JS or Rego
Reflection / self-critiquea sub-process that appends its findings back to the model's stack
Multi-agent orchestrationsub-flows, parallel branches, and a barrier that waits for all
Human in the loopa run that parks on a real task and resumes on the answer
Observabilityevery engine event streamed back onto the nodes that produced it
Schedulingresumption as an execution primitive, not a queue you operate

None of these needed a runtime feature invented for it. They fall out of six primitives, a shared context, and a compiler seam — which is the underlying bet of Inflowenger, the runtime FloMorphic is built on. A node in a palette is a configuration of a primitive, not a feature someone implemented in the engine. That is why FloMorphic is one palette rather than the whole platform: a different domain draws a different palette on the same six primitives, and the runtime does not change.


It attaches to what you already run

The last piece matters most to the enterprises this is aimed at, because it is where most "AI platform" conversations die.

Your existing backend does not get rewritten, replaced, or migrated. It joins. It answers the graph over a request/reply subject, and the graph calls it. A system that has been in production for a decade can become AI-native without a rewrite, and can grow from one laptop to a cluster without changing shape — because scaling means attaching more processors, not re-architecting. The process you composed on day one is the thing that runs in production, not a sketch of it.

It is open source, Apache-2.0, and self-hostable. The model and MCP nodes are ordinary plugin binaries with no privileged access — whatever you build gets exactly the contract they do. There is no hosted-only capability holding the interesting part back.


The larger bet: Software V3

Everything above is the AI-layer argument. Underneath it is a claim about how software gets written at all.

In the model most of us still work in, business logic is code — distributed across services, expressed in branches and handlers, owned by engineers, and changeable only through a deploy pipeline. The process a business actually runs exists nowhere as an artifact. It is reconstructed, imperfectly, by reading the code that implements it. That is why the domain expert and the system drift apart, and why "what does this system do?" is a research project rather than a document.

The bet Inflowenger is built on is that this inverts: business logic is a workflow graph over living context, changeable by an operator without a redeploy. The process is the artifact, not a description of the artifact. Context is a first-class object — one live document that moves through the graph, versioned and inspectable — rather than state threaded through callbacks as an implementation detail.

This is also where the name comes from. Andrej Karpathy calls this moment Software 3.0: programming in natural language, where the context window is the program and the model is its interpreter. His axis is what a program is made of — code, then weights, then context. The arc here is how a system is structured — procedural, then service-oriented, then context-driven. Two different lenses that arrive at the same place: the context becomes the center. And they leave the same thing open. His framing names what the program becomes; it does not name what runs it. That runtime — the thing that persists the context, scopes who may read and write each slice, routes on it, and records what happened — is the seam Inflowenger fills. In his framing the context window is still a window inside a single model call, and it evaporates when the call returns.

Which is another way of saying: context engineering becomes the development model, not a technique you apply inside one. When every node declares the slice of context it may read and the key it writes back, you are not prompt-tuning around a system — you are composing the system out of context boundaries, and the runtime enforces them. The model is one participant in that composition, with the same kind of contract as every other participant.

FloMorphic is that thesis applied to the AI layer: the first product built end to end on the runtime, and the proof that nothing in it is reserved. But the thesis is bigger than the AI layer, and it is the reason the harness argument works. A model whose decisions are visible edges is only possible in a system where the process itself is a visible artifact in the first place.


Where it stands

FloMorphic is pre-1.0 and moving. The runtime, the canvas, the API, the compiler seam and the builtin plugin nodes are all readable and forkable today; the developer tooling around them is still being assembled. If you want to run it, Docker is the only prerequisite and the canvas comes up on localhost:8090:

curl -fsSL https://raw.githubusercontent.com/FloMorphic/getting-started/main/install.sh | bash

I built this because I kept meeting the same wall: the model was good enough, and the system around it was not defensible. As AI moves into processes with real consequences — claims, credit, care, compliance — the hard problem stops being how do we get an intelligent response and becomes how do we understand, govern, and evolve the system that produced it. And answering that question well turns out to require rethinking what a system is made of in the first place: a graph over living context, with the model as a bounded participant in it.

So, back to the question at the top. Control does not live in the prompt. It lives in the paths — which steps exist, which transitions are permitted, where a human signs off, where the model's discretion ends and the rules resume. If those are not drawn somewhere a person can read, you do not have control. You have hope, with good results so far.

Intelligence without control is a demo. Operational intelligence needs both.

Repo: github.com/FloMorphic/getting-started

Concepts and docs: inflowenger.com/flomorphic

If you work in a domain where "why did the system decide that?" is a question with legal weight, I would genuinely like to hear where this framing holds and where it breaks. That is the feedback I am looking for.

Part two builds a working claims adjudicator from scratch — install to running flow: Build a Claims Adjudicator You Can Actually Audit.

This piece is also on Medium — if you read there, a clap helps it travel.