I didn't write most of Asset Forge's code by hand. I wrote cards, read handoffs, made decisions and checked the results. The code came from Claude agents (Opus, running in Hermes through the official Claude Code plugin), one card at a time.
This post is about how that works day to day, and where it doesn't.
The board is the plan
Every piece of work is a card on a Kanban board. A card has a body: why it exists, what to build, the rules it has to follow, and what "done" means. When an agent finishes, or gets stuck, it writes a handoff: what it did, what it checked, and what's left.
An orchestrator agent sits between me and the workers. I tell it what I want, it writes or edits cards and comments, and it answers the workers' questions when it can. It wrote 335 of the 337 comments on the board. So when I say "I wrote a card", it's usually "I asked for it and the orchestrator wrote it". The decisions are mine; the typing mostly isn't.
On 11 October the Asset Forge board had 131 cards and 274 worker runs. 128 cards went to the main worker profile and 3 to a separate profile that only reconciles merge conflicts.
One run is rarely enough
Only 120 of those 274 runs ended cleanly with "completed". 71 of the 131 cards needed more than one run.
The biggest reason is the step budget. Each run gets a fixed number of steps (tool calls, roughly), and long cards use them up. 22 runs ended with the message "Iteration budget exhausted (110/110)", and 47 more stopped themselves saying they had run out of steps.
That's not a disaster, because the work isn't lost. A card that runs out writes a handoff and gets picked up again from that point. An overnight helper resumes cards that stop this way; it has done so 19 times. But each restart costs time, and the card with the most runs so far has needed 13.
Early days: one checkout and a lot of "don't touch that"
For the first few days, every card worked in the same copy of the code. Coordinating meant orchestrator comments like "Don't run any git command that writes (add, commit, stash, checkout) until ... S1 is done", because another card was rewriting the repository's history at the time.
That works with one card at a time. It doesn't work with two.
Lanes
On 5 October a card called PX0 added lanes (v1.8.2). Each card now gets its own git worktree and branch, its own ports, and a copy-on-write copy of my real asset library. Nothing a lane writes reaches my data. On my disk the copy is instant and takes no extra space; making a new lane takes about 19 seconds with a frontend build.
Things that really are shared go through locks: submitting to Higgsfield, Blender, and one lock for heavy CPU work. That last one exists because my PC doesn't cope well with long all-core loads, so only one heavy job runs at a time. The card rules say to wait for a lock "in ONE blocking call, not by polling", and to commit after every working step.
The lock log has 9,544 entries so far.
One way into main
af_merge.sh is the only way a lane's work reaches the main branch. Under a merge lock it:
- rebases the lane on the latest main;
- folds in the lane's change notes and bumps the version;
- builds the frontend and runs the full pytest suite;
- runs the UI checks;
- fast-forwards main, tags the version, restarts the live app and checks that
/api/healthreports the new version.
If anything fails, main doesn't change. If the rebase hits a conflict, the script prints a ready-made card for the reconciler profile. That has happened three times. All three were what the reconciler called "disjoint intent": both sides had added different things to the same file, so it kept both. As one handoff put it, "the tuple is additive, so no design question required picking an answer".
45 lane merges have gone through this way, from v1.9.0 to v1.36.1.
lane A worktree + branch + ports + its own data ─┐
lane B worktree + branch + ports + its own data ─┼─▶ af_merge.sh ──▶ main ──▶ tag ──▶ live app
lane C ... ─┘ (merge lock: rebase, build, pytest, UI checks)
conflict? ──▶ a card for the reconcilerTwo at a time
I run two cards at once. There's a written rule to "raise parallelism from 2 to 3 only after measuring". More cards in parallel drain the Claude and ChatGPT plans faster, and they mostly end up queueing for the same merge lock anyway.
The honest downsides
The gate had a hole. For the first few days, the UI-check script always exited with success, even when a check failed. The failure flag was being set inside a subshell, so it never reached the script itself. That meant af_merge.sh never stopped on a failed UI check. The effects card (FX1) found it; a follow-up fixed it in v1.10.3, and the lane card added a test for it in v1.10.4. FX1's own handoff said it plainly: "Because of that last bug, earlier lane merges could have gone in with a failing UI check."

Merges queue. A full merge took about an hour, and it held the heavy-CPU lock the whole time. Other cards ran out of steps just waiting for it. One handoff reads: "Out of steps while queued for heavy-cpu (help1's merge has held it for over 20 minutes)." Post 5 is about making that faster.
Agents loop. One early card kept repeating the same failing action in the Higgsfield web page. I stopped it twice: first for "looping on the same failing Higgsfield action", then because it was using the wrong reference picture of the drifter. It ended up archived.
Usage limits stop everything. 21 runs ended because the Claude usage limit had been reached. On the morning of 7 October, two cards (procedural walk and the guides) were sent out every few minutes from about 07:55 to 10:20 and bounced every time. On 11 October, 9 of one card's 13 runs ended the same way.
The live app dirtied main. The running app rewrote a couple of files that were tracked in git, like the pricing data and the motion library index. That stopped merges with "main checkout had outside changes" until a housekeeping card (v1.31.0) moved those writes out of git.
Crashes. 9 runs crashed. Once the PC restarted at 04:08 in the middle of a merge, and a stash had to be put back by hand.
Self-reports need checking. A handoff is the agent's own account, and sometimes it's wrong. The tile card first said it was done with no real runs and an Export button that did nothing. A reviewer sent it back, and the cause turned out to be a toast notification covering the button. A layout card's check failed when the reviewer ran it again. Another card's handoff said the work was built but not committed. Review rounds catch these, but only because someone runs things again instead of trusting the summary.

Measurements beat descriptions. One more lesson came from a card that used a vision model to check contrast. The vision model said some links were green. The page's own styles said they were black. Vision models misread too, so where something can be measured, the measurement wins.
What I'd tell someone trying this
It works. 66 versions in ten days is more than I'd have written alone, and most of it is tested better than I'd have tested it.
But it isn't hands-off. The useful work on my side is writing clear cards, saying what "done" means in a way that can be checked, and reading handoffs with some suspicion. The process around the code (lanes, locks, one merge gate, a test for the gate) took real effort, and every one of those pieces exists because something went wrong without it.
