Engineering design

FOUNDRY

FOUNDRY is the engineering framework of a one-person company. The company has one person, the operator. Its engineering workforce is AI agents from two vendors, Anthropic (Claude) and MiniMax. Built with Claude.

The company has two business units. FOUNDRY is the engineering business: work comes in, it is built, tested, shipped and probed. TIDE-WAVE is the trading business and today it is FOUNDRY's only customer. The engine itself knows nothing about trading; trading plugs in as sources of work and as the product that ships.

Three rules hold it together. Every piece of work is a bug record, and a bug is one step. Nobody pushes to the main branch; only the test farm merges. Every feature ships with a switch that turns it off in seconds without a deploy.

1 · The whole system

Work flows through one bug database

WORK COMES IN THE CENTRE BUILD AND VERIFY DECIDE, SHIP, RUN Operator specshis requests, kept word for word Phone commentsa reply to any push notification Live trading eventstrade monitor, exit guardians Nightly postmortemsan agent reads the day's charts Sim and replay findingseach loss read as its own case Error reportsSentry, test-farm failures Health monitorswhat stopped running Test Manager auditgaps in what is tested each source files a bug and is recorded as its origin Quality gate Specific, measurable, achievable, result-driven, time-bound, with evidence. Fails → filed as rejected, never built. passes → open Bug database DiscoveredBugs One record per unit of work: a fix, a feature, a study, an ops run. • one bug = one step • order is a dependency link, not prose • priority P0–P3, severity S1–S3 • origin: which source filed it • every status move goes through one function and is audited The roles never call each other. Project Manager WHAT WORK: reasons the next step for every open bug and acts on it; decides how many agents run at once reads open bugs spawns, picks the vendor AI builder agents Claude (Anthropic) · MiniMax one git worktree and feature branch per bug; builds from the bug record, never from another agent's memory submits the branch Crucible the gated check-in farm 1 an idle farm box claims it 2 rebase on current master 3 rule gates + full test suite 4 trading replays of pinned cases 5 AI code review (advisory) 6 one merger at a time fast-forwards master Pass: bug resolved with the merge sha reject: bug reopens with a handoff (kept branch, failing tests, log) Operator the one person: specs, vetoes, the decisions only he can make Chief of Staff WHAT THE OPERATOR SEES: approves routine PM requests itself, escalates live-money or irreversible ones asks by exception, to his phone master branch (protected) only the Crucible merger pushes here merge Release Manager WHAT SHIPS: GO/HOLD on accepted work, deploys the tested sha, restarts the services that run the changed code TIDE-WAVE the trading business, the customer every feature behind a hot switch, ON by default, off in seconds with no restart and no deploy Event bus every status move is written to BugEvents and published live; roles and agents subscribe instead of polling ROLES BESIDE THE FLOW · EACH DECIDES ONE THING · THEY HAND OFF THROUGH BUG STATES Test Manager WHAT IS TESTED scores the confidence each build earned; audits the suite Infrastructure WHAT RUNS fleet matches its manifests; restarts or files a bug Risk Manager WHAT SIZE WE TRADE only through sizing switches, inside the operator's bounds Public Relations WHAT CLIENTS HEAR client messages and their schedule Expense + Tax WHAT WE SPEND, OWE costs beside earnings; quarterly estimates; never pay or file Compliance WHAT WE MAY DO, WHO HOLDS THE KEYS tracks terms and key expiry; reminds only the next trading day produces the next findings: the trading flywheel and the engineering flywheel turn each other
Work arrives from many sources and becomes a bug record. The bug database sits at the centre: the named roles never call one another; each one reads bug states and moves them. A rejected check-in goes back to its bug with everything the next agent needs, because the next agent may be a different model from a different vendor. The loop at the bottom closes the circle: what ships changes the next trading day, and that day files the next bugs.

2 · The bug lifecycle

Every hand-off is a status move on the bus

filed quality gate rejected never built fails the S.M.A.R.T. test corrected re-file passes open waiting for an agent PM spawns atomic claim resolving an agent builds the fix submit in_crucible the farm tests it merged resolved merge sha stamped rejected or rebase conflict: back to open with a handoff (kept branch, failing tests, log tail, attempt count) reviewing needs a look merged, but touches no file a decision reads or rejected 3 times in a row (escalated) triage sends it back to work closed verified reviewer checks it landed, live Also: wontfix (decided not to fix) and escalated (waiting on a human). Terminal states: resolved, closed, wontfix, rejected. Dashed outline = end state. Event bus each arrow above is one guarded status move → one durable BugEvents row + one live message: fingerprint, from, to, actor, note, sha, time Who listens: the builder agent waits on its own bug until resolved the Project Manager picks the next step from the new state the code reviewer's verdict rides the same bus, so the submitter sees it at once A move from a state that already changed loses the race: two agents cannot claim one bug.
States come from the lifecycle module's list: open, resolving, in_crucible, resolved, reviewing, closed, wontfix, escalated, rejected. Each move is an atomic database update guarded on the state the mover expected, and each move publishes one event, so an agent subscribes to its bug instead of polling it.

3 · A check-in through Crucible

Cheapest checks first, one merger at the end

1 Submit the agent pushes its branch, never master, and moves on 2 Queue queued; a change to the live trading path is held, then released by auto-ack 3 Claim an idle farm box takes it atomically; one suite per box, many boxes at once 4 Rebase onto current master; a release is frozen once and that exact sha ships 5 Rule gates static checks over the diff: switches, studies, time handling, imports 6 Smoke tests a fast build check; a broken branch fails in seconds Rejected · master untouched the failure fires at once and the bug reopens with a durable handoff: reason, failing tests, log tail, the kept branch, attempt count. After 3 rejects in a row the bug goes to review for a human. conflict 7 Unit suite the full suite in its own checkout and environment 8 Time budget tests over 10 s are named; a slow test usually hides a live call. Advisory today 9 Release reads scenario sims, speed ratchet, Test Manager confidence; gate deploys 10 AI code review advisory; MiniMax, Claude as fallback; comments are written into the bug 11 Trading replays pinned real-day cases and artifact gates, run in parallel 12 Merge one merge lock for the whole farm: fast-forward master and push Accepted bug resolved with the merge sha and test count; the Release Manager reads the release-tier results Master moved during the merge the check-in is requeued for a fresh rebase; after 3 lost races it is rejected Every queue move (submit, ack, claim, accept, reject, conflict, requeue) is published on the check-in bus; the submitter watches it instead of waiting in silence. Stages 4–7 and 11 can reject. Stage 8 is advisory today. Stage 9 holds a deploy, not a merge. Stage 10 records feedback and never blocks; its blocking mode sits behind a switch that is off.
Crucible is the only path to the main branch. The farm boxes pull work from a shared queue; there is no central dispatcher. Test passes run in parallel across boxes, and only the final merge is serialized. Stage 5 also requires a recorded study for any new trading rule switch, and stage 11 replays the trading cases a change can touch.
A moved base costs only what changedEach stage result is stored under a digest of the bytes it read, so a rebase re-runs only the stages whose inputs changed.
A merge that would void a run waitsAnother check-in that changes files a running stage reads waits at its merge step, in claim order. It is never rejected for waiting.
A busy box is untouchableThe claim lease and box heartbeat answer "is this box busy". No deploy, restart or reclaim touches a box with a run in flight.

4 · The machine farm

Machines by role

The fleet is a set of small Mac machines, each with a committed manifest of the services it runs. Several machines hold more than one role, so the counts below overlap; the notes say where.

Database primary ×1 document database (writable primary), the live event bus (pub/sub), the shared snapshot file store bugs, check-in queue and events live here Database secondaries ×2 voting replicas of the primary; three members in one replica set one also runs live trading, the other is the compute-cluster head replicate Dev box ×1 the operator's terminal and the coordinating agent sessions; feature work in git worktrees, pushed as branches only Code host (git remote) feature branches from agents; master, written only by the farm merger push branch Manager boxes ×3 Project, Release, Infrastructure Managers share one; builder agents are spawned there. Risk, PR, Expense, Compliance on a second; Test Manager on the research box read and move bugs push branches Crucible farm ×5 machines on the eligible list; each runs one runner that pulls the queue and tests one check-in at a time one also serves the beta web site, one also hosts managers pull queue merge master Live trading ×1 the trading engine, broker streams, account monitors and exit guardians; also a database secondary its services restart only on a deploy orders, events Compute cluster 1 head the head (also a database secondary) schedules replay and training units on workers across the boxes; documented as a 12-node cluster. Pure compute, never test runs or live API calls. store every unit Web ×2 stable dashboard and a beta site the beta shares a farm machine Research ×1 default replay lanes, data sync, Test Manager read
Counts come from the committed service manifests and the farm settings in the repository; machine names, addresses and accounts are left out. Everything coordinates through the database primary: the farm pulls work from a queue there, the managers move bugs there, and the event bus runs beside it. The compute cluster is kept for pure number work; the test farm runs on its own queue because a test pass needs git, subprocesses and network access.

The ten named roles

One decision each, no shared knobs

Each manager is a small service over a pure library with its own command line and tests, and an LLM for the judgment calls. A new responsibility goes to the role whose authority covers it, or it needs a new role.

Project ManagerWhat work to do: the next step for every open bug, and how many agents run at once.
Release ManagerWhat ships: GO or HOLD on accepted work, then the deploy and service restarts.
Test ManagerWhat is adequately tested: confidence per build, suite audits. Never skips a test.
Chief of StaffWhat the operator sees: disposes of routine requests, escalates by exception, keeps a same-day veto window.
Infrastructure ManagerWhat runs: the fleet matches its manifests and stays up. Never merges or deploys.
Risk ManagerWhat size we trade: only through registered sizing switches, inside the operator's bounds.
Public Relations ManagerWhat clients hear: the client communication schedule.
Expense ManagerWhat we spend: AI, data and infrastructure costs shown beside trading earnings on one chart.
Tax ManagerWhat we owe and when: realized gains and quarterly estimates, net of deductible costs.
Compliance and Security ManagerWhat we may do and who holds the keys: terms, licences, key and token expiry. Tracks and reminds only.

History and hardware

Hand-coded for six years, then the agents took over

I wrote the project by hand from March 2020, and in 2024 built my own generator that wrote Python from historic trading scenarios. From January 2026 AI coding agents made most of the commits, and by October 2026 more than 80% of them. The whole farm runs on 12 Mac minis on one shelf at home. Numbers measured November 4, 2026, and still growing.

† 2024 has extra commits from my own code generator, which wrote Python automatically from historic trading scenarios - an experiment before the AI agents.

Commits per year: hand-coded 2020 to 2025, AI agents from 2026

The Foundry build farm: 12 Mac minis on one shelf