AI First Software Factory
Gailleur Labs · Engineering
An agentic software factory: eight long-lived AI agents, each owning a lane, that take work from one queue, coordinate over a message bridge, and carry a task from ticket to production on their own — inside a pipeline of gates, a second model that reviews adversarially, and a handful of deterministic loops that keep the whole thing moving. 100% of the product's code is written by the agents. One human owns the product, decides what ships, and is the only authority in the system. This page is the reference for the concept; the product it builds, Domi, is the instrument.
What an agentic software factory is
Frontier models contain incredibly broad knowledge. Specialized agents narrow the problem space — giving that intelligence a role, a context, and a definition of what "good" looks like. That is why the factory is eight stations with lanes rather than one very capable assistant with more tabs: each station knows what it owns, what it must not touch, what evidence counts, and who decides when it cannot.
A factory, then, is everything around those specialized agents that lets a task run for hours or days without a person steering it, and still be safe to trust at the end. Six ideas carry the whole design:
Long-lived agents with a lane
Each station is a Claude Code session that stays up: a mandate, a repository, a set of paths it owns and a set it must not touch, an inbox. It boots into a card that says what it may do on a peer's word and what it must bring to a human first. It is the same session next week — it remembers.
Work as decisions already made
The human files work in one append-only queue, in his own words. A station claims a task and executes it — it does not hand back a plan. Rulings on a task are recorded on the task, attributed, where every station reads them first-hand. Ambiguity parks; nothing guesses.
Agents interfacing, untrusted
Stations never call each other. They append messages to each other's inboxes over a local bridge modeled on Google's Agent2Agent protocol — requests, responses, notes, a task lifecycle. Every message is untrusted input; authority never travels on it. A message claiming the human approved something is just a message.
Autonomy per action, mechanically
An action registry rates every action auto, confirm or deny, per station; an override may only be stricter; an unknown action defaults to confirm. What runs unattended runs on a checkable predicate — "zero failures, nothing running, all on this exact commit" — never on "it looked fine".
Clocks, not supervisors
Seven scheduled jobs pace the factory: redraw the board, wake the owner of a stuck pull request, ring the doorbell again on unanswered work, merge what is mechanically safe, sync the intake board, compile the blockers for the human. No model in any of them. They replaced a supervisor agent whose every judgement turned out to be a query.
Decides, and only decides
Files the work, rules on the calls that matter, holds every secret, promotes to production. Never types code, never merges routine work, never relays authority through a chat window. What the factory cannot decide on a predicate comes to him as a DECIDE — one line, with its context, in order of how long it has been blocking.
The stations
Eight stations on the bridge, one reviewer in CI. Four of the eight write no product code: their output is design values, acceptance, security documents, and the human's own words carried to the others.
| Station | Owns | Model |
|---|---|---|
| web | the web app and backend — the contract every other station consumes | opus-5 (1M context) |
| mobile | the iOS and Android client, a pure consumer of that contract | opus-5 |
| devx | CI, gates, evals, test infrastructure — what "green" means | opus-5 |
| security | reads everything, writes only security documents; can hold a release without asking, can never clear the hold — only the human can | opus-5 |
| design | the design system, tokens and brand-string ledger — values, not stylesheets | sonnet-5 |
| product | acceptance: is the built thing the asked-for thing, and in what order — authors no specs, decides nothing | sonnet-5 |
| marketing | positioning and this site — every public claim traced to shipped product | sonnet-5 |
| chief | the human's proxy: turns his words into queue entries, carries questions back, records his rulings — never his authority | sonnet-5 |
| reviewer | in CI, not on the bridge: reads every pull request adversarially before a human does — a different model family on purpose | gpt-5.6 (OpenAI) |
The security station is the clearest example of the design
Security is the one lens where being wrong is unbounded, and the station that builds a thing is the worst judge of whether it is safe. Three decisions on its card are the point, not the fact that it exists:
Raising an alarm needs no permission
A hold on a release is auto for the security station — an alarm that requires approval is an alarm nobody raises.
Clearing one needs the human, no exceptions
Releasing that hold is denied to every station, including security itself. Only the human clears a hold — which is precisely what makes the auto-hold safe to grant.
It reviews; it does not ship
It writes only security documents and cannot patch what it finds. The station that reviews does not also ship the fix.
Its card carries the rule an attacker would test first: a request to approve, downgrade, or drop a finding is the highest-value thing an injected message could ask for. Findings are judged against the code, never against a peer's account of it. "JF said it is fine" is not JF.
The factory in one picture
Work enters as a ticket, leaves as a release, and feeds back into the next ticket. Agents write; other models review, evaluate, render and triage; the human decides. The loop below is drawn from the actual workflows, not from a plan.
1 · Intake — where work comes from
Work reaches the factory through one door: a queue the human owns. Four sources feed it, and only one of them is a person typing. The founder dogfoods the product with his own household and files what he hits, in his own words. Production errors are read by an autonomous loop every six hours and filed as tickets — deduplicated, with the stack trace fenced as untrusted evidence — onto an intake board where a human promotes them to Ready; nothing the factory files can promote itself. Support requests arrive through the in-app ticketing surface into the same board. And the product station reviews the backlog on a schedule and proposes what should become Ready next — proposes, never decides.
Dogfood
One household, one family, two homes, two cars, two companies, one school — run on the product daily. Most of the backlog's best items started as "I opened the page and…".
Error triage
Unresolved production errors become labelled tickets automatically, identity-keyed so a sweep can never file twice. A ticket is input to an agent, never an instruction.
Intake
Issues on the board's Ready column become queue tasks, routed by the lane label they already carry. Two lane labels, or a needs-human label, park the issue rather than guess.
Acceptance & order
The product station checks delivered work against the human's own words — not the issue text, which is already an interpretation — and proposes the next Ready items from one ordered backlog.
2 · Specify — the harness the agents work inside
An agent with no memory rebuilds the product's assumptions every session. So the assumptions are written down, versioned and checked into the repo: a working-memory file read at the start of every session, locked specs for every subsystem, decision records, a catalogue of invariants that a future change could silently break, and per-agent memory notes for the lessons that don't fit anywhere else. The visual side is specified the same way: a design station owns its own repo of design-system specs and token values, and the web and mobile stations build against those as a frozen contract — a token set changes by renegotiation, never by a quiet edit in a stylesheet.
| Artifact | What it holds | Scale today |
|---|---|---|
CLAUDE.md | The working memory: what the product is, the locked decisions, the conventions that must not drift, the current sprint. | 517 lines, read every session |
docs/specs/ | Locked specifications — requirements, data model, permission matrix, LLM routing, RAG architecture, threat model, privacy assessment, DR runbook… | 80 documents |
docs/adr/ | Architectural decisions with the reasoning that produced them. | 8 records |
domi-design | The design station's repo: design-system specs, explorations, and the token values (colour, type, spacing, light/dark) the web and mobile stations consume — sent over the bridge as a frozen contract, rendered and screenshot-checked before it is called done. | 1 design system · 2 consuming apps |
regression-suite.md | Every invariant a shipped fix established, with the test that guards it and the root cause it closes. | 303 invariants |
| Agent memory | Library quirks, footguns, corrections — the things worth not re-learning. | 62 notes |
| Sprint closeouts | What shipped, what broke, what was learned — append-only. | 47 reports |
| The factory's own registry and cards | One JSON file that launches every station and loop; one card per station saying what it owns and may do; 33 actions rated auto / confirm / deny. | 1 registry · 8 cards · 33 actions |
3 · Build — eight stations, one bridge
Each station is a Claude Code session with a mandate, a repo, and a set of paths it owns. They coordinate over a small agent-to-agent protocol on the same machine — shaped after A2A so it ports to the real thing later: an agent card each, a JSONL inbox each, tasks with a state lifecycle, and a durable trail on one GitHub issue for anything that should outlive a session. Nobody edits another station's repo; they send a request. A request that will take a while gets a working note first, because silence and busy look identical from outside.
How it is wired → the station registry, the card each agent boots into, the bridge protocol, the loops, and the one rule that makes an untrusted channel between agents safe enough to run.
Frozen contracts
When one station builds against something another publishes — design tokens, a sync protocol, what a CI gate enforces — the contract is written, acked, and changed only by renegotiation. A merge is not a render: the design station asks for the screenshot.
Observation over inference
House rule, earned the hard way: verify against the real artifact — the actual run log, the served page, the row in the database — never a doc's claim. "A green test past the real code path is worse than none."
Retract loudly
When a station is wrong it says so, names the false premise, and corrects the record where the claim was made. The durable trail keeps the retractions next to the claims.
Trunk, squash, worktrees
One trunk, squash-merge only, every station in its own worktree, Closes #N in every PR body — enforced by a gate, because a convention without a gate lapses.
4 · Verify — other models check the work
This is the part that makes "100% AI-written" a fact rather than a risk. Deterministic gates catch what they encode; evals catch model regressions per role; a reviewer from a different model family catches what the author's blind spots share with its own; and a browser catches what none of them can see.
Cross-model checking
Claude writes; GPT reviews. Cohere embeds and reranks; Claude and GPT are pitted against each other on the planning eval before either is promoted. The evaluator is never the thing being evaluated.
The reviewer has its own eval
Five planted-defect pull requests — a table without row-level security, a mutation without its audit write, a seed that violates a foreign key, a change that delivers the mechanism but not the outcome, and a clean control — run through the exact live review path before the reviewer's prompt or model may change. It is also judged on one live metric: how often a human sends its verdict back, and what it missed that the human caught.
Gates that can't rot
Lists are derived, never hand-kept: which suites run against the real database, which roles have an eval, which secrets a workflow may hold. A gate that verified nothing must never look like one that did — skips are loud and named.
The database is real
Integration suites run on a fresh Neon branch cut from a wiped template on every PR, connected as an RLS-enforced role — so tenant isolation is proven, not assumed, every time.
Security, checked the same way
Security is not a phase; it is a set of gates a pull request cannot get past, plus sweeps that run whether or not anyone is looking, plus a station that reads on its own judgment and can hold a release. Two full vulnerability passes have been run over the codebase by agents and closed as tickets; the day-to-day is automated.
Dependabot, every day — merged by a loop
Library updates and security advisories arrive as pull requests that go through the same gates and the same AI review as everything else; a loop merges the green ones on a pinned head. Installs are hardened against supply-chain attacks: lifecycle scripts blocked, an empty build allowlist, and no package version younger than seven days.
Tenant isolation proven per PR
Every table with a tenant id has row-level security, and the integration suite connects as a role that cannot bypass it — on every pull request. A migration that forgets a grant fails the drift gate before it can reach a deploy.
Keys that cannot cross
CI and evals run on development keys only; a gate scans every workflow and refuses one that names a production secret. A lint rule trips on any decrypted-looking value reaching a log. The human holds every secret; no agent ever sees a value.
Threat model, audits, response
A STRIDE threat model, a privacy impact assessment, a disaster-recovery and an incident-response runbook — and two agent-run vulnerability audits closed as pull requests. Data is encrypted at rest per household under a master key the database never holds.
Pipeline economics — the cost that shows up once the agents are fast
An AI-first factory has a cost shape nobody warns you about: once the agents themselves are fast, the pipeline becomes the expensive line item. In one seven-day, 120-run measurement, 61% of billed CI minutes went to a single job — the real-database integration suite — which ran on every pull request regardless of what the change touched. Two mechanisms came out of that, and both are still how the pipeline runs:
Run the expensive suite only where it can matter
The database suite runs only when a change could plausibly touch it. The filter was first written as an allow-list of what's relevant; four holes were found in it in one afternoon — one by replaying it over real pull requests, three by the AI reviewer — so it was inverted to run unless proven irrelevant: an unclassified path costs minutes, not a missed regression.
Cancel the expensive job, don't reorder it
Every check starts at once on a pull request; the AI reviewer simply finishes first. A changes-requested verdict cancels the in-flight expensive runs for that commit and posts a plain notice that those checks verified nothing and must be re-run before merge. The reviewer doesn't decide what gets tested, and the author remains free to contest the verdict.
Flow — the honest half
The median path is fast: a filed task is picked up by a station in seconds, and a clean pull request merges in minutes. The tail is where the time actually sits.
The median is not the problem
From task filed to a station picking it up, then a clean pull request to merge.
The tail is
Most pull requests merge clean the first time. The rest is where the elapsed time goes — review rounds and waiting, not authorship.
5 · Ship — what a release carries with it
Merging to trunk deploys staging automatically. Production moves only on a deliberate promote of a green staging build: migrate, build, deploy, smoke-test with automatic rollback, tag. Before the promote, a gate reads whether the staging browser suite passed for that exact commit; the security station can hold the promote; only the human can clear the hold. Everything a user or an integrator needs ships in the same motion — generated, not remembered.
Release notes
Every production promote writes a consumer-facing release note from the merged changes, keyed to the build stamp the app shows on its sign-in page, in both languages — and opens the PR that publishes it. An expectation loop checks that every promote was followed by its notes within two hours.
Two languages, always
Every feature lands with English and French copy and documentation in the same PR; a CI gate refuses a string that exists in one language only. The same discipline holds on mobile, where French runs 20–30% longer and is a first-class layout defect.
MCP and API stay current
Each capability is written once as a typed tool; the chat assistant and the MCP server both consume it, so ChatGPT, Claude and other clients see new tools the moment they ship. A gate keeps the OpenAPI reference and the tool list honest.
Help that answers
The documentation is also a retrieval index: the assistant answers "how do I…?" from the help site's own sections, re-ingested by a CI hook whenever a page changes, citing the page's stable URL.
6 · The product's own intelligence — built the same way
The factory builds a product that is itself a model pipeline. Uploaded documents are transcribed verbatim, summarised, filed, chunked and embedded into a tenant-isolated vector index with hybrid retrieval and reranking; facts become a household knowledge graph the assistant can traverse; a deterministic engine plus a prediction model turn those facts into the tasks a household needs next. Every role in that pipeline has a pinned model, a capability gate, and an eval — the same rules the factory applies to itself.
7 · Learn — the loop closes
Errors become tickets
The triage loop turns production errors into work without a human reading a dashboard — and keeps nudging a closed ticket that still fires, so a "fixed" that didn't fix is heard.
Evals are monitoring
Every prompt or model change runs the role's eval first; a floor is set from the first green run and never lowered. What production teaches goes back into the fixture set.
Invariants are catalogued
A shipped fix isn't done until the invariant it established is written down with the test that guards it and the root cause it closes — 303 of them, mutation-verified where it matters.
Stations remember
Corrections, footguns and decisions that aren't in any spec live in per-station memory, linked, and are re-read next session. The same lesson is not paid for twice.
Expectations watch for silence
Five things that must keep happening are probed on their own clocks — release notes follow every promote, the triage sweep keeps running, the reviewer keeps reviewing, no peer request sits unanswered for days, the backlog keeps getting reviewed. Every other detector finds a problem that appeared; these notice a process that stopped.
The factory measures itself
The same tools that run it draw the board: where the time goes per repository, which handoffs are stale, what is blocked on the human, and what it costs. The public board is generated by the same command, with contents redacted.
8 · The machinery that keeps long-lived work moving
A task can take hours or days and cross three stations. What keeps it moving without a person watching is a small set of mechanisms, each of which exists because a specific thing went wrong once.
A work queue
One inbox for the human, and it is not a station. A task in it is a decision already made — stations execute rather than hand back a plan. State is a fold over an append-only log; nothing is ever rewritten.
An action registry
33 actions, each rated auto / confirm / deny per station. A mechanical check answers "may this station do that?" — an override may only ever be stricter, never looser, and an action nobody has listed defaults to confirm. Every grant carries a why, a name and a date.
The chief
A proxy that carries the human's words but not his authority — the distinction the whole trust model rests on. Its one added power is to record his rulings on the queue, where they can be read first-hand; it cannot merge, commit, widen a scope or clear a hold.
A review loop
The reviewer was working; nothing woke the author. The loop wakes the owner of a stuck pull request — changes requested on its current head, approved and unmerged, or green with no review — capped at three pings, then one escalation to a human, then silence.
Pace
Replies a station owes a peer, and work routed to it that it never picked up. The filing nudge rings once, at the moment of filing, while a station may be mid-turn; this is what rings it again. One digest per station, not one message per debt.
Merge predicates
Documentation and dependency pull requests merge themselves once a tool says zero failures, nothing running, every check on the pinned head — and, for docs, every changed path is documentation. Unknown is never permission.
A WIP ceiling
Claiming a task refuses past a limit. Cycle time is work-in-progress over throughput: holding four tasks at once does not finish four sooner, it finishes each one four times later.
Blocker review
Every four hours the standing blocker list goes to the proxy to verify against the record, clear what is already answered, and compile one DECIDE for the human. The loop compiles; the proxy judges; the human reads one thing, not ten.
A generic engine, a configured instance
The factory is extractable from this company. A CI gate fails the build if an engine file names Gailleur Labs or Domi; the instance is one registry, the cards and the briefs.
CI on the factory's own logic
The cards, the action table and the routing rules are regression-tested like any other code, in the factory's own CI — a change to who may do what fails a test before it changes behaviour.
By the numbers
Everything below is counted, not estimated: from the GitHub API, the CI logs of the latest green runs on trunk, and the repositories. Rows without a date cover the 90 days ending 2026-08-31; a row with its own date was measured then and is carried, not silently relabeled.
| Phase | Metric | Value |
|---|---|---|
| Build | Pull requests merged (web + mobile) | 1,131 — 943 web, 188 mobile |
| Build | Lines added / removed | 467,766 / 57,183 across both repos |
| Build | Filed → picked up by a station | 23 seconds (median, last 150 merges) — see Flow, above |
| Build | Work-queue tasks filed | (as of 2026-09-16) 146 since the queue opened, all-time |
| Build | Commits on trunk | 1,154 — squash-merge only, linear history |
| Build | Who wrote it | (as of 2026-08-22) All-time, both repos: 1,222 trunk commits carry an explicit AI co-author trailer, 163 are bots (Dependabot, release notes), 299 are content-free merge commits from the pre-squash era. The first commit is the agent-written bootstrap; no generator was run by hand. |
| Build | Lines in the repos today | (as of 2026-08-22) 406k — web 381k (290k TypeScript/JS in 1,459 files, 53k docs, 32k config, 6k SQL) + mobile 25k (20k code) |
| Build | Model spend to build | (as of 2026-08-22) ≈ $15.6k over 90 days — ≈ $13.50 per merged PR, ≈ $175 per day; ≈ 43M billed input + output tokens, 13.4B all-in (cache included) over the 64 measured days. Claude Code + Codex sessions only; excludes the CI reviewer and evals.* |
| Build | Agent-to-agent messages | (as of 2026-09-16, all-time since 30 July) 2,799 — 440 requests · 962 responses · 1,397 notes; by station: web 573 · devx 489 · mobile 268 · chief 214 · security 150 · design 121 · marketing 109 · product 51; the rest from the loops and the human |
| Verify | Test cases executed per PR | (as of 2026-08-22) 5,916 — 3,068 unit (221 files) + 2,848 on a real Postgres branch (290 files, 4 shards, 17 env-gated web suites, a deterministic per-task eval) |
| Verify | Required checks per PR | 7 — plus an AI review and per-role evals when the PR touches a role |
| Verify | Wall-clock per PR | (as of 2026-08-22) ≈6 min unit lane · ≈8 min real-DB lane · AI review ≈10 min, in parallel |
| Verify | CI workflow runs, 90 days | (as of 2026-08-22) 7,600+ across 21 workflows (seven of them capped at 1,000 by the API, so the true figure is higher) |
| Verify | Throwaway databases, 90 days | (as of 2026-08-22) 1,000+ Neon branches cut from a wiped template and deleted after the run |
| Verify | Eval fixtures / roles / workflows | (as of 2026-08-22) 165 fixtures · 16 LLM roles · 7 eval workflows · 290 eval runs in 90 days |
| Verify | Reviewer accuracy | 5/5 on the planted-defect smoke set, re-run before any prompt or model change |
| Verify | Browser suite on staging | (as of 2026-08-22) 24 Playwright tests in 3 files — 16 screenshot surfaces (en + fr), 4 palettes, 4 flows · 20 committed baselines |
| Verify | Catalogued regression invariants | 303, each with the test that guards it |
| Security | Dependency PRs / advisories resolved | 85 merged in 90 days · 75 advisories resolved (as of 2026-08-22) · 7-day minimum package age |
| Security | Row-level-security tables | 60 — enforced on every PR by a non-bypassing role · 178 migrations |
| Ship | Production releases | 78 in 90 days; a failed smoke rolls back |
| Ship | Release notes | 89 published, English + French, generated from the merged changes |
| Ship | Documentation | 349 help pages · 523 retrieval chunks for the in-app assistant (chunk count as of 2026-08-22) |
| Ship | UI strings | 2,746 keys × 2 languages on web and mobile — parity gated |
| Ship | Integration surface | 64 API routes · 56 MCP tools (as of 2026-08-22) · 11 scheduled jobs, each with a user-facing dial |
| Learn | Tickets filed by the error-triage loop | (as of 2026-08-22) 10 since it went live, zero duplicates |
| Harness | Specs / ADRs / sprint closeouts / memory notes | 80 · 8 · 47 · 62 notes (memory-note count as of 2026-08-22) — and a 517-line working memory read every session |
What the human does
Owns the product. Uses it every day with a real household — a family, two homes, two cars, two companies, a school. Writes the tickets in plain words — which the stations and the reviewer treat as the request, with the issue text as one possibly-lossy interpretation of it. Holds every secret and flips every switch: a gate goes from advisory to hard, a reviewer is enabled, a release is promoted, only by a person. Rules on what comes to him as a DECIDE, and his ruling is recorded on the task. Reads the review on the changes that matter — migrations, auth, money, anything the reviewer sent back — and merges those; routine green pull requests are merged by the stations or by a loop. Everything else is a model, checked by another model.
The machinery → how the stations are configured, briefed and kept in time with each other.
The live board → what the factory is actually doing right now, generated from its own tools: station status, where work comes in, and ninety days of throughput.