Deep dive

How NautFlow works

Most "AI builds your app" tools take a prompt and start writing files. NautFlow does something slower and, we think, more honest: it writes the documents first, has a second model attack them, gets your approval on a design, and only then lets several coding agents loose, each in its own worktree, judged by an acceptance test written before the build began.

1 August 2026 · André

Idea your words Documents reqs · arch · tickets Validator hostile · writes gate Design you approve then build Build manager plans the slices slice · worktree slice · worktree slice · waiting on a dependency Acceptance gate 31 / 35 passing Integrator merge · verify push · open PR every event appended to one durable build log work runs in GitVM sandboxes
The flow, end to end. The gate is written before the build starts, which is the part that makes the rest of it mean anything.

The problem with "just build it"

Hand a coding agent a one-line request and it will produce something. It will look plausible. It will even run. What it will not do is tell you which parts of your request it quietly dropped, which assumptions it invented, or whether the thing it built matches what you actually asked for.

The failure is not that the model is bad at coding. It is that nobody wrote down what "done" meant before the work started, so there is nothing to check the result against except your memory of a sentence you typed an hour ago.

NautFlow is our answer. It is a staged pipeline where each stage produces an artifact that the next stage is checked against.

The pipeline

1

Your request, kept verbatim

The first artifact is your own words, unedited, stored as the contract. Everything downstream is measured against this file, not against a summary of it, and not against a model's restatement of it.

A dialogue file sits beside it, capturing the clarifying conversation. If you agree to drop a feature, that agreement lives here in writing.

2

The document chain

Product requirements, architecture, data model, and executable tickets. Each is a separate document, each building on the one before. This is the part most tools skip, and it is the part that makes everything after it checkable.

Tickets are the unit that matters: each carries concrete acceptance criteria, because a ticket you cannot verify is a ticket nobody can finish.

3

The Validator: a second model, told to be hostile

Before a single line of product code is written, a different model reads every document and attacks the chain on five dimensions:

  • Contract coverage every feature you named is traced through the stages, or explicitly listed as dropped, with your sign-off in the dialogue. A silent substitution is a failure.
  • Stage completeness no scaffold documents, no empty sections pretending to be finished.
  • Cross-stage consistency the data model matches the architecture matches the tickets.
  • Testability every ticket has criteria you could actually check.
  • Build readiness nothing blocked. And any requirement naming an AI step must specify a real model call; a deterministic stand-in is a failure.

It ends with one line: Verdict: PASS or Verdict: FAIL, plus every finding written as expected X, found Y, with a proposal attached.

4

The acceptance gate, written before the build

This is the piece we are most attached to. In the same pass, the Validator writes an executable test: a standalone Python script that checks the built product against the tickets' acceptance criteria. Files exist with real content. Commands exit zero. Endpoints answer. Pages contain what the spec demands.

One line per check, PASS: or FAIL: expected X, found Y, fix: …, and it must fail against an empty repository. If it passes on nothing, it tests nothing.

Why write the test first

Because a test written afterwards tests what was built. A test written beforehand tests what was asked for. Those are different documents, and the gap between them is exactly where "it looks done" hides.

5

Design, before code

For anything with a user interface, a design pass drafts the primary screens as self-contained HTML mocks, rendered live in the centre pane while you steer from a chat beside them. Cheap to change, because nothing has been implemented yet.

The design agent runs with an explicit craft brief rather than being asked politely for something nice. That brief, which asks for restraint, deliberate spacing, real typographic hierarchy and asymmetry over grid-sameness, is what separates a considered layout from a component-library assembly, and it is doctrine, not a model setting.

6

The build: several agents, real isolation

A Build manager reads the tickets and groups them into parallel slices, each a self-contained piece of work one agent owns end to end. Every ticket belongs to exactly one slice.

Each slice gets its own git worktree: a real, separate checkout on its own branch, so two agents editing the same file is not a thing that can happen. It also gets its own terminal session, which survives you quitting the app. You watch them work, live, in the centre of the window. They are not hidden behind a spinner.

Each agent appends progress to a status log as it goes, and writes a report file only when everything it was assigned genuinely works.

7

The manager that watches

A supervisor loop checks on the build every couple of seconds. It notices when an agent has died and restarts it in the same worktree, keeping the code and discarding the dead process. It notices when a slice reports finished, closes its session cleanly, and marks it done.

And it nudges agents that have gone quiet, because an interactive coding agent will stop and ask a question, then wait forever for an answer nobody is there to give.

8

The Integrator

When every slice is green, the manager finalises automatically: merge the worktrees, verify the result in a real browser, push, open the pull request, and leave the app running so you can try it yourself.

That closing step is the manager's job, not yours. A build that stops at "the agents finished" has left you the worst part.

What makes it different

Every stage produces an artifact the next stage is checked against. Nothing is judged by whether it looks right.

A second model attacks the plan. Self-review by the model that wrote something is close to worthless. The Validator's whole job is to find where the chain breaks, and it does that before any code exists, when fixing it costs a paragraph rather than a refactor.

The test predates the code. The gate is written from your requirements, not from the implementation, so it cannot be quietly shaped to fit whatever got built.

Isolation is real, not conceptual. Separate worktrees and separate branches mean parallel agents genuinely cannot collide. Sessions outlive the app, so closing the window does not kill a twenty-minute build.

You can watch, and you can intervene. The terminals are right there. You can read what an agent is doing and type into its session. Nothing is hidden behind an abstraction that only reports success.

And everything is logged

Because this is xNAUT, every command an agent runs is timestamped and chained into a SHA-256 Merkle tree as it happens. When the build finishes you have not only a working product but a report anyone can verify: what was done, in what order, by which agent.

That matters most when the work is billed. "Trust me, the AI did it" is not an invoice. A hash chain is.

What shipped since

When this post first went up it ended with three honest gaps. All three are closed in v1.13, so rather than quietly edit them out, here is what happened to each.

Slices can now depend on each other. The build manager used to treat every slice as independent, so there was no way to say "the API needs the database schema first". Now a plan can declare dependencies, and a slice waits with no worktree and no agent until the work it needs has landed. If a foundation fails, everything built on it is marked unreachable rather than being started and then wasted.

The gate reports a score, not a verdict. It always ran real checks and then collapsed them to pass or fail, so "four failing" and "forty failing" were the same answer. It now reports how many checks pass out of how many, which is what makes it possible to tell steady progress from going in circles.

Agents can read each other's findings. Each slice gets a shared notes directory, so the second agent to hit a problem can read what the first one learned instead of rediscovering it.

And a build you can actually watch

Running real builds taught us something uncomfortable: the manager watching the agents was reporting things that were true and useless. It held a single status line that the next event overwrote, so the entire decision history of a build existed for a few seconds and was then gone.

So every build now writes one durable log. Every event, with a level and a source, appended to a file that is kept after the run. Filter it by level, filter it to one slice, search it, tail it live, and reopen any earlier build weeks later. Alongside it, a Files view shows what each slice actually changed, measured against the commit it forked from rather than the working folder, with the diff inline.

An agent that has already committed its work shows a clean working folder. Measure the folder and you will report a busy agent as idle.

The Build log tab in xNAUT showing 48 events from a four-slice build, with DEBUG, INFO, WARN and ERROR counts across the top, a sidebar listing each slice as a filterable source, and lines reporting gate scores such as 24 of 35.
A real build, mid-run. The gate reports 24/35 rather than pass or fail, which is what lets you tell progress from thrashing. The amber line is the plateau nudge firing: gate flat and nothing written for 2 checks. Lower down the manager recovers its plan and reports three slices running with one still waiting on a dependency.
The Files tab showing five changed files on a slice branch measured from its merge base, with an inline diff of the goal file the agent was given.
The same build's Files tab: 5 files, +135 measured from the merge base, against 0 commits. A working-folder view would have called that agent idle. The open diff is the goal file itself, including the shared-notes protocol every agent on the project reads before it starts.

Where the work actually runs

There is a piece of this that is not xNAUT at all. NautLoop is a sovereign sandbox platform, and GitVM is the fabric underneath it: isolated sandboxes where an agent's work genuinely runs, built on Firecracker microVMs that boot in about two seconds, rather than everything happening on your laptop and hoping nothing collides.

Sovereign is meant literally rather than as a slogan. Sandboxes are pinned to a jurisdiction across infrastructure in the EU and Switzerland, and the pinning is enforced: Swiss data routes to a Swiss node or the run fails, with no quiet fallback to whichever region happened to be nearest. The control plane starts and stops sandboxes and holds none of your content itself.

The division of labour is deliberate, and xNAUT's half is the small one. xNAUT captures the intent, plans the work and triggers the run; GitVM does the heavy lifting and hands back a branch. Keeping the workspace thin is what lets the same flow drive work that is far too large or too messy to want anywhere near your own machine.

That deserves its own post rather than a paragraph, and it is the next one: Where the agents actually run.