<?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>DEV Community: UNO Leo</title>
    <description>The latest articles on DEV Community by UNO Leo (@leouno).</description>
    <link>https://dev.to/leouno</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4064468%2Ff150a01d-1fb2-475b-bf98-0c6c7bedefe5.png</url>
      <title>DEV Community: UNO Leo</title>
      <link>https://dev.to/leouno</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leouno"/>
    <language>en</language>
    <item>
      <title>Same agent, different list: 238 cold emails to Japanese schools, 13 replies, 2 meetings</title>
      <dc:creator>UNO Leo</dc:creator>
      <pubDate>Fri, 04 Sep 2026 13:32:07 +0000</pubDate>
      <link>https://dev.to/leouno/same-agent-different-list-238-cold-emails-to-japanese-schools-13-replies-2-meetings-37ai</link>
      <guid>https://dev.to/leouno/same-agent-different-list-238-cold-emails-to-japanese-schools-13-replies-2-meetings-37ai</guid>
      <description>&lt;p&gt;Last week I wrote about 1,027 cold emails that got 7 replies. In that post I mentioned a second product that we sell with the same agent. I used it as a comparison. This post is about that second run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The product and the list
&lt;/h2&gt;

&lt;p&gt;The second product is Speech Monster. It is a speaking practice app for students. A student talks to an AI for three minutes a day, and the AI trains the student to answer in a fixed order: conclusion, reason, example, conclusion. Schools use it for interview practice and for presentation practice.&lt;/p&gt;

&lt;p&gt;The customers are schools, prep schools and boards of education in Japan. The emails are in Japanese. This is one big difference from the LeadAce run, and I will come back to it at the end.&lt;/p&gt;

&lt;p&gt;The agent is the same. LeadAce builds the prospect list, reads each organization's website, writes one email per organization, sends it from our own mailbox, and records every reply.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;The numbers below are from August 28. The agent is still running, and I will write up the newer sends separately.&lt;/p&gt;

&lt;p&gt;All time, July 12 to August 28:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emails and contact forms sent: 238. One per organization&lt;/li&gt;
&lt;li&gt;Bounced: 1&lt;/li&gt;
&lt;li&gt;Replies from a human: 13, which is 5.5%&lt;/li&gt;
&lt;li&gt;Of those 13: 6 were interested, 4 were a no, 3 were unsubscribes&lt;/li&gt;
&lt;li&gt;Meetings: 2. One turned into several calls. Neither turned into a contract&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last 30 days, July 30 to August 28:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sent: 167, about 5 a day&lt;/li&gt;
&lt;li&gt;Replies from a human: 11, which is 6.6%&lt;/li&gt;
&lt;li&gt;Interested: 4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the same period, the LeadAce run sent more emails and got only a few replies, and all of them were a no. The code was the same. The research step was the same. I was the person pressing the button in both runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the list was built
&lt;/h2&gt;

&lt;p&gt;The agent had 6 ways to find organizations. This is what each one returned.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prep schools that advertise interview coaching, found by web search. This had the best reply rate. Small schools that do one-on-one interview practice replied most.&lt;/li&gt;
&lt;li&gt;Career support offices at colleges and technical colleges, found from the public school directories. This was the only source the agent's own scoring rated above the baseline.&lt;/li&gt;
&lt;li&gt;Schools named in education press releases and case studies. Medium.&lt;/li&gt;
&lt;li&gt;Exhibitors at an education technology expo. Too few sends to judge.&lt;/li&gt;
&lt;li&gt;Boards of education, from their public sites. 20 sent, 0 replies.&lt;/li&gt;
&lt;li&gt;Member lists of private school associations. 29 sent, 0 replies. The agent archived this one on August 20.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I see one pattern here. The sources that worked were the ones where the email could go to a department that has this problem, like a career center. The sources that failed were lists of institutions with only a general address.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the emails asked for
&lt;/h2&gt;

&lt;p&gt;None of these emails asked for a meeting. I was surprised when I read them again.&lt;/p&gt;

&lt;p&gt;The closing line asks for one sentence back. It also tells the reader what to write if the answer is no. Something like: if this is not your department, just reply "wrong department". If this is not the time, just reply "maybe later".&lt;/p&gt;

&lt;p&gt;So replying takes one line, and saying no takes two words. This is why the no replies are useful. "Wrong department" tells the agent to look for another contact at the same school. "Maybe later" puts the school back in the queue for a later cycle. If the reader says nothing, the agent learns nothing.&lt;/p&gt;

&lt;p&gt;Each email also starts with one specific thing from that organization's website. For example, a course the school runs, a purchase notice a prefecture published in May, or a seminar the principal gave at an expo. The agent finds these in the research step. The LeadAce run used the same step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the replies said
&lt;/h2&gt;

&lt;p&gt;I am not naming the schools. Here is what the replies looked like.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two meetings. One was with a private school that does one-on-one interview coaching. We met several times, and they told us in detail how they run interview practice. It did not become a contract. The other was one introduction call with the career center of a junior college. It stopped there.&lt;/li&gt;
&lt;li&gt;One technical college career office printed our materials and put them where students can see them, and shared the PDF with the homeroom teachers of two grades.&lt;/li&gt;
&lt;li&gt;Two asked for materials before deciding. One of them said the fit with their support program looked small, but asked for a test account anyway.&lt;/li&gt;
&lt;li&gt;One said they use a different app already.&lt;/li&gt;
&lt;li&gt;One said that paid apps are hard to recommend to students. This is a signal about price, and the agent recorded it as a rejection reason.&lt;/li&gt;
&lt;li&gt;One board of education replied with exactly the two words we suggested: wrong department.&lt;/li&gt;
&lt;li&gt;Three unsubscribes. Two of them came from shared mailboxes, an admissions PR address and a career office mailing list. When you send to a shared address, the reply comes from whoever reads it that day.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What was different from the LeadAce run
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The reader could use the product. A school can start using an app. Nothing in their setup blocks it. In the LeadAce run, the reader needed a Mac and a Claude Code plan, and my list never checked for that.&lt;/li&gt;
&lt;li&gt;The ask was one line, and the email said what to write if the answer was no. The LeadAce emails asked people to try a product and gave them no link. That is a much bigger ask, and there was no easy way to do it.&lt;/li&gt;
&lt;li&gt;The sender was our company, from our company domain, with a website at the other end. The LeadAce run sent from a separate domain that had no website.&lt;/li&gt;
&lt;li&gt;The market. Japanese institutions answer email, even when the answer is no. I cannot separate this from the other three with this small amount of data. I want to be clear that this difference is real.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Points 1 to 3 are things I control. Point 4 is not. What I learned is that 1 to 3 were all wrong in the LeadAce run at the same time, and the agent could not fix any of them by writing better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Boards of education: 0 for 20. Now the agent only targets the officer who runs a specific program, and skips the general inbox.&lt;/li&gt;
&lt;li&gt;Association member lists: 0 for 29. Archived.&lt;/li&gt;
&lt;li&gt;Shared mailboxes: two of the three unsubscribes. The list needs a department or a person, not an info@ address.&lt;/li&gt;
&lt;li&gt;Price: one reply said a paid app is hard to put in front of students. One reply is not a trend. But it is the kind of no that a sales tool should record, and ours did.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I take from this
&lt;/h2&gt;

&lt;p&gt;This is not a great result. Two meetings and no contract do not make a business. But the two runs used the same agent, and one of them produced conversations while the other produced nothing. The writing was the same in both. What was different was who was on the list, what we asked for, and whether the reader could act on it.&lt;/p&gt;

&lt;p&gt;If you are testing an outbound tool on your own product and getting nothing, I would check those three things before you change the copy.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>sales</category>
      <category>ai</category>
      <category>japan</category>
    </item>
    <item>
      <title>I sent 1,027 cold emails with my own AI sales agent. 7 replied. The problem was not the emails.</title>
      <dc:creator>UNO Leo</dc:creator>
      <pubDate>Sat, 29 Aug 2026 13:31:08 +0000</pubDate>
      <link>https://dev.to/leouno/i-sent-1027-cold-emails-with-my-own-ai-sales-agent-7-replied-the-problem-was-not-the-emails-gco</link>
      <guid>https://dev.to/leouno/i-sent-1027-cold-emails-with-my-own-ai-sales-agent-7-replied-the-problem-was-not-the-emails-gco</guid>
      <description>&lt;p&gt;Last week I wrote about our Product Hunt launch. 2 upvotes, 0 signups. This is the other half of the story.&lt;/p&gt;

&lt;p&gt;Before that launch I was already using our own product to sell it. It has been running every day since June. Here is what 1,027 cold emails looked like. The numbers come from our production database on August 29. I show all time and the last 30 days separately, because the early months were not the same product.&lt;/p&gt;

&lt;p&gt;We are a small software company in Tokyo. LeadAce is an outbound sales agent that runs as a Claude Code plugin. It builds a prospect list, reads each company's website, writes one email per company, sends it from my own Gmail, and records every reply and every rejection reason. I run it on a cron to sell LeadAce itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;All time, June 11 to August 28:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emails sent: 1,027. One email per company, no bulk sending&lt;/li&gt;
&lt;li&gt;Replies from a human: 7. 1 was interested, 5 were a no, 1 was an unsubscribe&lt;/li&gt;
&lt;li&gt;Signups I can trace to these emails: 0&lt;/li&gt;
&lt;li&gt;Paying customers from this: 0&lt;/li&gt;
&lt;li&gt;Bounced: 75, which is 7.3%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing about what I asked for. These emails never asked for a meeting. The ask was "if this sounds useful, try LeadAce". So a meeting count would be 0 by design, and I am not using it as a result. The result that matters for this ask is a signup, and that is the 0 above.&lt;/p&gt;

&lt;p&gt;Last 30 days, July 30 to August 28:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emails sent: 246, about 8 a day&lt;/li&gt;
&lt;li&gt;Replies from a human: 5, which is 2.0%. 0 interested, 4 a no, 1 unsubscribe&lt;/li&gt;
&lt;li&gt;Bounced: 17, which is 6.9%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The all time number hides a bad start. Most of the total went out in June, at a much faster pace than now, and a lot of the targeting that month was wrong. June got almost nothing back. I am not taking it out of the total. But the last 30 days is the better picture of what the agent does now, and the reply rate there is several times what it was before.&lt;/p&gt;

&lt;p&gt;Both rates are still low. And every reply in the last 30 days was a no.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first answer I found was email deliverability
&lt;/h2&gt;

&lt;p&gt;I spent two weeks here. It was a real problem.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We had no DMARC record until August 13. The emails went out. A lot of them most likely went to spam.&lt;/li&gt;
&lt;li&gt;After adding DMARC I checked Google Postmaster Tools. Direct sends passed alignment 16 out of 16.&lt;/li&gt;
&lt;li&gt;There was a second problem. Many prospects use a generic info@ address that forwards to a founder's personal Gmail. Forwarding rewrites the message, so the DKIM signature breaks. On August 17, 15 of 33 forwarded copies failed DMARC.&lt;/li&gt;
&lt;li&gt;I kept the policy at quarantine anyway. The fix for forwarding is on the receiving side, not on mine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since then, our seed tests show no spam reports. So the sending is healthy now. The bounce rate went down after the fix, and every reply in the last 30 days came after it.&lt;/p&gt;

&lt;p&gt;I thought that explained everything. Then I compared it with a second product we run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number that broke that explanation
&lt;/h2&gt;

&lt;p&gt;We run a second product with the same agent and the same research step. It is a speaking practice app for students, and it sells to schools and prep schools in Japan, in Japanese. So the market, the language and the ask are all different from the LeadAce run. I will write that run up on its own. Here I only use it as a control, because the code that finds a company, reads its site and writes the email is the same.&lt;/p&gt;

&lt;p&gt;All time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emails sent: 238&lt;/li&gt;
&lt;li&gt;Replies from a human: 13, which is 5.5%. 6 of them were interested&lt;/li&gt;
&lt;li&gt;Bounced: 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That product asks for a conversation, so the ask is different too. I am only comparing replies here.&lt;/p&gt;

&lt;p&gt;It is the same code. One list gets a reply from fewer than one email in a hundred, and none of those replies are interested. The other list gets a reply from about one in twenty, and half of those are interested.&lt;/p&gt;

&lt;p&gt;Part of that gap is the market. Japanese schools answer email more often than US startup founders do. I cannot separate that from the list itself with this data. But it does not change the point. The same agent wrote both sets of emails. If the writing were the problem, both lists would be bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was wrong
&lt;/h2&gt;

&lt;p&gt;Our agent picks who to contact using discovery strategies. We had 8 of them running: YC and HN launch pages, accelerator rosters, Product Hunt, tech news, Techstars, GitHub trending, Crunchbase, Wellfound.&lt;/p&gt;

&lt;p&gt;Every one of them selects companies by "this company exists and is doing something". Not one of them checks the thing that decides whether the reader can use my product.&lt;/p&gt;

&lt;p&gt;To use LeadAce you need a Mac, a Claude Code Pro or Max plan, and a Gmail account. That is a narrow group. None of my 8 strategies tested for it. So the chance that any given recipient could install the product was about the same as picking a company at random.&lt;/p&gt;

&lt;p&gt;There is a worse part. The one population that was closest to my real users, founders who post their launches on HN, had the best reply rate of the eight. My own bandit archived it in mid August for low yield, because the rate was still low in absolute terms. The system did what I told it to do. I told it to optimize reply rate across strategies. I never told it that only some strategies contain people who can run the software at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the replies said
&lt;/h2&gt;

&lt;p&gt;Seven human replies is not data. But the content lines up with the above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One said they already have agents doing this, and asked about per user pricing. That was the only positive one.&lt;/li&gt;
&lt;li&gt;One said they built their own agent to do the same thing.&lt;/li&gt;
&lt;li&gt;One said they are not looking for outbound sales support or new partnerships.&lt;/li&gt;
&lt;li&gt;One said they are not looking for digital marketing or outbound services.&lt;/li&gt;
&lt;li&gt;One was an automated reply quoting their blog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read them together and two things show up. The people closest to my target are technical enough to have already built a small version of this themselves. And the people who are not technical read my email as an offer of outsourced sales work, because that is what a cold email about "outbound" sounds like if you are not the buyer I imagined.&lt;/p&gt;

&lt;h2&gt;
  
  
  There was also nowhere to go
&lt;/h2&gt;

&lt;p&gt;The ask in the email was "try LeadAce". We do not put links in the email body. That was on purpose, because of domain reputation, and I still think the reasoning was right. But it means the only way to act on the email was to remember the name and search for it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Searching "LeadAce" put our site in eighth place, under a different company with a similar name. Most people do not scroll that far for a name from a cold email.&lt;/li&gt;
&lt;li&gt;The sending domain, getleadace.com, had MX, SPF and DMARC records, and no A record. If a reader typed the domain from the From line into a browser, they got a connection error.&lt;/li&gt;
&lt;li&gt;The closing line of most emails was some version of "might be worth a look", with no place named to look.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the path I was asking a reader to take was: read the email, keep the name in mind, search for it, not find it. Even in the case where the email arrived, and the reader could use the product, and they were interested, that path ends before the signup page. I built a funnel with the last step missing and then measured the reply rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What our own product told me
&lt;/h2&gt;

&lt;p&gt;LeadAce has a detector that watches the reply rate over a 90 day window and estimates whether an outbound setup is dead, meaning more sending will not produce more replies. It warns at 0.99.&lt;/p&gt;

&lt;p&gt;The last reading I have for my own account is 0.979, from August 18.&lt;/p&gt;

&lt;p&gt;So my own product was about to tell me that my own outbound does not work, using a feature I built for customers. I am leaving it on. If it fires, the feature is doing its job. I would rather have the number than not have it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am changing
&lt;/h2&gt;

&lt;p&gt;I am not changing the copy. I read a lot of the sent emails and they are fine. They are specific and researched, and there is one per company. The copy was not what was holding this back.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change who gets contacted. The people who can use this are the people already publishing Claude Code plugins, skills and MCP servers on GitHub. That is a list you can build from public data, and it tests the hard requirement directly instead of guessing at it.&lt;/li&gt;
&lt;li&gt;Give the email a destination. Our own guidelines already recommend aged domains like github.com. The repo is a better landing place than a marketing page for this audience anyway. Asking someone to search for a name that does not rank is not a call to action.&lt;/li&gt;
&lt;li&gt;Point the sending domain at something. A redirect is a ten minute job that I did not do for three months.&lt;/li&gt;
&lt;li&gt;Stop treating cold email as our acquisition channel. It is a good product demo and a good source of data about our own product. It is not where our first users are. Our users are in Claude Code, and I should meet them there.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code: my normal Max plan. No per email AI cost.&lt;/li&gt;
&lt;li&gt;Cloudflare Workers and Supabase for the backend. If you self-host it, you need the Cloudflare Workers Paid plan, which starts at $5 per month. The Supabase free tier is enough to evaluate it.&lt;/li&gt;
&lt;li&gt;My time: about 10 minutes a day to read the cycle summary, plus two weeks on deliverability that fixed a real problem but not the main one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I take from this
&lt;/h2&gt;

&lt;p&gt;The lesson I expected to write was about DMARC. The real one is smaller and more embarrassing. I built a targeting system with eight ways to find companies and zero ways to check whether a company could install my software. Then I ran it for three months and read the reply rate as if it were telling me something about my writing.&lt;/p&gt;

&lt;p&gt;A reply rate can only tell you about the list you sent to. I had no number at all for how many people on that list could install the product. So there was nothing in the reply rate for me to read.&lt;/p&gt;

&lt;p&gt;The agent, the prompts and the detector are all in the open source repo. If you run outbound from your own inbox, I would like to know how you check that your list can buy what you sell, before you send.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>sales</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Our Product Hunt launch returned 2 upvotes and 0 signups. Here is every number.</title>
      <dc:creator>UNO Leo</dc:creator>
      <pubDate>Sat, 22 Aug 2026 09:36:29 +0000</pubDate>
      <link>https://dev.to/leouno/our-product-hunt-launch-returned-2-upvotes-and-0-signups-here-is-every-number-89l</link>
      <guid>https://dev.to/leouno/our-product-hunt-launch-returned-2-upvotes-and-0-signups-here-is-every-number-89l</guid>
      <description>&lt;p&gt;On August 19 we launched LeadAce on Product Hunt. It was our first launch to an English speaking audience. I am writing down the numbers while they are still uncomfortable, because the posts I found most useful when I was preparing were the ones that did this.&lt;/p&gt;

&lt;p&gt;We are a small software company in Tokyo. LeadAce is an outbound sales agent that runs as a Claude Code plugin. The backend is open source. It has been in Public Beta since the launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Product Hunt, 24 hours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 upvotes&lt;/li&gt;
&lt;li&gt;1 comment, which was mine&lt;/li&gt;
&lt;li&gt;Day rank #160, week rank #758&lt;/li&gt;
&lt;li&gt;3 followers on the product page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signups from the launch: 0.&lt;/p&gt;

&lt;p&gt;Site traffic for the four weeks up to launch day: 6 active users, 27 page views. Referrers were direct 4, producthunt.com 1, t.co 1.&lt;/p&gt;

&lt;p&gt;Our X account over the same four weeks: 48 posts, 576 impressions total, 2 link clicks, 2 new followers.&lt;/p&gt;

&lt;p&gt;So the launch did not fail at the landing page. It failed before that. Almost nobody arrived.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we got stopped
&lt;/h2&gt;

&lt;p&gt;This is the part I did not plan for. I spent weeks on the product, the demo video, the gallery images and the copy. Every one of those was ready. What I did not have was accounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hacker News.&lt;/strong&gt; I could not post Show HN at all. HN was limiting Show HN submissions from low karma accounts, and my account had karma 1. I created it years ago and never used it. There is no way to buy your way past this, and there should not be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;r/ClaudeAI.&lt;/strong&gt; My first attempt was removed by automod because the account was too new. I tried again from my older Reddit account, which has an age of 5 years but karma 1. A moderator locked it. The subreddit requires 50 total karma to post a Showcase on the feed. They pointed me to a megathread instead, which is the correct call on their side. My comment there got 67 views and 1 upvote in 19 hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;r/SaaS.&lt;/strong&gt; The post went through, but Reddit's pre-submit check warned me that it might break the rules on vendor spam. I removed every link from the body and changed the ending to a real question. That version posted fine. It is now the post with the most discussion of anything we published.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;r/selfhosted.&lt;/strong&gt; Blocked by a rule I should have read first. Projects less than three months old can only go in the New Project Megathread. Our public repo was created on May 28, so we reach three months on August 28. We will post then.&lt;/p&gt;

&lt;p&gt;The pattern is the same in every case. The gate was not the quality of the post. The gate was account history, and account history takes months of ordinary participation that I had not done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually worked
&lt;/h2&gt;

&lt;p&gt;Two subreddits let us in, and both were worth more than Product Hunt.&lt;/p&gt;

&lt;p&gt;r/SideProject and r/SaaS produced real questions from people who read the post. One of them changed the roadmap on the same day.&lt;/p&gt;

&lt;p&gt;Someone asked about pricing. The tiers all have a hard monthly cap. When you hit the cap, sending stops. They asked whether the accounts sending 200 emails a month are structurally different from the ones sending 4,000, or whether it is the same customer at different stages. Writing the reply is what made the problem visible to me. A hard stop at the cap is lost revenue for me and a bad moment for the user at the same time. Metered overage on top of the flat tier went on the roadmap that evening.&lt;/p&gt;

&lt;p&gt;Another asked about prompt injection, which is the right question for this product. The agent reads a prospect's website and then writes an email. So a hostile page is an instruction source. My answer was that the send step only uses the stored record, and the server enforces quotas, do-not-contact, the country allowlist, email verification and the compliance footer. The model cannot skip those even if a page fools it. A hostile page could still poison one prospect's record or make one email strange. It cannot trigger mass sends. I said I would harden the research step, and that is now a real task instead of a vague worry.&lt;/p&gt;

&lt;p&gt;Neither of those conversations needed traffic to happen. Six upvotes and a dozen comments were enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist I did not have
&lt;/h2&gt;

&lt;p&gt;If you are planning a launch, check the account requirements before you write anything. This is the table I wish I had:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;How long it takes to fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Product Hunt&lt;/td&gt;
&lt;td&gt;None. Anyone can schedule a launch&lt;/td&gt;
&lt;td&gt;Same day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hacker News&lt;/td&gt;
&lt;td&gt;Enough karma for Show HN. The limit is not published and it changes&lt;/td&gt;
&lt;td&gt;Weeks of commenting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r/ClaudeAI&lt;/td&gt;
&lt;td&gt;50 total karma for a Showcase post on the feed&lt;/td&gt;
&lt;td&gt;Weeks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r/SideProject&lt;/td&gt;
&lt;td&gt;None that blocked us&lt;/td&gt;
&lt;td&gt;Same day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r/SaaS&lt;/td&gt;
&lt;td&gt;No links in the body, and the post has to read as a discussion&lt;/td&gt;
&lt;td&gt;Same day, if you rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r/selfhosted&lt;/td&gt;
&lt;td&gt;Project must be 3 months old to post on the feed&lt;/td&gt;
&lt;td&gt;Fixed by the calendar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indie Hackers&lt;/td&gt;
&lt;td&gt;New accounts cannot post at all. A moderator has to grant it, or you pay for IH Plus&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I hit a fifth wall while writing this post. I made an Indie Hackers account so I could post there too. New accounts cannot create posts at all. You unlock that by leaving thoughtful comments until a moderator picks you, or by paying for Indie Hackers Plus. I did not know that before I signed up.&lt;/p&gt;

&lt;p&gt;The fix is boring. Pick the three channels that matter for your product, and start commenting on them six weeks before you launch. Not promoting. Commenting. Your karma on launch day is a thing you build in advance, like a mailing list.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am doing next
&lt;/h2&gt;

&lt;p&gt;I am not going to run the launch again. Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Daily replies on X to posts about Claude Code and AI agents, with something useful in each one. Our single highest performing post in four weeks was a reply to someone else, at 65 impressions against an average of 12. When you have no followers, the only path to an audience is someone else's.&lt;/li&gt;
&lt;li&gt;Ordinary participation on HN and Reddit from the accounts that will be used for the next launch. Karma first, launch second.&lt;/li&gt;
&lt;li&gt;r/selfhosted on August 28, when the project is old enough.&lt;/li&gt;
&lt;li&gt;Writing down the numbers, like this post.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The product side of the launch was fine. The distribution side started from zero, and I did not notice that zero was a number I had to fix in advance.&lt;/p&gt;

&lt;p&gt;If you launched recently and hit the same wall, I would like to know which channels let you in. I will post our next set of numbers whether they are better or not.&lt;/p&gt;

&lt;p&gt;LeadAce is at &lt;a href="https://leadace.ai" rel="noopener noreferrer"&gt;leadace.ai&lt;/a&gt;. The source is at &lt;a href="https://github.com/aitit-inc/leadace" rel="noopener noreferrer"&gt;github.com/aitit-inc/leadace&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>startup</category>
      <category>saas</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Building an outbound sales agent as a Claude Code plugin (and open-sourcing it)</title>
      <dc:creator>UNO Leo</dc:creator>
      <pubDate>Thu, 13 Aug 2026 11:45:10 +0000</pubDate>
      <link>https://dev.to/leadace/building-an-outbound-sales-agent-as-a-claude-code-plugin-and-open-sourcing-it-17ae</link>
      <guid>https://dev.to/leadace/building-an-outbound-sales-agent-as-a-claude-code-plugin-and-open-sourcing-it-17ae</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/tILouCeVYb4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I run a small software company in Tokyo. I am an engineer, not a salesperson. Cold outbound was the part of my job I kept avoiding. So I built an agent that does it for me. It runs as a Claude Code plugin, and the whole stack is open source. This post is about the architecture decisions that mattered.&lt;/p&gt;

&lt;p&gt;The product is LeadAce (&lt;a href="https://leadace.ai" rel="noopener noreferrer"&gt;leadace.ai&lt;/a&gt;, &lt;a href="https://github.com/aitit-inc/leadace" rel="noopener noreferrer"&gt;source&lt;/a&gt;). It is in Public Beta. It finds companies that match your ICP, reads each company's site, writes one email per company, and sends from your own Gmail. Then it collects the replies. And it turns every rejection into a structured reason: budget, timing, wrong buyer, or missing feature. That data changes the next round's targeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a plugin, not another dashboard
&lt;/h2&gt;

&lt;p&gt;The honest reason: I already spend all day in Claude Code. I did not want to build one more web app with a chat box in it.&lt;/p&gt;

&lt;p&gt;Later I found a better reason. A Claude Code plugin runs on the user's own Anthropic plan, on their machine. I do not proxy the LLM calls. So I do not have to charge for them. The price only covers send volume and infrastructure. That is why the entry plan can be $29/mo. My users are developers who already pay for Claude Pro or Max. For them, "bring your own agent runtime" is a feature, not a limitation.&lt;/p&gt;

&lt;p&gt;The plugin is only the UX layer. Everything stateful is a normal SaaS backend behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Claude Code plugin model in 30 seconds
&lt;/h2&gt;

&lt;p&gt;If you have not built one: a plugin is a directory with skills (markdown instructions that become slash commands), an optional MCP server declaration, and scripts. Distribution is a git repo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;claude plugin marketplace add aitit-inc/leadace
claude plugin install leadace@leadace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;LeadAce ships skills like &lt;code&gt;/leadace&lt;/code&gt; (onboarding: point it at your homepage), &lt;code&gt;daily-cycle&lt;/code&gt;, &lt;code&gt;build-list&lt;/code&gt;, &lt;code&gt;outbound&lt;/code&gt;, &lt;code&gt;check-responses&lt;/code&gt;, and &lt;code&gt;evaluate&lt;/code&gt;. Each skill is a prompt that works like a program. It contains instructions, guardrails, and references to MCP tools and local scripts. &lt;code&gt;${CLAUDE_PLUGIN_ROOT}&lt;/code&gt; resolves file paths inside the installed plugin. That sounds like a small thing. But you need it the first time a helper script inside your plugin has to run on someone else's machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The split that matters: LLM vs MCP tools vs local tools
&lt;/h2&gt;

&lt;p&gt;The main design question for any agent product is this: what does the model decide, and what is code?&lt;/p&gt;

&lt;p&gt;Our split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP tools (server-side, deterministic):&lt;/strong&gt; database writes, dedup, quota enforcement, compliance checks, do-not-contact lists. The model calls &lt;code&gt;record_outreach&lt;/code&gt;. It does not see the twelve validation rules behind it. The validation runs on the server. So a prompt injection hidden in some company's website cannot turn it off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local tools (user's machine):&lt;/strong&gt; things that need the user's environment. Sending through their Gmail. Fetching pages. Browser automation. This is what keeps "sends from your own inbox" true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The LLM (judgment):&lt;/strong&gt; reading a company's site and choosing the angle, writing the email, classifying a reply, updating the strategy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule I ended up with: if a mistake causes a compliance or data problem, it must be code. If a mistake causes a quality problem, the model can do it, with review gates around it.&lt;/p&gt;

&lt;p&gt;There is one more point I understood too late. This split is also the trust boundary. The agent reads random websites all day. A prospect's site is untrusted input by definition. So anything that touches the database or sends email has to be a fixed contract in code. It must not be something the model can be talked into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-tenancy: RLS as the safety net
&lt;/h2&gt;

&lt;p&gt;Every table has a &lt;code&gt;tenant_id&lt;/code&gt;. Every request runs in a Postgres transaction that starts with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET LOCAL ROLE app_rls
SET LOCAL app.tenant_id = '&amp;lt;tenant&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;app_rls&lt;/code&gt; is a role with row-level security enforced. The policies filter on &lt;code&gt;app.tenant_id&lt;/code&gt;. Route handlers still write normal filtered queries. RLS is not the query mechanism here. It is the thing that saves you on the day a handler forgets a &lt;code&gt;where&lt;/code&gt;. Only the auth middleware bypasses RLS, because it has to resolve user → tenant before the tenant is known.&lt;/p&gt;

&lt;p&gt;The whole setup is about a hundred lines. This product stores other people's prospect lists and email threads. For that risk, a hundred lines is very cheap insurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  One env var to turn off billing
&lt;/h2&gt;

&lt;p&gt;The backend has one switch, &lt;code&gt;LEADACE_EDITION&lt;/code&gt;. It has two values: &lt;code&gt;cloud&lt;/code&gt; and &lt;code&gt;self-hosted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In self-hosted mode, the Stripe endpoints (&lt;code&gt;/me/checkout&lt;/code&gt;, &lt;code&gt;/me/portal&lt;/code&gt;, &lt;code&gt;/stripe/webhook&lt;/code&gt;) return 404, and every tenant resolves to an unlimited plan. The default is self-hosted. So a fresh deploy fails closed into the free mode. It cannot accidentally run billing without keys.&lt;/p&gt;

&lt;p&gt;This is what makes the open-source story real. The hosted service and the self-hosted deploy are the same code. Hosted is just the edition where Stripe is on. The deploy target is Cloudflare Workers + Supabase. The free tiers of both cover solo and small-team volume. So self-hosting costs nothing.&lt;/p&gt;

&lt;p&gt;Why give away an unlimited edition? Because my buyer is a developer. A developer asks "what happens if this company disappears?" before wiring their outbound pipeline to a SaaS. My answer: you deploy the same repo and keep going. That answer closes the objection better than any uptime page. (The license is a modified Apache 2.0.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ship the single entry point first.&lt;/strong&gt; For weeks the plugin had many skills but no clear front door. Adoption got easier on the day &lt;code&gt;/leadace &amp;lt;your-homepage&amp;gt;&lt;/code&gt; became the one command that sets up everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the receive side earlier.&lt;/strong&gt; Each recipient gets a page where they can ask questions before replying. I believe this side is the long-term core of the product. The roadmap is agent-to-agent over A2A, and the rejection-reason schema will become a public spec. I built this part too late.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not pre-load and merge for upsert PUTs.&lt;/strong&gt; Two concurrent writers and one read-modify-write cycle means silent data loss. Use the database's upsert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat migrations as immutable once they touch any environment.&lt;/strong&gt; I edited an applied Drizzle migration once because "it is only staging". That is how you get two divergent histories.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest numbers and limits
&lt;/h2&gt;

&lt;p&gt;Cold outbound reply rates are in the single digits. The pitch is not "10x replies". The pitch is that the nos come back as structured reasons instead of silence. Sending is capped at a human pace per mailbox, on purpose. Recipients are limited to the US, Canada and Japan until per-country compliance rules ship. The plugin is verified on macOS with Claude Code today. Other runtimes are unverified.&lt;/p&gt;

&lt;p&gt;We use LeadAce to sell LeadAce. So most of the rejection reasons in my dashboard are about my own product. Reading them is not fun. But it is the most useful screen in the product.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/aitit-inc/leadace" rel="noopener noreferrer"&gt;github.com/aitit-inc/leadace&lt;/a&gt; · Product: &lt;a href="https://leadace.ai" rel="noopener noreferrer"&gt;leadace.ai&lt;/a&gt; (Free tier, no card)&lt;/p&gt;

&lt;p&gt;If you have questions about the plugin model, the RLS setup, or the edition switch, I am happy to go deeper in the comments.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>mcp</category>
      <category>saas</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
