<?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>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>
