Engineering log
How Vibes DIY itself gets built: the bugs, the evals, the architecture calls and the agent workflow. We share how it works because every vibe is scoped to its own data and you can read its code, and the platform under it should be just as easy to understand.
54 posts · follow this lane: RSS · Atom · or the whole blog
-
November 5, 2026
Three AI judges helped write our home page
Theo Browne showed that a council of AI models can score a design and push it better, round after round. We pointed the same idea at the first screen of Vibes DIY, and in one day it climbed from 5.7 to a best of 8 out of 10.
-
October 23, 2026
Cattle not pets
We start a fresh copy of Vibes DIY for every change we make, so our servers are a herd, not a pet. A security review this week found two protections that only switched on when someone remembered to. Now every copy is born with them.
-
October 8, 2026
We Know Too Much About How Mercury Doesn't Think
We spent a week trying to make a very fast, very cheap model plan new apps as well as our careful one. It lost round after round, and losing showed us its real job: a quick first read of your idea. That's live now, and your first app is on screen in about half the time.
-
September 23, 2026
How we use Muse to get more done in parallel
Give Muse a clear task and its own worktree. Keep the main conversation available for decisions, then bring the result back through independent review.
-
September 18, 2026
Good vibes only
We already have one rule for how we talk to the code generator: never tell it what not to do. This is the same rule for how we talk to people. Every bummer sentence has a dope version, and the dope version is the one that ships — with nine inversions from our own product, most of them shipped the day this was written.
-
September 15, 2026
Your app already talks to the model
Everywhere else on the web, calling an AI model from a browser leaks a key, so every model believes an AI call needs a server. Ours does not, and our building agent kept adding one anyway. Here is how we taught it the page's own habit in two sentences, without ever saying the word no.
-
September 11, 2026
Ten strangers, ten phones, one evening
We put our home page in front of ten people we had never met, on their own phones, with a recorder running. Eight of the nine who made an account lost the first thing they typed. Here is what they built, what broke, and what we changed the same week.
-
August 5, 2026
Nine quiet minutes and a screenshot
Most agent output is written for the person who would have done the work by hand — branches, file paths, a running commentary of green checkmarks. everybody-vibes is the mode that strips all of it out: results and pictures in the conversation, options side by side when it's a matter of taste, every change parked as a draft a human flips, and every word of shop talk moved onto the pull request. Install it in one line.
-
July 28, 2026
No negative tokenization
The one rule we enforce hardest on our code-generation prompts: never tell the model what not to do. A prohibition ships the exact spelling of the mistake into the context and raises its salience — so we teach only the good shape, fix the example instead of the rule, and point an automated gate at prompt edits that say "don't." Behind the scenes of how you school a code generator.
-
July 28, 2026
The curb cut and the robot
We built a no-footguns app platform for people who've never deployed anything, and it converged — genuinely unplanned — on the shape of an autonomous deployment system for AI agents. That convergence is our pitch to experts: a platform for everyone is the only kind whose abstractions can't afford to leak, and the only kind you can safely hand to a fleet.
-
July 27, 2026
Making Pickathon fast
The sequel to our festival-app detective story. The mystery ended with a twist: an empty app loaded almost as slowly as the real one, so the remaining fifteen seconds were ours — the platform's. This is the ledger of paying them down: a compiler shipped to people who only read, two innocent-looking import lines that dragged whole libraries along, a 60 KB fix we built, measured, and threw away, and the cache our own ad clicks could never hit.
-
July 27, 2026
The case of the slow festival app
A festival schedule app got slower the more people loved it, then stopped loading entirely — days before the gates opened. Following the clues (a crash code, a database that read like a diary, one question asked 551,551 times, and a helper that had quietly gone blind) is the best case we can make that debugging is a mystery genre — and you're allowed to play detective.
-
July 24, 2026
The day we gave shell-less agents hands on your data
A look back at how vibes-diy mcp came to be — the shell-vs-no-shell asymmetry that motivated it, and the design calls that gave Claude Desktop and Cowork a door into your vibe's live data.
-
July 20, 2026
From Local First to User First
We didn't return to local-first for the manifesto — we returned because every loading screen we profiled ended at the same place: the network asking permission to show you your own data. The story of a cutover where almost every fix was a deletion.
-
July 19, 2026
The first turn does less on purpose
We pulled access rules, sound effects, and backend wiring out of the first generation — and taught it to remember what it skipped. The app arrives faster, the skipped work comes back as an offer at exactly the right moment, and nothing gets locked in before you have the context to decide.
-
July 15, 2026
Don't reply to bots
Our social bot builds you an app when you mention it — and it just replied, enthusiastically, to a Hacker News mirror bot. The fix wasn't a smarter classifier. It was putting the guard in the layer that can see the tell.
-
July 15, 2026
The palette that resized your app
Clicking a color swatch made every app four times bigger. The trail led to a CSS variable name collision with Tailwind's engine, a months-old bug we'd politely documented as a 'platform quirk,' and a repair codemod that proves its own diff.
-
July 15, 2026
Your loading screen is a brand deck
The first-build wait now plays the brand brief Jona Bechtolt of YACHT designed for us — as a pure-CSS storyboard cut from the PDF's own vectors. Along the way the loading screen learned semantics: a color face that means 'seconds away,' recovery that settles instead of rewinding, and status labels mined from the build stream.
-
July 11, 2026
Apply now, verify in the background
Making cross-vibe navigation feel instant wasn't about faster answers — it was about asking the access question earlier, on a socket we already had, and remembering the answer honestly. A tour of the small freshness contract behind an instant-feeling hop.
-
July 11, 2026
The speed knob that made every mock global
One Vitest flag — isolate: false — gives every test file a shared module registry to run faster, so the last mock quietly wins across files. Three files mocked one module three different ways, a partial mock leaked, and it bricked our npm release for two days. Here's the villain, and the three moves that fixed it.
-
July 11, 2026
The meter read zero
A batch of latent-cost bugs — a green-check gate that a rebase-merge dodged, a cron that did nothing but spin up runners, a deploy that compiled the app twice, an unminified worker parked on Cloudflare's startup-CPU cliff, a lockfile check running once per shard, and a test pool tuned for cores we no longer had. All free and invisible while the repo was public. Going private billed them all at once, and turned it into a performance event.
-
July 11, 2026
The invite that can't be an oracle
We built an email-invite growth loop where privacy is structural, not a later patch: the opt-out list shipped before the send button existed, the send endpoint returns the same 'ok' whether or not you're a user, and a sandboxed app can ask to invite a friend but only the platform gets consent.
-
July 11, 2026
The eval learned to read the UI
Our codegen eval graded generated apps with static regexes — until the failures got semantic. A regex can't tell who wrote a document, and it can't see a quiet refusal: an app that technically satisfies a social-sharing prompt but buries the share affordance in its UI. So the eval hired a judge that reads the generated App.jsx and grades what a user would actually experience.
-
July 11, 2026
Ship it dark: the scariest change is the smallest line you write
We shipped social-graph notifications as a sequence of dark slices — schema first, then the wire, then the digest — so the PR that finally turned the feature ON was the smallest and least risky one in the stack. Merge ordering was the rollout guard, no feature flag required.
-
July 11, 2026
The three doors
Three 'public' schedule feeds — DEF CON, Oregon Country Fair, IETF side meetings — each turned out to be unreachable from where the app runs. The fix walked the data in through the app's own database. Here's how a workaround hardened into a genre, and why the real answer is a server-side fetch.
-
July 11, 2026
The gallery is in the HTML now
The front-page gallery used to wait for React, a WebSocket, and two feed requests before painting a single tile. Now the worker composes the same feed during server render, and the gallery is real pixels in the first HTML byte stream — wearing MTV-style credit plates.
-
July 11, 2026
Delete is just a put
We shipped a careful, provenance-tracked delete permission — and deleted it a few hours later. A delete is sugar for writing a tombstone, and anyone who can write a doc could always destroy it by overwriting. The fix wasn't a better gate; it was one less concept.
-
July 7, 2026
You've come a long way, baby
A year ago this platform was a React SPA with no backend at all — its entire server story was vending an OpenRouter key into your browser. Today it's a stream-based platform with live data, access rules, and server-side AI. The retrospective, with the credit where it's owed: Meno Abels hardened the architecture everything since is built on.
-
July 7, 2026
Asked to build platform infrastructure, the agent picked a vibe
We asked an agent to build our social mention-builds bot — @-mention us on Bluesky and the platform builds your app and replies with a screenshot. It surveyed the codebase and chose a vibe as the production home: scheduled backend, credential vault, access control, dashboard, all product primitives. When your own agents reach for your product to run your platform, that's what feature-complete looks like.
-
July 7, 2026
We shipped a perfect cache that zero real users could hit
The SWR cache for vibe HTML worked flawlessly — 230ms hits, correct stale-refresh lifecycle — for the bare URL nobody requests. Every real page view carried one query param, and both ends of the cache read it as personalization and bypassed. The fix wasn't more cache; it was teaching the eligibility gate that the platform's own version pin is a cache key, not a personal preference.
-
July 6, 2026
The cruft isn't in the files — it's in the seams
Feature velocity is way up, so we braced for a mountain of AI-generated cruft and ran a whole-monorepo housecleaning audit: five parallel explorer agents plus a dead-code linter. The files came back mostly clean. The debt was hiding between them — in workflows, manifests, and docs nobody rewrites.
-
July 6, 2026
Cloudflare ate our ETag
We shipped a whole conditional-request pipeline — input-derived ETags, a 304 fast path, an edge cache — and none of it ever fired, because Cloudflare silently strips validators from HTML. Three plausible fixes died on the wire before a zone-settings dump found all four culprits.
-
July 6, 2026
Trust the target, bless the person
Designing outbound fetch for user backends died in one sentence: the owner is an attacker in some cases. So trust comes from somewhere that isn't the tenant — the target's own CORS policy, a platform list where adding a host is a PR, and blessing people instead of approving hosts forever.
-
July 6, 2026
One pixel of fake scroll
iOS scrolls to the top when you tap the status bar — unless your whole app lives in a cross-origin iframe, where the gesture never arrives. We catch it anyway: a hidden pixel of overflow, parked at scrollTop 1, that only the native tap can move.
-
July 5, 2026
The third implementation is a markdown file
We built iPhone calendar subscriptions into a festival picker, ported them to a bike-ride tracker, then distilled everything both apps taught us into a codegen skill — and proved it works by asking for the feature in one sentence.
-
July 4, 2026
First paint is the app
How fast a user first sees their app is the product. In one July arc we cached the entire HTML serve at the edge, seeded SSR with real data, compiled the styles on the server, took the auth overlay off the critical path, started the first build before the browser even landed on the page, and made the reveal push-first instead of polled. Then dark mode handed us the invoice.
-
July 4, 2026
Announcing beast-mode: follow-through for high-fan-out development
We extracted our agent working culture into a portable Claude Code skill. It doesn't make one change better — it makes ten parallel changes all land. Install it in any repo with one command.
-
July 2, 2026
Every PR plants a seed: how this blog gets written
Every unit of work that ships here drops a one-file capture note next to the code. Periodically we mine the pile and combine the good ones into posts. That's why reading this blog is the closest thing to watching the project happen in real time.
-
July 2, 2026
270 PRs in 17 days — the speed was the safety
We pulled the stats on 17 days of merges: 270 PRs, ~223k lines of churn, a median PR of 196 lines merged in under an hour, 95% agent-authored. The surprise wasn't the volume — it's that velocity and safety turned out to be the same property.
-
July 2, 2026
Not a loop, on purpose
Everyone assumes an AI app generator must be an agent loop — a model reading files with tools, editing, iterating. Ours is a pure function: database state in, one streamed response out. That purity is load-bearing, and it's a strength, not a lag.
-
July 1, 2026
From one CLAUDE.md to forty runbooks
A year of agent documentation, read straight from git history: a 103-line init file, a 326-line grab-bag, a hard split into version-controlled runbooks — and what each era says about the work we were shipping at the time.
-
June 30, 2026
If tokens were free, we'd precompute every chip
A suggestion chip is a transform of the vibe you're on, and clicking it is real codegen. So we cache the result — a repeat click becomes an instant read instead of regenerating. The interesting part isn't the cache; it's the deny-by-default gate that decides who is allowed to read it.
-
June 29, 2026
The edit button that was secretly a save loop
We made the code editor live inside the running app — no hop to a separate chat route. 'Make the Code tab editable' sounded like a UI task. It was a distributed save loop in disguise, and the whole thing hinged on one decision: re-pin, don't navigate.
-
June 28, 2026
Why our agents don't get a laptop
A capability that only works on a hand-configured laptop quietly pushes all the work back to the laptop. Here's why we made cloud containers the default home for agent QA — and three war stories from getting browser validation to run there.
-
June 28, 2026
We only needed one Durable Object
We had three Durable Object classes that were really one handler surface opened against three shard keys. Here's how we collapsed them into a single class — and which 'separate-class' argument fell apart the moment we pushed on it.
-
June 28, 2026
We deleted our auth dependency. Nothing changed.
We moved our device-id PKI and Clerk token verifiers in-house, out of @fireproof/*, with zero call-site changes — gated by a byte-compatible golden harness so the lift was provably identical before we cut the dependency.
-
June 28, 2026
We deleted the preview pane
We moved first-generation onto the deployed app itself — stream into the card, hot-swap the running iframe, de-blur the app forming behind it — and in doing so deleted the separate preview pane entirely. The risk was the simplification.
-
June 28, 2026
Save a tree, skip the tests: leaner CI for docs-only PRs
A README typo doesn't need a Playwright suite and a Postgres cluster. Teaching docs-only PRs to skip the heavy CI work — without falling into the 'required check stuck pending' trap.
-
June 27, 2026
The NUL byte that broke every write (+7 more)
Eight little fixes from the build log — a NUL byte that took down every Postgres write, an iOS audio-unlock race, a markdown blank line that clobbered a file — each with a lesson bigger than the diff.
-
June 27, 2026
Teaching an AI you're not 'the owner'
Generated apps used to default to owner-gated permissions — broken for everyone but the creator. Here's how we flipped the default to author-owned, steered the model toward multiplayer without ever saying 'don't,' and built a metric so the prompt could iterate itself.
-
June 23, 2026
The vibe that locked out its owner
A vibe locked its own owner out of saving. The fix wasn't a better isOwner check — it was deleting isOwner and treating 'owner' as a seeded, revocable role instead of an ambient super-user.
-
June 9, 2026
How we batch-upgrade apps with screenshots
Every deployed Vibe serves both a live screenshot and its own source. That closes a visual feedback loop an agent can run alone — see the app, fix the code, push, look again — and fan out across dozens of apps at once.
-
June 9, 2026
How we eval the generator
Every edit to the system prompt changes every app anyone generates. Here's the harness that measures generation quality — 46 prompts in three sets, scored 1–5, fanned out across a Workflow pipeline — so we know within a coffee break whether a change made things better or worse.
-
June 9, 2026
Can one English prompt rebuild our festival app?
We tried to recreate Pickathon's built-out 2026 app — data model, views, and a fiddly access policy — from a single plain-English prompt. It got ~90% there on description alone; a URL and a one-sentence schema closed the rest.