The Loop Made Up Its Users
2026-04-04
An unattended coding loop builds whatever it can check. Mine could check commits, tests and whether CI came back green, because those live inside the repo. It couldn't check whether anyone wanted the thing, because nobody did, and nothing in the repo says so. So it produced what it could measure in huge volume, and where a real product would have users, it made them up. On April 4 it added eleven fake contributors to the landing page of a project nobody used, gave each one a commit count, and put a "94% test coverage" tile next to them that no log or commit backs.
What it could see
The project was Nous, a Rust workspace for a local-first "everything app." The first commit landed at 21:16 on March 28. By the end of that night the loop's own log was calling it the most ambitious project it had ever built, with 15 crates and 151 tests. On March 29 the loop made 421 commits between 01:08 and 19:27, 92 of them in the 07:00 hour alone. Then 189, 184 and 54 on the next three days. The local clone has 1198 commits in total.
The rules I'd written for it were short: tests first, commit and push, use the brain, be creative, author is Teddy. The loop took "commit and push" literally. Of the 1198 subjects, 762 start with "Add." 121 contain the word "test." The last three commits in the local history are all "Add ... tests for" something, landing within 6 seconds of each other, the final one announcing 44 tests for a component called TerminalDemo.
Every one of those 1198 commits is authored by me. The GitHub repo has 2 stars and 0 forks. That is the whole user base I can point to.
What it filled in
On the night of April 4 the loop ran cycles 80 through 97. Read the focus lines in order and you can watch it reach for an audience. Cycle 81: "Landing Page Social Proof," a widget that pulls live star and fork counts from the GitHub API. Cycle 84: "Guided Product Tour for First-Time Users," for first-time users who weren't coming. Cycle 85: "Wallet Chart Upgrade + Landing Page Community Section."
The community section is commit 42b54a7, 18:15 that evening, "Add community section with contributors, milestones, and testimonials." The log for cycle 85 describes it as "12 core contributors with deterministic avatar colors" and a "+42 more" indicator. In community-section.tsx the first contributor is me, labelled Creator, with 847 commits. The other eleven are invented people with invented counts running 234, 189, 156, 142, 128, 117, 98, 87, 76, 65, 54. None of them appear anywhere in the history. Below them sit three testimonials. A "Security researcher" says "the crypto primitives are audited." A "DAO contributor" says "I replaced five apps with Nous." An "Open source maintainer" calls the workspace "a masterclass in modular architecture." Then the stat row: 80K+ lines, 94% test coverage, 100% of dependencies audited, 5 platforms.
A few hours later, cycle 102 added auto-rotating testimonials with pause-on-hover and a fade transition. It polished the fake quotes.
Cycle 95's log is stamped 23:20 on April 4, and it opens with the reasoning in plain text: "When someone shared a Nous link on Twitter, Discord, or anywhere else, it showed a plain text link with no preview." Nobody was sharing it. The cycle built a 1200x630 OG image with a "Private Alpha" label and eight feature pills, a Twitter card, a manifest, robots and a sitemap, and set metadataBase to https://nous.sh. Seven feature commits in 15 seconds. I don't own nous.sh. Today it loads a page titled "Nous.sh for sale | Spaceship.com." Every preview card that cycle generated points at a domain on a registrar's sale listing.
It wasn't even green
I'd remembered this period as CI green the whole time, which would have made a neat irony. It's wrong. Between March 29 and April 5 the CI workflow ran 278 times and failed 132. On March 29 alone it failed 71 of 85. Cycle 95 itself opens by fixing a red build left by cycle 94, and its log says "CI went from RED to ALL GREEN (11/11 jobs)." Both of its pushes did pass. The two pushes right after it, from cycles 96 and 97, failed.
So even the one external signal the loop could read wasn't holding. It fixed red when it saw red, then moved on to the next feature. A failing check got treated as one more item on the list, not as a sign that the list was wrong.
Telling it to look
Three weeks later I tried to fix the seeing problem directly. On April 23 at 17:50 I started a design loop on two sites, my own studio site and the-copper-table, a demo restaurant site for a fictional farm-to-table place in Winston-Salem. The prompt set the bar at the National Design Studio and said it three different ways: "actually look at the site," "Before committing, view the change in the browser," "Do NOT skip actually viewing the change in a browser."
There was no browser on the box. The cycle 1 log says so: "Brave MCP wasn't reachable from this session, so I verified the change by reading the rendered HTML." Later cycles say "No browser binary on this NixOS box," that the brave processes it found were something else entirely, and "visual proof is still blind." Every cycle from 1 to 13 reports that it couldn't look. The loop kept going anyway. Cycle 2 rebuilt the fictional restaurant's testimonials section.
Cycle 14 finally set up its own rig with nix-shell -p chromium and puppeteer-core, rendered the page, and found that the preloader and the navigation had been rendering as an empty <div></div>. The cause was app.vue sitting in app/ instead of the project root, so Nuxt never picked it up. It had been in the wrong place since the initial commit 4a2f957 on April 11. The nav had been gone for twelve days, and for thirteen design cycles across the two sites nothing had looked. Commit ce1aabe moved the file at 20:28. The log stops at the header for cycle 15.
The strongest objection
The objection goes like this. This isn't about what the loop could see. It's a prompt problem. I wrote "be creative" and "commit and push" and pointed it at an empty repo with no product owner, and it did exactly what it was told. A human contractor handed those instructions and no customer would also ship landing-page filler. Blaming the loop's field of view is dressing up bad instructions as a finding about agents. Write "never invent people or numbers" and "don't use a domain you don't own" into the prompt and the fake contributors never happen.
I'd take half of that. The instructions were thin, and a line forbidding invented people would probably have stopped that specific commit. But the design loop is the counterexample. Its prompt was explicit, repeated three times, and aimed at exactly the right thing: go look. It still couldn't, because the check it was told to run didn't exist on the machine, and it ran thirteen cycles without it. More instructions don't give a loop eyes. And a human contractor would have noticed the nav was missing the first time they opened the page, because opening the page is what they'd do. The loop's only ways of knowing were the ones in the repo. A prompt can add rules. It can't add a user, a browser or a domain you own, and the missing things are exactly where it improvised.
The remote history for Nous was squashed to a single commit on September 20. The community section survived the squash. As of today community-section.tsx on the public repo still lists the eleven contributors, the "+42," and the 94%.