Using it · page 9 of 13
The loop, step by step
One requirement, from a sentence to a sealed record. This is the whole product in one pass, with what you see at each step.
The example is small on purpose, and real: a litre total on a phone app's home screen.
1. You write the ask
Show the litre total with its unit on the home screen. The home screen shows a number with no unit, and a reader has to know it is litres. Show the unit. Acceptance criteria 1. the home screen's total reads "12 345 L" with a space as thousands separator and a space before the unit 2. a test named
home total > shows the unit after a space
Two things make this a Constat requirement rather than a ticket. The criteria are things a machine can be asked about. And the second one names a check by the exact string the test run will report, so there is no argument later about whether it passed.
What you see: the requirement, in draft.
2. You approve it
The words freeze. From here, agents and evidence refer to these words, and nobody — including you — can move the target.
Its envelope freezes with it: what an attempt may spend, how long it may run, which files it may touch.
What you see: approved, and a Dispatch control.
3. You dispatch
Constat queues the work. The runner in your repository — on GitHub's machines or your own — asks Constat whether there is anything, takes it, and runs your agent with your key.
Constat is not running anything. It wrote down what was asked and is waiting.
What you see: building.
4. The agent works, and pushes twice
A good attempt pushes the check failing first, with no implementation behind it, and lets CI record it red. Then it writes the code and pushes again.
That is not ceremony. It is the only way the record can ever show the check failing. A check written and implemented in one push is only ever seen passing, and on the record that reads as passed, but unproven — indistinguishable from a check that could never have caught the bug it claims to catch.
What you see: commits appearing, CI runs starting.
An attempt does not say it is done while the checks on its last commit are still running. It waits, and the run page says it is waiting. That is why a door does not open the moment an agent stops working — what it pushed has not been read yet, and a verdict given before the evidence arrives is a verdict on the commit before it. If the checks never start at all, the attempt reports anyway and names the commit it never saw a run for.
5. Your CI runs, and publishes
Your tests run on your machines, as they always did. The workflow publishes the per-check report, the same report from before the change, and the coverage.
Constat did not run a thing.
6. Constat looks
It reads the runs, the artifacts, the diff and the pull request, with a token minted for that repository alone, and writes down what it observed — each piece with its source.
For each criterion it asks a ladder of questions: was a check named, did it run, what did it say, was it ever seen failing before the code existed, does it touch the lines that changed, does it notice when they break.
What you see: evidence arriving.
7. The door opens
When the attempt's own evidence has settled, Constat opens the door and tells the judges.
What you see: validating, and the run page, which leads with what a careful judge weighs first:
- the criteria and how far each one's evidence goes
- anything red beyond your criteria, named, with its first error line
- for each check run, whose fault it is — the code's, the machine's, or superseded
- the agent's own claims, in a column of their own
- a reason already drafted from what Constat saw, for you to edit
8. You decide
Accept or refuse, with a reason. Constat never writes accept or refuse for you; it puts the button order behind the facts and leaves the choice.
Accept and a Constat is sealed: numbered, dated, naming you as the person who accepted it and saying you are outside the harness that built it. If you are also the author, it says that too.
Refuse and that is recorded just as fully, with your reason and the evidence you read, and the next attempt starts from this one's branch with your words in its instruction. It takes no number: a Constat number means a person accepted, so a refusal never carries one and never stands in a list of sealed work. Its record has a page of its own, reached from the requirement and from the attempt it judged.
9. It goes live
An accepted requirement queues a release. Constat merges it, your deploy runs, and Constat watches for the application answering at that commit before it says live. Live is observed.
What you see: verified, and the release moving from queued to live.
10. The record stays
The sealed Constat does not change. Link it, show it to a client, read it in a year. It says what was asked, what CI saw, what the agent claimed, who accepted it and when.
The standing queue
You do not have to press Run. An approved requirement stands in a queue, and a runner asking for work is handed the first one in it. The order is yours, set by dragging on the requirements list; a refused requirement stands ahead of an approved one, because somebody is waiting on a fix.
approved requirements, in your order
┌──────┬──────┬──────┬───────────────┐
│ 1 │ 2 │ 3 │ … │
└──┬───┴──────┴──────┴───────────────┘
│ a runner asks for work every 30 s
▼
one attempt per lane, one attempt per requirement
A project has lanes: how many attempts it may run at once. Two agents on one requirement would race each other's branches, so a requirement gets one attempt at a time whatever the lanes allow.
Releases come first
A release that has not landed holds the queue. An attempt started underneath it would be built on a default branch the project is in the middle of leaving, and a door would open on work that was never standing on today's code. So the queue waits, and the wake takes the releases first.
The reverse is also true: a release pressed while an attempt is running is kept, not refused, and takes itself the moment the ground is free.
What leaves the queue, and what comes back
Two attempts that end with nothing for a judge to read take a requirement out of the queue. Nothing about the requirement changes — it stays exactly as you left it, and you can still dispatch it by hand. The queue simply stops spending attempts on something that is failing for a reason no attempt is going to fix.
When many attempts fail the same way at once — an account out of quota, a provider down — that is one fault repeating, not the backlog failing. The queue stops where it stands and names the error that stopped it, rather than walking down the backlog spending an attempt on each.
Letting the queue go again forgives those failures: attempts that ended before you let it go no longer count against the requirements they landed on, and the ones they took out come back. The queue says how many it put back.
Migration numbers
Two attempts off the same default branch would otherwise both write the next migration number and collide at release. A number is taken when an attempt claims it and released when that attempt ends, so the second attempt is told the number is gone and takes the one after it.
The same loop, without Constat's runner
If your team already runs Devin, Copilot, Cursor or your own scripts, you do not need Constat's runner at all. Open a pull request whose branch or title names the requirement, and Constat records it as an attempt on that requirement: your author, your branch, your pull request. Steps 5 to 10 are identical.