<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Vibes DIY Blog</title>
  <subtitle>Field notes, evals, and stories from building the no-code app builder that turns a sentence into a working app.</subtitle>
  <link href="https://good.vibes.diy/blog/feed.xml" rel="self"/>
  <link href="https://good.vibes.diy/blog/"/>
  <id>https://good.vibes.diy/blog/</id>
  <updated>2026-07-07T12:00:00.000Z</updated>
  <entry>
    <title>Asked to build platform infrastructure, the agent picked a vibe</title>
    <link href="https://good.vibes.diy/blog/the-agent-picked-a-vibe.html"/>
    <id>https://good.vibes.diy/blog/the-agent-picked-a-vibe.html</id>
    <updated>2026-07-07T12:00:00.000Z</updated>
    <published>2026-07-07T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;s what feature-complete looks like.</summary>
  </entry>
  <entry>
    <title>We shipped a perfect cache that zero real users could hit</title>
    <link href="https://good.vibes.diy/blog/the-cache-nobody-hit.html"/>
    <id>https://good.vibes.diy/blog/the-cache-nobody-hit.html</id>
    <updated>2026-07-07T10:00:00.000Z</updated>
    <published>2026-07-07T10:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;t more cache; it was teaching the eligibility gate that the platform&apos;s own version pin is a cache key, not a personal preference.</summary>
  </entry>
  <entry>
    <title>The cruft isn&apos;t in the files — it&apos;s in the seams</title>
    <link href="https://good.vibes.diy/blog/housecleaning-at-agent-speed.html"/>
    <id>https://good.vibes.diy/blog/housecleaning-at-agent-speed.html</id>
    <updated>2026-07-06T14:00:00.000Z</updated>
    <published>2026-07-06T14:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>Cloudflare ate our ETag</title>
    <link href="https://good.vibes.diy/blog/cloudflare-ate-our-etag.html"/>
    <id>https://good.vibes.diy/blog/cloudflare-ate-our-etag.html</id>
    <updated>2026-07-06T12:00:00.000Z</updated>
    <published>2026-07-06T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>Trust the target, bless the person</title>
    <link href="https://good.vibes.diy/blog/the-owner-is-the-attacker.html"/>
    <id>https://good.vibes.diy/blog/the-owner-is-the-attacker.html</id>
    <updated>2026-07-06T11:00:00.000Z</updated>
    <published>2026-07-06T11:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;t the tenant — the target&apos;s own CORS policy, a platform list where adding a host is a PR, and blessing people instead of approving hosts forever.</summary>
  </entry>
  <entry>
    <title>One pixel of fake scroll</title>
    <link href="https://good.vibes.diy/blog/one-pixel-of-fake-scroll.html"/>
    <id>https://good.vibes.diy/blog/one-pixel-of-fake-scroll.html</id>
    <updated>2026-07-06T10:00:00.000Z</updated>
    <published>2026-07-06T10:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>Your backend can call the model now — and there&apos;s no key to leak</title>
    <link href="https://good.vibes.diy/blog/backend-callai.html"/>
    <id>https://good.vibes.diy/blog/backend-callai.html</id>
    <updated>2026-07-05T12:00:00.000Z</updated>
    <published>2026-07-05T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>backend.js gets ctx.callAI: one await, text in, text out. No API key exists anywhere in your app — the platform places the call like a switchboard operator, meters it to the user who triggered it, and hands your server code the answer.</summary>
  </entry>
  <entry>
    <title>Remix meta-hub into your own social media machine</title>
    <link href="https://good.vibes.diy/blog/remix-meta-hub.html"/>
    <id>https://good.vibes.diy/blog/remix-meta-hub.html</id>
    <updated>2026-07-05T10:00:00.000Z</updated>
    <published>2026-07-05T10:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Every post on this blog now ships itself to Instagram, Threads, and Facebook — published by an owner-only vibe that keeps the API tokens as database records and rotates them on a schedule. Because the publisher is a vibe, one remix makes the whole machine yours.</summary>
  </entry>
  <entry>
    <title>The third implementation is a markdown file</title>
    <link href="https://good.vibes.diy/blog/third-implementation-markdown-file.html"/>
    <id>https://good.vibes.diy/blog/third-implementation-markdown-file.html</id>
    <updated>2026-07-05T00:00:00.000Z</updated>
    <published>2026-07-05T00:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>First paint is the app</title>
    <link href="https://good.vibes.diy/blog/first-paint-is-the-app.html"/>
    <id>https://good.vibes.diy/blog/first-paint-is-the-app.html</id>
    <updated>2026-07-04T18:00:00.000Z</updated>
    <published>2026-07-04T18:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>Announcing beast-mode: follow-through for high-fan-out development</title>
    <link href="https://good.vibes.diy/blog/beast-mode-skill-for-claude-code.html"/>
    <id>https://good.vibes.diy/blog/beast-mode-skill-for-claude-code.html</id>
    <updated>2026-07-04T16:00:00.000Z</updated>
    <published>2026-07-04T16:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We extracted our agent working culture into a portable Claude Code skill. It doesn&apos;t make one change better — it makes ten parallel changes all land. Install it in any repo with one command.</summary>
  </entry>
  <entry>
    <title>Ninety days, twelve headline features</title>
    <link href="https://good.vibes.diy/blog/ninety-days-twelve-headlines.html"/>
    <id>https://good.vibes.diy/blog/ninety-days-twelve-headlines.html</id>
    <updated>2026-07-03T14:00:00.000Z</updated>
    <published>2026-07-03T14:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Since April 1 the platform grew a live data layer, per-app access rules, a server side, in-app editing, a real CLI, DMs, server-rendered vibes, env vars and secrets — and this blog. The quarter in twelve headlines, with links to the deep dives.</summary>
  </entry>
  <entry>
    <title>Pickathon made the fan-made planner official — your festival could be next</title>
    <link href="https://good.vibes.diy/blog/pickathon-adopts-the-picker.html"/>
    <id>https://good.vibes.diy/blog/pickathon-adopts-the-picker.html</id>
    <updated>2026-07-02T16:00:00.000Z</updated>
    <published>2026-07-02T16:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Pickathon liked the fan-built schedule planner so much they&apos;re now co-marketing it as Pick. Plan. Share. If you run a festival like Bumbershoot, Outside Lands, Sasquatch!, or Newport Folk, the same app is a remix away — you just point a coding agent at your schedule feed.</summary>
  </entry>
  <entry>
    <title>Every PR plants a seed: how this blog gets written</title>
    <link href="https://good.vibes.diy/blog/every-pr-plants-a-seed.html"/>
    <id>https://good.vibes.diy/blog/every-pr-plants-a-seed.html</id>
    <updated>2026-07-02T14:00:00.000Z</updated>
    <published>2026-07-02T14:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;s why reading this blog is the closest thing to watching the project happen in real time.</summary>
  </entry>
  <entry>
    <title>We might be the most agentic open-source project you can contribute to</title>
    <link href="https://good.vibes.diy/blog/most-agentic-open-source.html"/>
    <id>https://good.vibes.diy/blog/most-agentic-open-source.html</id>
    <updated>2026-07-02T12:00:00.000Z</updated>
    <published>2026-07-02T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Agents here don&apos;t just write code — they audit onboarding, file issues, open PRs, absorb review, and merge on green. Every artifact of that workflow is public in one repo, which makes it an unusually good place to learn agentic engineering by doing.</summary>
  </entry>
  <entry>
    <title>270 PRs in 17 days — the speed was the safety</title>
    <link href="https://good.vibes.diy/blog/270-prs-in-17-days.html"/>
    <id>https://good.vibes.diy/blog/270-prs-in-17-days.html</id>
    <updated>2026-07-02T11:00:00.000Z</updated>
    <published>2026-07-02T11:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;t the volume — it&apos;s that velocity and safety turned out to be the same property.</summary>
  </entry>
  <entry>
    <title>Not a loop, on purpose</title>
    <link href="https://good.vibes.diy/blog/not-a-loop.html"/>
    <id>https://good.vibes.diy/blog/not-a-loop.html</id>
    <updated>2026-07-02T09:00:00.000Z</updated>
    <published>2026-07-02T09:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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&apos;s a strength, not a lag.</summary>
  </entry>
  <entry>
    <title>Every vibe just got a backend</title>
    <link href="https://good.vibes.diy/blog/backend-js-server-side-vibes.html"/>
    <id>https://good.vibes.diy/blog/backend-js-server-side-vibes.html</id>
    <updated>2026-07-02T00:00:00.000Z</updated>
    <published>2026-07-02T00:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>One new file — backend.js — runs on our servers for your app: answer webhooks at your own /_api URL, react to every saved document, and run work on a timer. Server writes go through the exact same access rules as user writes, so your permission model stays in one place.</summary>
  </entry>
  <entry>
    <title>From one CLAUDE.md to forty runbooks</title>
    <link href="https://good.vibes.diy/blog/one-claude-md-to-forty-runbooks.html"/>
    <id>https://good.vibes.diy/blog/one-claude-md-to-forty-runbooks.html</id>
    <updated>2026-07-01T09:00:00.000Z</updated>
    <published>2026-07-01T09:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>If tokens were free, we&apos;d precompute every chip</title>
    <link href="https://good.vibes.diy/blog/precompute-every-chip.html"/>
    <id>https://good.vibes.diy/blog/precompute-every-chip.html</id>
    <updated>2026-06-30T20:00:00.000Z</updated>
    <published>2026-06-30T20:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>A suggestion chip is a transform of the vibe you&apos;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&apos;t the cache; it&apos;s the deny-by-default gate that decides who is allowed to read it.</summary>
  </entry>
  <entry>
    <title>From the group chat to the front counter</title>
    <link href="https://good.vibes.diy/blog/group-chat-to-front-counter.html"/>
    <id>https://good.vibes.diy/blog/group-chat-to-front-counter.html</id>
    <updated>2026-06-30T12:00:00.000Z</updated>
    <published>2026-06-30T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We&apos;ve always said &apos;make apps with your friends.&apos; True — but it undersold the thing. The same tool that builds a trivia app for the group chat takes the order and the payment for the taco truck, and retires the spreadsheet a small shop has been fighting for years. Here&apos;s the repositioning, and why &apos;we build apps&apos; is the weakest thing we could say.</summary>
  </entry>
  <entry>
    <title>The edit button that was secretly a save loop</title>
    <link href="https://good.vibes.diy/blog/editing-moved-into-the-app.html"/>
    <id>https://good.vibes.diy/blog/editing-moved-into-the-app.html</id>
    <updated>2026-06-29T09:00:00.000Z</updated>
    <published>2026-06-29T09:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We made the code editor live inside the running app — no hop to a separate chat route. &apos;Make the Code tab editable&apos; sounded like a UI task. It was a distributed save loop in disguise, and the whole thing hinged on one decision: re-pin, don&apos;t navigate.</summary>
  </entry>
  <entry>
    <title>Why our agents don&apos;t get a laptop</title>
    <link href="https://good.vibes.diy/blog/agents-in-the-cloud.html"/>
    <id>https://good.vibes.diy/blog/agents-in-the-cloud.html</id>
    <updated>2026-06-28T12:00:00.000Z</updated>
    <published>2026-06-28T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>A capability that only works on a hand-configured laptop quietly pushes all the work back to the laptop. Here&apos;s why we made cloud containers the default home for agent QA — and three war stories from getting browser validation to run there.</summary>
  </entry>
  <entry>
    <title>Edit a stranger&apos;s app, and it&apos;s yours</title>
    <link href="https://good.vibes.diy/blog/the-vibe-owner-viewer-experience.html"/>
    <id>https://good.vibes.diy/blog/the-vibe-owner-viewer-experience.html</id>
    <updated>2026-06-28T11:00:00.000Z</updated>
    <published>2026-06-28T11:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>The /vibe page now meets you where you are: a non-owner edit forks the app to your handle in place, owners get a private draft they can publish in one tap, and small indicators always tell you whether you&apos;re the author, an admin, or a read-only guest.</summary>
  </entry>
  <entry>
    <title>We only needed one Durable Object</title>
    <link href="https://good.vibes.diy/blog/collapsing-durable-objects.html"/>
    <id>https://good.vibes.diy/blog/collapsing-durable-objects.html</id>
    <updated>2026-06-28T10:00:00.000Z</updated>
    <published>2026-06-28T10:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We had three Durable Object classes that were really one handler surface opened against three shard keys. Here&apos;s how we collapsed them into a single class — and which &apos;separate-class&apos; argument fell apart the moment we pushed on it.</summary>
  </entry>
  <entry>
    <title>We deleted our auth dependency. Nothing changed.</title>
    <link href="https://good.vibes.diy/blog/defireproofing-auth.html"/>
    <id>https://good.vibes.diy/blog/defireproofing-auth.html</id>
    <updated>2026-06-28T09:00:00.000Z</updated>
    <published>2026-06-28T09:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>We deleted the preview pane</title>
    <link href="https://good.vibes.diy/blog/in-place-generation.html"/>
    <id>https://good.vibes.diy/blog/in-place-generation.html</id>
    <updated>2026-06-28T08:00:00.000Z</updated>
    <published>2026-06-28T08:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>We almost paid for faster CI</title>
    <link href="https://good.vibes.diy/blog/shard-the-runners.html"/>
    <id>https://good.vibes.diy/blog/shard-the-runners.html</id>
    <updated>2026-06-28T07:00:00.000Z</updated>
    <published>2026-06-28T07:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We almost bought a bigger CI machine. Instead we fanned the test suite across free standard runners — and put the failed-test names where triage actually looks.</summary>
  </entry>
  <entry>
    <title>Save a tree, skip the tests: leaner CI for docs-only PRs</title>
    <link href="https://good.vibes.diy/blog/save-a-tree-skip-the-tests.html"/>
    <id>https://good.vibes.diy/blog/save-a-tree-skip-the-tests.html</id>
    <updated>2026-06-28T06:30:00.000Z</updated>
    <published>2026-06-28T06:30:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>A README typo doesn&apos;t need a Playwright suite and a Postgres cluster. Teaching docs-only PRs to skip the heavy CI work — without falling into the &apos;required check stuck pending&apos; trap.</summary>
  </entry>
  <entry>
    <title>The NUL byte that broke every write (+7 more)</title>
    <link href="https://good.vibes.diy/blog/small-fixes-real-lessons.html"/>
    <id>https://good.vibes.diy/blog/small-fixes-real-lessons.html</id>
    <updated>2026-06-27T15:00:00.000Z</updated>
    <published>2026-06-27T15:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>Teaching an AI you&apos;re not &apos;the owner&apos;</title>
    <link href="https://good.vibes.diy/blog/teaching-codegen-defaults.html"/>
    <id>https://good.vibes.diy/blog/teaching-codegen-defaults.html</id>
    <updated>2026-06-27T09:00:00.000Z</updated>
    <published>2026-06-27T09:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Generated apps used to default to owner-gated permissions — broken for everyone but the creator. Here&apos;s how we flipped the default to author-owned, steered the model toward multiplayer without ever saying &apos;don&apos;t,&apos; and built a metric so the prompt could iterate itself.</summary>
  </entry>
  <entry>
    <title>The vibe that locked out its owner</title>
    <link href="https://good.vibes.diy/blog/retiring-isowner.html"/>
    <id>https://good.vibes.diy/blog/retiring-isowner.html</id>
    <updated>2026-06-23T12:00:00.000Z</updated>
    <published>2026-06-23T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>A vibe locked its own owner out of saving. The fix wasn&apos;t a better isOwner check — it was deleting isOwner and treating &apos;owner&apos; as a seeded, revocable role instead of an ambient super-user.</summary>
  </entry>
  <entry>
    <title>How we batch-upgrade apps with screenshots</title>
    <link href="https://good.vibes.diy/blog/upgrading-apps-with-screenshots.html"/>
    <id>https://good.vibes.diy/blog/upgrading-apps-with-screenshots.html</id>
    <updated>2026-06-09T12:00:00.000Z</updated>
    <published>2026-06-09T12:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>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.</summary>
  </entry>
  <entry>
    <title>How we eval the generator</title>
    <link href="https://good.vibes.diy/blog/how-we-eval-the-generator.html"/>
    <id>https://good.vibes.diy/blog/how-we-eval-the-generator.html</id>
    <updated>2026-06-09T11:00:00.000Z</updated>
    <published>2026-06-09T11:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>Every edit to the system prompt changes every app anyone generates. Here&apos;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.</summary>
  </entry>
  <entry>
    <title>Can one English prompt rebuild our festival app?</title>
    <link href="https://good.vibes.diy/blog/can-a-prompt-rebuild-the-pickathon-app.html"/>
    <id>https://good.vibes.diy/blog/can-a-prompt-rebuild-the-pickathon-app.html</id>
    <updated>2026-06-09T10:00:00.000Z</updated>
    <published>2026-06-09T10:00:00.000Z</published>
    <author><name>Vibes DIY</name></author>
    <summary>We tried to recreate Pickathon&apos;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.</summary>
  </entry>
</feed>
