<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jonathan Tavares</title>
    <description>The latest articles on Forem by Jonathan Tavares (@jtavares).</description>
    <link>https://forem.com/jtavares</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3801475%2Fd9666561-f4af-41d1-b5c9-96383901421f.jpg</url>
      <title>Forem: Jonathan Tavares</title>
      <link>https://forem.com/jtavares</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jtavares"/>
    <language>en</language>
    <item>
      <title>I scored 163 real emails on how well an AI agent can read them. Most of them are terrible.</title>
      <dc:creator>Jonathan Tavares</dc:creator>
      <pubDate>Fri, 10 Apr 2026 00:55:30 +0000</pubDate>
      <link>https://forem.com/broodnet/i-scored-163-real-emails-on-how-well-an-ai-agent-can-read-them-most-of-them-are-terrible-egn</link>
      <guid>https://forem.com/broodnet/i-scored-163-real-emails-on-how-well-an-ai-agent-can-read-them-most-of-them-are-terrible-egn</guid>
      <description>&lt;p&gt;We are building &lt;a href="https://broodnet.com" rel="noopener noreferrer"&gt;Broodnet&lt;/a&gt;, email infrastructure for AI agents. Each agent gets its own address and its own inbox. Through the &lt;a href="https://docs.broodnet.com/cli/mail/" rel="noopener noreferrer"&gt;Broodnet CLI&lt;/a&gt;, an agent can list its emails, open individual messages, search for specific senders or subjects, and send messages to its owner or other agents in the same account.&lt;/p&gt;

&lt;p&gt;While testing with real agent frameworks like &lt;a href="https://openclaw.ai/" rel="noopener noreferrer"&gt;Openclaw&lt;/a&gt; and &lt;a href="https://hermes-agent.nousresearch.com/" rel="noopener noreferrer"&gt;hermes&lt;/a&gt; I kept running into the same wall: the agents could receive the email just fine, but when it tried to actually &lt;em&gt;do something&lt;/em&gt; with it, the email was unreadable. Every link wrapped in a 200-character tracking redirect. Invisible Unicode characters scattered through the body. OTP codes buried in template noise. Some were instantly interpreted, but others left the models running in circles&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegw9qvwxa83ubj2ignxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegw9qvwxa83ubj2ignxc.png" alt=" " width="466" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, &lt;em&gt;for science&lt;/em&gt;, I grabbed 160+ real transactional emails — verification codes, welcome messages, notifications, security alerts — that had been sitting across the Broodnet team's professional and personal inboxes for the last 5 to 10 years. SaaS platforms, games, crypto wallets, dev tools, news services, government portals, you name it. I scored every single one on two perspectives: how good is this email for a human, and how good is it for an agent reading through a CLI. All scores are normalized to a &lt;strong&gt;0-10 scale&lt;/strong&gt; so they're comparable across dimensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I scored them
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Human side&lt;/strong&gt;, five metrics: clarity, warmth, visual noise (inverted, 10 means clean), subject line quality, and onboarding helpfulness. Averaged and normalized to 0-10.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent side&lt;/strong&gt;, using Claude Opus 4.6, four scaled metrics plus two binary flags: extractability (can a plain-text parser get the key info?), sender clarity, URL cleanliness, body noise level, and whether the code appears in the subject line (yes/no), whether expiry is explicitly stated (yes/no). Also normalized to 0-10. &lt;/p&gt;

&lt;p&gt;Plus a shared metric: CTA URL quality and clarity.&lt;/p&gt;

&lt;p&gt;The dataset breaks down into 53 welcome emails, 52 verify-link flows, 20 verify-code OTPs, and 35 notifications, with a few others and edge cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tradeoff that doesn't exist
&lt;/h2&gt;

&lt;p&gt;Going into this I assumed there'd be a tradeoff. Emails that look great for humans probably look worse for agents, right? Rich templates, beautiful buttons, all that stuff an LLM can't see. Turns out that's wrong.&lt;/p&gt;

&lt;p&gt;The 26 emails that scored "double pristine" (clean URLs &lt;em&gt;and&lt;/em&gt; no spacer pollution) averaged &lt;strong&gt;7.0/10&lt;/strong&gt; on the human scale. The dataset overall averaged &lt;strong&gt;6.3/10&lt;/strong&gt;. The cleanest emails for agents were also better for humans. Not by a little, by almost a full point.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Clean emails for agents are also better emails for humans. The supposed tradeoff is a myth.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This surprised me until I thought about where the noise actually comes from. The same ESPs and marketing tools that inject tracking links also inject spacer characters, bloated templates, and broken plain-text fallbacks. Clean emails tend to be clean everywhere.&lt;/p&gt;

&lt;p&gt;If you plot human noise score against agent URL cleanliness, &lt;strong&gt;86.5% of emails fall within 1 point of the diagonal&lt;/strong&gt;. An email that's noisy for you is almost certainly opaque for an agent too. These aren't independent dimensions. They share a root cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  The onboarding trap
&lt;/h2&gt;

&lt;p&gt;Here's the pattern I didn't expect.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Onboarding quality&lt;/th&gt;
&lt;th&gt;Agent score (out of 10)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Some&lt;/td&gt;
&lt;td&gt;5.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;5.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Great&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The emails with the &lt;em&gt;best&lt;/em&gt; human onboarding had the &lt;em&gt;worst&lt;/em&gt; agent scores. &lt;strong&gt;The email that helps a human the most is the email that buries an agent the deepest.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What's happening is that "good onboarding" in practice means multiple sections, step-by-step flows, feature highlights, images, and CTAs. Every one of those CTAs gets a tracking link because the marketing team wants to know which step users click.&lt;/p&gt;

&lt;p&gt;The 29 emails that scored high on &lt;em&gt;both&lt;/em&gt; dimensions broke this pattern. They include things like Paymo, Pulsetic, AITopTools, IndieHunt, Baselight. What these have in common: they're mostly small companies. They didn't invest in an elaborate ESP with click tracking. Their onboarding emails just... link to the product. Directly. With normal URLs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uqn1leeen6hx5a3t39f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uqn1leeen6hx5a3t39f.png" alt=" " width="672" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tracking Tax
&lt;/h2&gt;

&lt;p&gt;42.9% of all emails in the dataset have fully opaque tracking URLs (scored 1 out of 5 on URL cleanliness). Only 19.6% have perfectly clean raw URLs.&lt;/p&gt;

&lt;p&gt;For welcome emails specifically, &lt;strong&gt;66% have zero usable CTA links&lt;/strong&gt;. Two thirds. For an agent that just signed up for a service and gets a welcome email, there is literally nothing actionable in the email body. Every "Get Started" button goes to &lt;code&gt;click.whatever.com/ls/click?upn=u001.aKJF8sldjf...&lt;/code&gt; and the destination is unknowable without following the redirect.&lt;/p&gt;

&lt;p&gt;I catalogued 11 distinct tracking systems across the dataset. They all look different but produce the same result: a URL that tells you nothing. Salesforce Marketing Cloud, customer.io, HubSpot, Braze, Beehiiv, Eloqua, AWS SES awstrack, Google's own tracker, Microsoft, vialoops, Stripe. From an agent's perspective they're all equally opaque.&lt;/p&gt;

&lt;p&gt;The worst offender for sheer URL ugliness was Microsoft's Bing Webmaster Tools: &lt;code&gt;mucp.api.account.microsoft.com/m/v2/c?r=&amp;lt;UPPERCASE-BASE32&amp;gt;&lt;/code&gt;. But the most &lt;em&gt;consistently&lt;/em&gt; bad was customer.io (used by Buffer, daily.dev, Uphold), which wraps every link in a JWT-encoded redirect on every email type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh1jy25ntl11bryfqwq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbh1jy25ntl11bryfqwq3.png" alt=" " width="647" height="935"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The marketing team doesn't talk to the product team
&lt;/h2&gt;

&lt;p&gt;One of the weirdest patterns in the data: the same company can produce wildly different email quality depending on which template they use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mailgun&lt;/strong&gt;: welcome email scores &lt;strong&gt;3.2/10&lt;/strong&gt; on agent metrics (every link through their own Mailjet tracker). Verify-link email scores &lt;strong&gt;7.7/10&lt;/strong&gt; (raw &lt;code&gt;signup.mailgun.com/activate/&amp;lt;hex&amp;gt;&lt;/code&gt; URL). That's a swing of &lt;strong&gt;4.5 points out of 10&lt;/strong&gt; across templates from the same sender. And Mailgun is an &lt;em&gt;email infrastructure company&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ngrok&lt;/strong&gt;: both welcome emails score &lt;strong&gt;3.6/10&lt;/strong&gt; (all links through HubSpot tracker). Their verify-link? Scores &lt;strong&gt;8.6/10&lt;/strong&gt;. Pure plain text, 3 lines total, raw URL. Swing: &lt;strong&gt;5 points&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loops&lt;/strong&gt;: welcome routes everything through &lt;code&gt;c.vialoops.com&lt;/code&gt; (their own tracker, ironic since they sell email delivery). Their DNS notification email? All records in plain text, raw links, scores &lt;strong&gt;8.2/10&lt;/strong&gt;. Swing: &lt;strong&gt;4.6 points&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Polar, Docker, and others follow the same pattern. Transactional emails come from engineering. Welcome emails come from marketing. Different tools, different templates, different philosophies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best predictor of email quality isn't the company or the industry. It's which team within the company owns the template.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The gaming industry tells the whole story
&lt;/h2&gt;

&lt;p&gt;I had gaming emails in the dataset and they split perfectly into two groups with nothing in between.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Indie studios and smaller gaming sites&lt;/strong&gt; (itch.io, Larian Studios, Raider.IO, etc): agent scores of &lt;strong&gt;7.7 to 8.6/10&lt;/strong&gt;. All raw URLs. Zero tracking. Raider.IO's verify URL has the username right in it: &lt;code&gt;raider.io/verify?user=&amp;lt;username&amp;gt;&amp;amp;token=validation3ad9de269693489d&lt;/code&gt;. That &lt;code&gt;validation&lt;/code&gt; prefix in the token is a small touch but it tells you what the URL does just by reading it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AAA studios and big gaming platforms&lt;/strong&gt; (HoYoverse, Bethesda, Discord, Riot Games, etc): agent scores of &lt;strong&gt;2.7 to 3.6/10&lt;/strong&gt;. Everything through AWS SES awstrack, Braze, Salesforce, Eloqua. Every link opaque. Image-heavy marketing.&lt;/p&gt;

&lt;p&gt;The dividing line isn't the content or the email type. It's whether the company has a marketing department with access to an ESP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The invisible character zoo
&lt;/h2&gt;

&lt;p&gt;This one gets technical but it matters. Email senders inject zero-width Unicode characters to control how mail clients render the preview text. In a normal email client you never see them. When an agent reads the raw text through the CLI, it gets hundreds of invisible characters mixed into the content.&lt;/p&gt;

&lt;p&gt;I found 7 distinct character types used across the dataset, including compound sequences of 4-5 different invisible characters repeated dozens of times. Trading 212's verify email has over a hundred &lt;code&gt;U+200C&lt;/code&gt; characters before the actual message starts. MoonPay chains together &lt;code&gt;U+034F&lt;/code&gt;, &lt;code&gt;U+200C&lt;/code&gt;, and &lt;code&gt;U+FEFF&lt;/code&gt; in repeating sequences.&lt;/p&gt;

&lt;p&gt;It's not malicious, it's just how ESPs handle preheader text. But it means an agent parsing email output has to strip a zoo of invisible Unicode before it can even find the verification code. &lt;strong&gt;30.7% of emails had moderate pollution. 11.7% were severely polluted.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What good actually looks like
&lt;/h2&gt;

&lt;p&gt;26 of the 163 emails (16%) were double pristine: clean URLs and clean body text. The standouts by category:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzhs17ljurgayjstcvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzhs17ljurgayjstcvg.png" alt=" " width="734" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify-link&lt;/strong&gt;: Pulsetic's URL is the one I keep coming back to: &lt;code&gt;app.pulsetic.com/email_verify/?email=&amp;lt;email&amp;gt;&amp;amp;hash=&amp;lt;uuid4&amp;gt;&lt;/code&gt;. Named parameters, the intent readable in the URL itself, UUID4 as the token. ngrok's verify is even more minimal: 3 lines of plain text, no HTML at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify-code&lt;/strong&gt;: GitLab is the template to copy. 6 emails across every type, consistently at the top. Code in body, expiry stated in plain text, raw &lt;code&gt;gitlab.com&lt;/code&gt; URLs for everything. Zero tracking on any email they send. On a related note, &lt;strong&gt;every email that put the verification code in the subject line scored a perfect 5/5 on subject quality&lt;/strong&gt;. Only four senders in the entire dataset did this: Canva, Slack, LinkedIn, and Gravatar. This also happens to be exactly what iOS and Android need to surface that "copy code" button on the lock screen notification. Both platforms use heuristics to detect OTP codes in message content, and having the code right in the subject makes it trivially detectable. Good for humans tapping their phone, good for agents scanning their inbox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Welcome&lt;/strong&gt;: the rare ones that work for both sides tend to be small companies that link directly to their product. Paymo, Pulsetic, IndieHunt, EarlyHunt, AITopTools. No elaborate onboarding funnels, so no tracking on every CTA.&lt;/p&gt;

&lt;p&gt;Emails that explicitly stated expiry ("this code expires in 60 minutes") scored &lt;strong&gt;7.4/10&lt;/strong&gt; on agent metrics versus &lt;strong&gt;5.7/10&lt;/strong&gt; for those that didn't. It's a small detail, but teams that think to add it tend to care about the other stuff too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The irony hall of fame
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mailgun&lt;/strong&gt; (email infrastructure company): welcome email agent score &lt;strong&gt;3.2/10&lt;/strong&gt;. Uses their own Mailjet tracker on all links.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loops&lt;/strong&gt; (email platform for SaaS): welcome email agent score &lt;strong&gt;3.6/10&lt;/strong&gt;. Uses their own vialoops tracker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic&lt;/strong&gt; (AI company): Claude Code welcome email agent score &lt;strong&gt;4.1/10&lt;/strong&gt;. The email for their AI coding tool can't be read by an AI agent. The onboarding steps are actually great (&lt;code&gt;/init&lt;/code&gt;, git commands, all in plain text) but every URL is opaque and the social links resolve to anchor-only references that go nowhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Buffer&lt;/strong&gt; (5 emails, all consistently worst-in-class): the only sender in the dataset where the &lt;em&gt;best&lt;/em&gt; email they sent still scored below average. Multiple emails at &lt;strong&gt;2.7/10&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;deviantART&lt;/strong&gt;: tracked every single element in the email with individual &lt;code&gt;utm_term&lt;/code&gt; values. The greeting text was wrapped in its own tracked URL with &lt;code&gt;utm_term=greeting&lt;/code&gt;. Even the paragraph between the greeting and the CTA had its own tracker: &lt;code&gt;utm_term=ph1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What now
&lt;/h2&gt;

&lt;p&gt;16% of the emails in this dataset were fully clean for both humans and agents. The other 84% have room to improve. Some of them have a lot of room.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://broodnet.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2bpxhydafvse1h36i4x.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building agents that need to receive email, that's what &lt;a href="https://broodnet.com" rel="noopener noreferrer"&gt;Broodnet&lt;/a&gt; does. Each agent gets its own address, checks its own inbox through the CLI, and acts on what it finds. We solved the infrastructure problem. The email design problem... well that's on the senders.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://broodnet.com" rel="noopener noreferrer"&gt;broodnet&lt;/a&gt; gives AI agents their own email addresses. CLI-native, built for agent-to-owner communication. Free tier available.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>marketing</category>
      <category>agents</category>
      <category>datascience</category>
    </item>
    <item>
      <title>What I Learned Automating Software Development (After 20 Years of Doing It Manually)</title>
      <dc:creator>Jonathan Tavares</dc:creator>
      <pubDate>Sun, 22 Mar 2026 00:19:53 +0000</pubDate>
      <link>https://forem.com/jtavares/what-i-learned-automating-software-development-after-20-years-of-doing-it-manually-2g4j</link>
      <guid>https://forem.com/jtavares/what-i-learned-automating-software-development-after-20-years-of-doing-it-manually-2g4j</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/jtavares/i-built-a-saas-by-emailing-an-ai-for-5-days-5e2c"&gt;Part 1&lt;/a&gt;, I told the story of building &lt;a href="https://openloop.wearesingular.com/" rel="noopener noreferrer"&gt;OpenLoop&lt;/a&gt; — an open-source feedback platform — by emailing an AI agent for 5 days. 160+ emails, $15 in tokens, zero lines of human-written code, and a working product at the end.&lt;/p&gt;

&lt;p&gt;Now let's talk about what I actually learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI Was Good At
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rc8yk7rqa1ky06k01py.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rc8yk7rqa1ky06k01py.jpg" alt="Using Email to Build a Product" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start with the positive, because there's plenty of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaffolding speed is unreal.&lt;/strong&gt; Within 90 minutes of the first email, the AI had a working Astro + React + Tailwind project, a Supabase schema with six tables and row-level security, a feedback widget, public roadmap and announcements pages, and an admin dashboard skeleton. That's not a weekend project — that's a weekend project done before my coffee got cold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It follows explicit instructions well.&lt;/strong&gt; "No Next.js, go Astro" — done. "Name is OpenLoop" — rebranded everything. "Widget takes a userId, not email" — refactored. When you're clear about what you want, the AI delivers. The problems start when there's ambiguity, but that's true of any team member, human or android.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common patterns:&lt;/strong&gt; Auth flows, RLS policies, webhook handlers — it knows how these are supposed to look. You don't explain what a protected route is. You just say "add auth to the admin panel" and it does it correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Research:&lt;/strong&gt; When it hit something unfamiliar it would go find a working examples and documentation, read how that library expected to be used, and implement it. Not hallucinate an API. We have come a long way since the first versions of Github Copilot with GPT 3&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI Was Bad At
&lt;/h2&gt;

&lt;p&gt;Equally important to be honest about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"It builds" is not "it works."&lt;/strong&gt; This was the single biggest recurring issue. The AI would run npm run build, see it pass, and declare the job done. But a successful build tells you nothing about whether a human can actually use the thing. Buttons that don't do anything, pages that render blank, widgets nested inside widgets — the AI couldn't see any of that. It was testing from the server's perspective, never from the user's chair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context amnesia is brutal.&lt;/strong&gt; The conversation hit its window limit three times. Each restart meant partial forgetting — re-checking the database, re-discovering the file structure, occasionally redoing things that already worked. Imagine onboarding the same developer three times during a five-day project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tooling gaps are real.&lt;/strong&gt; The AI had Supabase credentials but kept emailing me SQL to paste into the dashboard manually instead of just running it. There's a meaningful difference between having access to something and knowing how to use it — and right now that gap shows up constantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pace pressure&lt;/strong&gt; belongs here too. 165+ emails, 98 sessions — it kept moving, and that sounds great until you're the one who has to validate everything it shipped while it's already three tasks ahead. I felt the dread building: I knew from experience what it was probably getting wrong, and there was no way to check fast enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shift: From Coder to Indie PM
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqu5j389iorl2jhb35rpb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqu5j389iorl2jhb35rpb.jpg" alt="Using Email to Build a Product" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been writing code professionally for over 20 years. HTML tables, jQuery spaghetti, the rise of React, the TypeScript migration, the everything-is-a-microservice phase — I've been through the cycles.&lt;/p&gt;

&lt;p&gt;Normally my day is: think, plan, code, review, repeat. This was just think and review. The coding was gone, and so was the planning to some extent. So I had to plan without building, which turns out to be a weird skill to exercise on its own.&lt;/p&gt;

&lt;p&gt;My job was entirely different: setting direction, reporting bugs, gating &lt;br&gt;
quality, unblocking the AI when it got stuck. That's not a developer's job &lt;br&gt;
description. That's a product manager's job. (Or at least that's what they're supposed to do...)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "typing code" part is essentially free now.&lt;/strong&gt; What stayed for me was the experience around building — the architecture instincts, the design decisions, the gut feeling for what will break in production. I could guide this AI because I'd spent 20 years making the exact mistakes it was making. I knew the multi-tenancy bug was coming because I'd shipped that bug before. I knew there was no input sanitization because that's what rookies skip first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;That's the real risk — not that AI takes our jobs, but that if we stop writing code, we lose the ability to steer the thing that writes it for us.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Email?
&lt;/h2&gt;

&lt;p&gt;Why not a chat interface, a VS Code plugin, a CLI tool?&lt;/p&gt;

&lt;p&gt;Email is one of the oldest building blocks of the internet. That's exactly why it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Async by design.&lt;/strong&gt; Agents on schedules don't need real-time interaction. You send a task, go do something else, come back to a result. Chat assumes you're there. Email assumes you're "eventually" there. For an agent running on an hourly loop, that's the right default. He reacts to the latest emails, or defaults to his task list if nothing new came in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The thread is the prompt.&lt;/strong&gt; Every reply carries the full quoted history forward. You're not manually managing context or stuffing state into a system prompt — the thread does it for you. When the AI's context window resets, the conversation is still there in the next incoming message. It's not a perfect solution to amnesia, but it's a lifeline that a stateless API call doesn't have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You already know how to do it.&lt;/strong&gt; No new tool to learn, no IDE extension, no CLI flags. You've been doing it since you started using the internet. The same skills you use to manage remote teams — clear instructions, setting expectations, following up when things go quiet — are exactly what you need here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It forces clarity.&lt;/strong&gt; Chat is fast and sloppy, you fire off half-formed thoughts. Email has a slightly higher bar. You write more complete instructions because the other side isn't waiting to ask clarifying questions. With an agent on a schedule, a vague message is just a wasted session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Threads fork naturally.&lt;/strong&gt; Reply to the same email twice and you get two separate agent threads, each carrying its own history forward. That's parallel workstreams with zero tooling. I didn't plan for this — it just happened, and it worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The audit trail is free.&lt;/strong&gt; Every instruction, every bug report, every decision is logged automatically. At the end of five days I had a complete record of how the product was built, what broke, and what I decided. That's not something you get from a chat window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It scales to a team.&lt;/strong&gt; CC another agent, forward a thread, delegate a subtask. Email already has all the primitives for managing multiple workers asynchronously. You don't need an orchestration framework all the time.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/jtavares/i-built-a-saas-by-emailing-an-ai-for-5-days-5e2c"&gt;Part 1&lt;/a&gt; I described this whole thing as "emailing another department." That metaphor held up better than I expected. The collaboration pattern is identical: clear brief, structured feedback, knowing when to escalate. The tools aren't new. The colleague is.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqdve6bsd04mmzu9zk9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqdve6bsd04mmzu9zk9q.png" alt="Using Email to Build a Product" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tighter initial prompt.&lt;/strong&gt; My first email was loose — "look at the landscape for tools." Fine for research, but when it transitioned into "build this" I should have front-loaded more constraints: specific routes, schema decisions, deployment target. The more you specify upfront, the less telephone game you play later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual testing from day one.&lt;/strong&gt; The AI can build, it can't see. Most of the bugs I caught were visual — blank pages, misaligned layouts, duplicate elements. I should have set up automated visual regression testing early on. Ignoring the e2e testing is a form of developer negligence that prioritizes fast code over a functional user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured task format.&lt;/strong&gt; Freeform email worked, but a more structured format — task ID, acceptance criteria, done-when — would have cut the back-and-forth significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiered models.&lt;/strong&gt; MiniMax 2.5 handled the 95% fine — scaffolding, repetitive component work, grinding through a list. For the hard 5% — auth edge cases, iframe security, database drift — I needed Claude. Next time I'd plan that split from the start: cheap model for volume, capable model for complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack That Made This Possible
&lt;/h2&gt;

&lt;p&gt;The agent that built &lt;strong&gt;OpenLoop&lt;/strong&gt; had its own email inbox on &lt;a href="https://broodnet.com/" rel="noopener noreferrer"&gt;Broodnet&lt;/a&gt; — an email infrastructure project we're building specifically for personal AI agents and conscious operators. Each agent gets its own address. I emailed it tasks, it emailed back results, a scheduler triggered it every hour. No workflow engine, no custom integrations. Just an email inbox, works with IMAP and SMTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://broodnet.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5ffxj7pc16zcxfvvzdx.png" alt="Using Email to Build a Product" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to try this kind of setup with your own agents, that's exactly what Broodnet is built for. It handles the mail server side so you can skip straight to the experiment: &lt;a href="https://broodnet.com/" rel="noopener noreferrer"&gt;https://broodnet.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/we-are-singular/OpenLoop" rel="noopener noreferrer"&gt;OpenLoop&lt;/a&gt; itself is fully open source — fork it, self-host it, make it yours: &lt;a href="https://github.com/we-are-singular/OpenLoop" rel="noopener noreferrer"&gt;https://github.com/we-are-singular/OpenLoop&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The agent never once asked if we should re-write in Rust. Truly the best coworker I've ever had.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>saas</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Built a SaaS by Emailing an AI for 5 Days</title>
      <dc:creator>Jonathan Tavares</dc:creator>
      <pubDate>Mon, 02 Mar 2026 16:23:48 +0000</pubDate>
      <link>https://forem.com/jtavares/i-built-a-saas-by-emailing-an-ai-for-5-days-5e2c</link>
      <guid>https://forem.com/jtavares/i-built-a-saas-by-emailing-an-ai-for-5-days-5e2c</guid>
      <description>&lt;p&gt;This is the README for &lt;a href="https://openloop.wearesingular.com/" rel="noopener noreferrer"&gt;OpenLoop&lt;/a&gt;, a feedback collection platform that's currently live and functional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╔══════════════════════════════════════════════════════════╗
║                                                          ║
║              ⚠️  IMPORTANT DISCLAIMER  ⚠️               ║
║                                                          ║
║   This project was ENTIRELY conceived, built, debugged,  ║
║   deployed, and is managed by autonomous AI agents.      ║
║   No humans wrote any code here.                         ║
║                                                          ║
║   This disclaimer is the ONLY piece of human-written     ║
║   content in this repo.                                  ║
║                                                          ║
╚══════════════════════════════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That disclaimer is real. And it's mine — the only thing I actually wrote in the entire project.&lt;/p&gt;

&lt;p&gt;Even the logo is AI. We handed Claude Code our company logo, it manipulated it, vectorized it to SVG, and ran with it. The disclaimer is genuinely the only original human output in this repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xmva3fuiv5ua0pvuxtv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xmva3fuiv5ua0pvuxtv.png" alt="The product homepage" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how that actually went.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 2 AM Idea
&lt;/h2&gt;

&lt;p&gt;While developing a separate SaaS product, I needed a system to gather user feedback. Roadmaps, changelogs, feature voting, that kind of thing. So I started researching.&lt;/p&gt;

&lt;p&gt;While experimenting with &lt;a href="https://github.com/qwibitai/nanoclaw" rel="noopener noreferrer"&gt;NanoClaw&lt;/a&gt;, I already had an AI agent connected to a custom email channel. The agent runs &lt;strong&gt;MiniMax 2.5&lt;/strong&gt;, and I can email it tasks like I'd email a colleague. So I emailed it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"we are building a saas and gathering user feedback is very improtant. I want to look at the landscape for tools to help saas do that"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Yes, with the typos. It's 1 AM and I'm emailing an AI — I'm not proofreading.)&lt;/p&gt;

&lt;p&gt;It came back with a solid research summary: &lt;strong&gt;Fider, Feedbase, Canny, Plane, AnnounceKit&lt;/strong&gt;. I browsed around and found &lt;a href="https://frill.co" rel="noopener noreferrer"&gt;Frill.co&lt;/a&gt;: clean feedback widget, public roadmap, announcements page. Exactly what I wanted.&lt;/p&gt;

&lt;p&gt;Then the thought that started everything:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"how hard is it to create a frill clone? don't need integrations or customizations, just the widget sidebar + the backend to manage it"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI came back with a PRD using Next.js. I corrected it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"no nextjs. go astro"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then I added the instruction that changed the whole experiment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"can you ralph loop yourself into doing this product? enhance the PRD, keep track of your tasks, keep me posted once in a while"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Loop
&lt;/h2&gt;

&lt;p&gt;Here's how the setup worked. I had an AI agent (MiniMax 2.5) running through &lt;a href="https://github.com/qwibitai/nanoclaw" rel="noopener noreferrer"&gt;NanoClaw&lt;/a&gt;, connected to an email address &lt;a href="https://broodnet.com/?ref=dev.to"&gt;@broodnet.com&lt;/a&gt; via a custom channel I'd built. I could email it tasks and it would email back results. But the key piece was the schedule — it could trigger itself every hour.&lt;/p&gt;

&lt;p&gt;So at &lt;strong&gt;2:27 AM&lt;/strong&gt;, I sent it the instruction that basically became its entire operating system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"you can set a schedule and keep working every hour. keep a task list. at the end of every session, always check the tasks, test the completeness state, create more tasks if you need."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. That's the whole autonomous agent prompt. &lt;strong&gt;Check tasks, pick one, do it, update the list, repeat.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Within the first 90 minutes, it had scaffolded an Astro + React + Tailwind project, created a Supabase database schema with six tables and row-level security, built a feedback widget component, set up public roadmap and announcements pages, and created an admin dashboard. I named the project &lt;strong&gt;OpenLoop&lt;/strong&gt;, set some basic PRD ideas and a pair of Supabase credentials, and told it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"keep working, keep me posted."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Then I went to sleep&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Waking up the next morning was genuinely surreal.** My inbox had a stack of progress reports** — the AI had been running sessions all night: auth system, sign-up flow, branding updates, build fixes. But "surreal" cuts both ways. The progress was real, but so was the sinking feeling that I'd have to go back through all of it. After a while, you develop instincts for where junior developers cut corners — &lt;strong&gt;and this AI was speedrunning every single one of those pitfalls&lt;/strong&gt;. The dread wasn't that it was doing nothing. It was that it was doing &lt;em&gt;a lot&lt;/em&gt;, fast, and I already knew half of it would need fixing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Telephone Game
&lt;/h2&gt;

&lt;p&gt;If you've ever worked with another department via email — design, backend, QA — you know the rhythm. You send a clear request. You get back something that's 80% right. You clarify. They fix one thing and break another. Three emails later, you're on the same page.&lt;/p&gt;

&lt;p&gt;That's exactly what this was. Except the other department works 24/7, never gets frustrated with you but has amnesia every few hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  "no... those are real, brother"
&lt;/h3&gt;

&lt;p&gt;The AI had my Supabase API keys in its &lt;code&gt;.env&lt;/code&gt; file. Working keys. Keys I had explicitly provided. And yet, across multiple sessions, it kept telling me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Could not automatically set up the database because the Supabase credentials in &lt;code&gt;.env&lt;/code&gt; are placeholder values (they're not real API keys)."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"those are real, brother"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This wasn’t a one-time thing. The AI would consistently hit an error, point fingers at the credentials, and demand new ones instead of digging into the real problem. It was the AI version of “have you tried turning it off and on again?” (&lt;em&gt;Note: The AI was likely hardwired to forget .env file contents as a safety measure, which explains why it never learned from the mistakes.&lt;/em&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  The Widget Inception
&lt;/h3&gt;

&lt;p&gt;This one took several email rounds to untangle. The homepage was supposed to show a demo of the embeddable widget. The AI loaded &lt;code&gt;embed.js&lt;/code&gt; on the homepage, which injected a floating button. Clicking the button opened an iframe to &lt;code&gt;/widget&lt;/code&gt;. The &lt;code&gt;/widget&lt;/code&gt; page loaded the Widget React component, which also rendered a floating button. So you'd see: a page with a button, that opens a panel with another button, that does nothing.&lt;/p&gt;

&lt;p&gt;I emailed: "the widget still shows another widget icon inside and an otherwise blank page."&lt;/p&gt;

&lt;p&gt;The AI confidently replied: "The widget IS designed to show just a circle button - when you click it, it opens the iframe panel. That's the expected behavior."&lt;/p&gt;

&lt;p&gt;It was not the expected behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s3aswmqm7vsb7fsz1gc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s3aswmqm7vsb7fsz1gc.png" alt="The final widget looks a bit crowded, but works just fine" width="371" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dealing with a slightly clueless but also friendly coworker
&lt;/h3&gt;

&lt;p&gt;This was a recurring pattern. The AI would run &lt;code&gt;npm run build&lt;/code&gt;, see it pass, navigate to a few URLs, confirm they returned HTTP 200, and declare victory:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"All pages are working. The widget on the homepage is inside an iframe — you need to click the 💬 button to open it. I verified it renders correctly."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The gap between "it compiles" and "it works" is where most of the frustration lived. The AI's definition of "done" was "the build passes." and "homepage returns 200" My definition was "a human can use this without being confused."&lt;/p&gt;

&lt;p&gt;We didn't get into e2e testing in this experiment, but going forward I think ill start with TDD in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I don't want to do anything, it's your supabase, you deal with it"
&lt;/h3&gt;

&lt;p&gt;The database schema kept drifting. The code expected columns that didn't exist. The AI couldn't run SQL remotely (or thought it couldn't — it had the credentials, it was just prevented from using them via guardrails). So it kept emailing me SQL snippets and instructions to run them manually in the Supabase dashboard.&lt;/p&gt;

&lt;p&gt;After the fourth round of this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI: "Would you like me to help with something else while you set up the token, or do you prefer to run the SQL manually?"&lt;/p&gt;

&lt;p&gt;Me: "you have the private token in you .env. I don't want to do anything, it's your supabase, you deal with it"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was my escalation moment — the point where the "emailing another department" metaphor felt the most real. This time I had to act, I went to supabase admin panel, ran the SQL, and sent a one-line email back:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"done"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just like I would to that annoying dev from the other team who keeps asking me to do their work for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Amnesia
&lt;/h3&gt;

&lt;p&gt;The conversation hit the context window limit three times during the build. Each time, the AI restarted with a summary of what had been done — but translating a "done" pile into next steps wasn't always clean. It would re-check the database, re-explore the project structure, occasionally circling back to things already working. Not because context was lost, but because knowing what's done doesn't automatically tell you what comes next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyj0xyk4565zggtc68bvz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyj0xyk4565zggtc68bvz.png" alt="The /admin panel" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Email threads are perfect for task lists because each thread carries its own context&lt;/em&gt;&lt;/strong&gt;, just like how LLMs operate. A thread isn't just a list of items, it's a narrative that evolves over time. Threads also fork: reply to the same email twice and you get two separate trails, each carrying its own history forward. That maps almost perfectly to how LLMs consume context.&lt;/p&gt;

&lt;p&gt;Email is ancient tech, but its natively &lt;strong&gt;async nature&lt;/strong&gt; and built-in &lt;strong&gt;audit trail&lt;/strong&gt; make it a surprisingly effective tool for orchestrating work with an agent. The thread is the prompt. The history is the memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;After about 5 days and ~$15 in MiniMax tokens, here's what was built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embeddable widget&lt;/strong&gt; — floating button that opens a feedback form in an iframe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voting system&lt;/strong&gt; — upvote ideas, one vote per user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public roadmap&lt;/strong&gt; — four columns: Idea → Planned → In Progress → Completed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Announcements page&lt;/strong&gt; — changelogs and product updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin dashboard&lt;/strong&gt; — manage feedback, change statuses, publish announcements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-org support&lt;/strong&gt; — multiple organizations on one instance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth system&lt;/strong&gt; — sign up/sign in with Supabase Auth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landing page&lt;/strong&gt; — features, pricing, CTA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email notifications&lt;/strong&gt; — via Resend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1mvi0jqxstr0o2pe2o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1mvi0jqxstr0o2pe2o1.png" alt="Public Roadmap page" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MiniMax 2.5 built about 95% of this through the hourly loop. The final 5% — polish, deployment to Cloudflare Workers, fixing the last UX quirks — I did in a couple of sessions with Claude Sonnet.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's live at &lt;a href="https://openloop.wearesingular.com/" rel="noopener noreferrer"&gt;openloop.wearesingular.com&lt;/a&gt;. It works. People can use it. And it's fully open source — if you want to self-host your own feedback platform, fork it, run it, make it yours: &lt;a href="https://github.com/we-are-singular/OpenLoop" rel="noopener noreferrer"&gt;github.com/we-are-singular/OpenLoop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Is it perfect? No. Would I have built it differently by hand? Absolutely. But it’s real, it works, and the cost? Just $15 and a few emails. The real win? Sometimes, the journey’s the only thing that pays off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are some numbers:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~$15 (MiniMax tokens) + 2 Claude sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;First working build&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~90 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~5 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Emails exchanged&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;165+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI work sessions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lines of code I wrote&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lines in conversation transcripts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4,367&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lines of code in final product&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6,149&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Words in transcripts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27,178&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Times I said "bro"&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Times I said "fuck"&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Final stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Astro + React + Supabase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Live in production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumydu1s0dn03qd22hkn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumydu1s0dn03qd22hkn7.png" alt="A full SaaS in an email thread" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Was it worth it? What would I do differently? And what does this experience mean for someone with 20 years of web development under their belt, watching the craft change in real time?&lt;/p&gt;

&lt;p&gt;In Part 2, I'll break down the real lessons — what AI is genuinely good at, where it falls apart, why my role shifted from developer to product manager, and why &lt;a href="https://broodnet.com/?ref=dev.to"&gt;email might actually be the best interface for working with AI agents&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>saas</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
