Pyrra is my solo web studio. I built a pipeline that finds local businesses, screens their websites, and drafts outreach. I ran it for three months. Then I audited my own campaign and rebuilt the system around what the audit found. The rebuild is the more interesting engineering, and the mistakes behind it are part of the record.
System as first built
- Prospecting. Text Search on the Google Places API (New) covered 63 business types across nine Denver-area cities and stored 4,961 listings in SQLite. Only 916 of them were contractors.
- Screening. Heuristic checks recorded HTTPS, a mobile viewport tag, CMS signatures, and whether the page loaded. Each score was saved together with its reasons.
- Contact discovery. The pipeline pulled email addresses from each business’s own site, then checked mail records and filtered out platform addresses.
- Drafting. Gemini 2.5 Pro wrote the emails. An optional interactive review step let me edit, retry, or skip a draft.
- Sending. Delivery went through Gmail SMTP with warm-up caps, a daily ceiling, and randomized spacing.
What the audit found
In October 2026 I traced the campaign through the send database, the logs, and git history. The audit found five problems:
- Most sends were not reviewed. Of 407 logged sends, 358 ran in the unattended mode with no approval of each message.
- Drafts repeated claims nobody had checked. The prompts were built from canned observations keyed to heuristic signals. Many emails said a site was slow or had been “checked on my phone” when no speed test or device check had been run.
- The email footer was incomplete. It had no postal address and no notice identifying the email as a solicitation.
- Opt-outs were tracked late. They were only reconciled months afterward. The send records show that each of the two people who opted out received a single email before their request, and nothing after it.
- Google Places data was stored and reused. The pipeline saved Places results (business names, addresses, phone numbers, ratings) in a lead database and carried them into exports and prompts. Storing that content is itself the problem: the Google Maps Platform terms allow long-term storage of place IDs only. Prospecting through Places is stopped.
Outreach has been paused since June 2026.
The rebuild
The rebuild is implemented and tested, but it has not been used for a campaign. Outreach is still paused, and no prospect has received an email from the rebuilt system.
- Mandatory review. Every send goes through interactive review. The unattended mode and the unreviewed follow-up command are gone.
- Evidence-gated claims. Approval is refused in code when a draft claims a speed test, a device check, ranking or lost-business harm, past clients, or a prior conversation that the human-reviewed findings don’t support.
- Required footer. Both senders add the sender’s identity, a solicitation notice, a postal address, and an opt-out to both the plain-text and HTML parts. They refuse to send if no address is configured.
- Fail-closed send ledger. Every send is reserved atomically before SMTP. A shared suppression list covers both send tools. Readiness gates block all sending until sender authentication and historical reconciliation are confirmed. An uncertain delivery is never retried blindly.
- Mailbox reconciliation. IMAP reconciliation found 30 bounces, 2 human replies, and 2 opt-outs.
- Pre-commit guard. Prospect data had reached a private repository’s history. I rewrote the branch history to remove it. GitHub still keeps copies inside the repository’s pull-request references, and removing those needs a request to GitHub Support. A pre-commit guard now blocks data files and contact details from being committed.
- Tests. The safeguards are covered by 64 offline tests.
Studio and interface
The public Astro/Tailwind site presents the offer. Visitors can explore concept builds at desktop, tablet, and mobile sizes using computed scale transforms. Those builds are studio concepts, not client outcomes. The site is hosted on Vercel behind Cloudflare.
Result and limits
- Sends. 432 initial emails were sent between March 16 and June 16, 2026. Of those, 30 bounced, so at most 402 were delivered. Inbox placement is unknown.
- Replies. Two human replies came in. One became a scoped proposal that did not proceed.
- No proven effect. No conversion, revenue, or reply-rate claim is made. The screening score is a heuristic: when the unsent prospects were re-checked, no issue was established on most of them.
