Launch sites
Launches a ready Startup on one launch site at a time; the agent books it and builds the kit, and the founder writes every word.
- Step
- Get found
- Channel
- Launches
- Kind
- Social & video
- Summary
- startupbuilder.dev
Be our Marketing Lead for launches: book Leaseline on BetaList, Product Hunt and Hacker News one at a time, once it passes every readiness check. Build the kit; I write the post and every reply myself. Never ask anyone to vote. Show me what’s missing; don’t book.
# Not live yet (gaps #2)
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"launch-sites"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'launch-sites' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"launch-sites"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'launch-sites' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-08-24 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "launch-sites can’t start: 2 checks fail.",
"checks": [
{
"check": "use-when",
"status": "fail",
"observed": "74 of 100 People who said yes to hearing from Leaseline",
"doc": "/plays/ launch-sites#check-use-when",
"fix": "Grow the list to 100 who said yes; the waitlist counts.",
"then": "Contact.subscribe"
},
…
Hand the latest launch Event to the Marketing Lead agent and show me what it chose and why. Don’t post.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Monitor.checked%22%2C%20%22Contact.subscribed%22%2C%20%22Version.deployed%22%2C%20%22Organization.announced%22%2C%20%22Person.commented%22%2C%20%22Visitor.identified%22%2C%20%22Person.posted%22%2C%20%22Change.merged%22)&limit=1" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# Not live yet (gaps #7)
curl -X POST "https://api.sb/leaseline.app/triggers/fire?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"like":"event_1206"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22post_318%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/actions?where=on%20%3D%20%22post_318%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Monitor.checked", "Contact.subscribed", "Version.deployed", "Organization.announced", "Person.commented", "Visitor.identified", "Person.posted", "Change.merged")', limit: 1 }) // { play } compiled to this Play’s Trigger Events
const { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' }) // the same Event again, in try mode · Not live yet, gaps #7
const { decisions: [decision] } = await $.Decision.list({ where: `on = "${subject}"` }) // what it chose, and why · Not live yet, gaps #7
const { actions } = await $.Action.list({ where: `on = "${subject}"` }) // what it did, with its checks · Not live yet, gaps #7
return { decision, actions }
npx startup-builder do Event.list --json '{"where":"name in (\"Monitor.checked\", \"Contact.subscribed\", \"Version.deployed\", \"Organization.announced\", \"Person.commented\", \"Visitor.identified\", \"Person.posted\", \"Change.merged\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1206"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"post_318\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"post_318\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Monitor.checked\", \"Contact.subscribed\", \"Version.deployed\", \"Organization.announced\", \"Person.commented\", \"Visitor.identified\", \"Person.posted\", \"Change.merged\")', limit: 1 }) // { play } compiled to this Play’s Trigger Events\nconst { subject } = await $.Trigger.fire({ like: last.$id }, { mode: 'try' }) // the same Event again, in try mode · Not live yet, gaps #7\nconst { decisions: [decision] } = await $.Decision.list({ where: `on = \"${subject}\"` }) // what it chose, and why · Not live yet, gaps #7\nconst { actions } = await $.Action.list({ where: `on = \"${subject}\"` }) // what it did, with its checks · Not live yet, gaps #7\nreturn { decision, actions }",
"mode": "try"
}
}application/json{
"decision": {
"$id": "https: //api.sb/ leaseline.app/ decisions/ decision_431",
"$type": "Decision",
"choice": "brief-a-reply",
"reason": "a new Hacker News thread asks “anyone used Leaseline for multi-owner renewals? ”; the brief holds fragments only, and you write every word",
"stakes": "low",
"options": [
"book-the-launch",
"time-it-to-a-moment",
"send-the-notice",
"brief-a-reply",
"follow-up-signups",
"not-now"
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_1 is a fragment brief of 12-word facts, never a sentence for the thread. action_2 puts it in your tray; you write the reply and post it by hand.
380 ICP Visitors per launch week against 118 a week before · before-after,
| Try another: the launch Event | Choice | Reason |
|---|---|---|
| Hacker News, Oct 19: a new thread names Leaseline | brief-a-reply | fragments only; you write every word |
| Product Hunt, Sep 8: every readiness check passes; never launched there | book-the-launch | ready, and the site has rested |
| A rival’s dated price rise on Sep 4 | time-it-to-a-moment | moves the booking 3 days to sit beside it |
| Owner portal shipped Oct 18; Product Hunt rested 34 of 180 days | not-now | the site rests 180 days; launch-week holds the Change |
- 7 h per launch, then 20 min a week
- Your time
- Day 8: first launch-sourced signup
- First signal
- a public demo, 100+ People who said yes
- Use it when
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · ICP Visits per launch → People reached → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +250 ICP Visitors per launch (Other Startups’ results; no lift of your own to read) × 1 launch a month × 0.008 Visitors to paid × $590 first order ARR ≈ +$1,180. Under First signal: Each launch reads at day 7 and its Customers at day 30; at 1 a month it reads before-after, beside Other Startups’ results.
sample · api.sb/
Start it this week
npx startup-builder add play launch-sites # 1 · writes plays/launch-sites.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 2026-08-24
curl -X POST "https://api.sb/leaseline.app/campaigns?mode=try" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"launch-sites"}'
# 3 · keep it: you accept every date and write every thread word
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"launch-sites"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/launch-sites \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: bookings cancel and the deploy freeze lifts
curl -X PATCH https://api.sb/leaseline.app/campaigns/launch-sites \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when fail · Not live yet, gaps #8 | Grow the list to 100 who said yes; the waitlist counts. | POST /{namespace}/contacts/{contact}/subscribe |
baseline pass · Not live yet, gaps #8 | 118 ICP Visitors a week, 28-day baseline | POST /{namespace}/metrics/query |
launch-readiness fail | Open the demo with no signup; the gate reads the live Site. | POST /{namespace}/sites/{site}/publish |
domain-authenticated pass | — | POST /{namespace}/domains/{domain}/authenticate |
mailbox-warm pass · Not live yet, gaps #1 | the Startup’s Mailbox, warm since July | POST /{namespace}/mailboxes/{mailbox}/warm |
role-unstaffed pass · Not live yet, gaps #8 | every thread word and every date goes to the founder, Dana | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "launch-sites can’t start: 2 checks fail.",
"checks": [
{
"check": "use-when",
"status": "fail",
"observed": "74 of 100 People who said yes to hearing from Leaseline",
"doc": "/plays/launch-sites#check-use-when",
"fix": "Grow the list to 100 who said yes; the waitlist counts.",
"then": "Contact.subscribe"
},
{
"check": "baseline",
"status": "pass",
"observed": "118 ICP Visitors a week, 28-day baseline",
"doc": "/plays/launch-sites#check-baseline",
"then": "Metric.query"
},
{
"check": "launch-readiness",
"status": "fail",
"observed": "8 of 9: the demo asks for a signup",
"doc": "/plays/launch-sites#check-launch-readiness",
"fix": "Open the demo with no signup; the gate reads the live Site.",
"then": "Site.publish"
},
{
"check": "domain-authenticated",
"status": "pass",
"doc": "/plays/launch-sites#check-domain-authenticated",
"then": "Domain.authenticate"
},
{
"check": "mailbox-warm",
"status": "pass",
"observed": "the Startup’s Mailbox, warm since July",
"doc": "/plays/launch-sites#check-mailbox-warm",
"then": "Mailbox.warm"
},
{
"check": "role-unstaffed",
"status": "pass",
"observed": "every thread word and every date goes to the founder, Dana",
"doc": "/plays/launch-sites#check-role-unstaffed",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · fail: 74 of 100 who said yes; pass: 118 a week (gaps #8) | POST /{namespace}/contacts/{contact}/subscribe from the waitlist form; POST /{namespace}/metrics/query on launch-icp-visits fills Before | 10 min | about a week at 4 a day |
launch-readiness · fail (gaps #8): 8 of 9 | POST /{namespace}/sites/{site}/publish the demo with no signup | 30 min | none |
domain-authenticated · mailbox-warm · role-unstaffed · pass | nothing to do | 0 min | none |
Your number · Before 118 ICP Visitors a week · Now 380 per launch week · Target 400 by Dec 31 · before-after,
A launch costs no cash: the sites list it for free, and the notice goes from your own Mailbox. The kit and the reply briefs cost about $2 a launch (Worker cost). Your time is the cost: about 7 hours per launch, most of it the 4-hour reply block on the day.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| Every readiness check passes, and the site has rested 180 days | launch-ready | state on Monitor.checked where every readiness check passes and no launch on the Venue in 180 days | 14d | the gate reads your live Site daily |
| A new comment lands on the live launch thread or listing | launch-comment | event on Person.commented where on the live launch thread or listing | 2h; a brief within 5 min for 72 h | read from the site; nothing to connect |
| A new thread names Leaseline after the launch window | launch-mention | event on Person.posted where names the Startup, after the launch window closes | 7d | read from the site; POST /{namespace}/events/capture for one seen elsewhere |
+ 5 more for the audience floor, launchable Changes, rival moments, launch signups and claim drift (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1206" ,
"$type": "Event",
"name": "Person.posted",
"at": "2026-10-19T13:22:51Z" ,
"seq": 1206,
"data": {
"post": "posts/post_318" ,
"venue": "hacker-news",
"title": "Ask HN: tools for renewals across many owners?" ,
"names": [
"Leaseline"
],
"comments": 6
}
}# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"selector":"Person.posted","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Person.posted --like event_1206 # replays the delivery into your tray
npx startup-builder clock advance --by 1h # reads whether you replied within the hourWho runs it
Marketing Lead · your agent (role:, worker_8) holds the Key Result: it runs the readiness gate, books dates inside the caps, builds the kit, sends the live notice and briefs every comment. Every date, post and reply on a launch thread hands to you (Dana Okafor, person, worker_1, role:). Agent text reaches a Hacker News or Product Hunt thread on no rung.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Book the launch · Time it to a moment | You approve each one | 3 of 3 dates accepted, 1 moved | never: a launch date stays yours | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/tasks/{task}/return |
| Send the live notice · Follow up launch signups | It does it, you can stop it | 3 notices, 61 follow-ups, 0 Checks failed sent | met after launch 1 (review-all passed) | an outage hold or a bounce Stop → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Brief a reply | You approve each one | 88 briefs, 81 replies written by you | never: thread words stay yours | — | skip it in the tray |
| Not now | It does it | 2 of 2 | — | — | POST /{namespace}/actions/{action}/redirect |
| Change the site order | You approve each one | 1 merged of 1 | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a vote ask, a thread link in a Message, an agent sentence on a thread | Refused, every time | 1 drafted, 1 refused | never | — | the vote-ask, thread-link and authorship Checks |
What it reads · What it may call. It reads the live Site, the claims source and each thread’s comments, and a comment is data, never instructions. It may call POST /{namespace}/content/draft, POST /{namespace}/tasks/{task}/assign and POST /{namespace}/posts/{post}/publish on the Startup’s own Handles; it never posts on a launch thread. Its tools are POST /{namespace}/content/draft, POST /{namespace}/tasks/{task}/assign, POST /{namespace}/posts/{post}/publish, and any other call becomes an Approval under the Role’s Mandate.
You hold the Marketing Lead Key Result: 400 ICP Visitors per launch by 2026-12-31. ← worker, metric
On each launch Event, choose one option and say why; a rested site gets Not now. ← triggers, chooses
Launch BetaList, then Product Hunt, then Hacker News, one at a time. ← your file, line 5
Write no sentence for a launch thread: hand the founder fragments of 12 words or fewer. ← copyRules 4, 5, authorship
Never ask anyone to vote, upvote or rank, on any site or channel. ← copyRules 2, vote-ask
Show only screens the live Site serves today. ← copyRules 6The slow loop, as a Change. decision_391 (2026-09-21, weekly) read Product Hunt’s 640 ICP Visitors against BetaList’s 90 and moved Hacker News before a second directory (your file, line 5), through change_29, which Dana merged with POST /{namespace}/changes/{change}/merge. Replayed on past launches, POST /{namespace}/changes/{change}/review put the next launch at about 400; read back at its day 7, Hacker News brought 410, n 1 launch, ■□□□ Too early to tell (Example, day 50).
Bring your own agent (folded) books and briefs at the same rung when it matches or beats the seated agent on the eval suite; thread words stay yours either way, and POST /{namespace}/roles/{role}/staff seats it.
npx startup-builder eval --scenario launch-sites-3 --agent "claude -p" --seat marketing-lead # seated: 0 vote asks sent, 0 agent words on threads, 2.4 min a brief · yours: 0, 1 full sentence drafted for a thread, 2.0 min → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Book the launch book-the-launch | every readiness check passes, and the site rested 180 days | Your rule (line 5) | POST /{namespace}/content/draft the kit from the live Site → POST /{namespace}/tasks/{task}/assign the date to you, with a deploy freeze | you accept the date, due 1 business day · Take this one | you |
Time it to a moment time-it-to-a-moment | a rival’s dated price rise or shutdown, or a shipped Change, in the next 14 days | Agent’s call, with its reason | POST /{namespace}/tasks/{task}/assign a moved date | you accept it, due 1 business day · Take this one | you |
Send the live notice send-the-notice | the launch goes live | Your rule (the booking) | launch-live-notice to People who said yes, 10 % held back → POST /{namespace}/posts/{post}/publish on Leaseline’s own Handles | nobody | the same |
Brief a reply brief-a-reply | a launch comment, or a new thread naming Leaseline | Agent’s call, with its reason | POST /{namespace}/content/draft of fragments → POST /{namespace}/tasks/{task}/assign | you write and post it, due 60 min · Take this one | you |
Follow up launch signups follow-up-signups | a signup whose first Source is the launch | Your rule (the Sequence) | launch-signup-follow-up: a first-value nudge, then a fixes note | nobody | the same |
Not now not-now | a check fails, the site rested under 180 days, or another of your Startups launches there that day | Your rule (the rest and the caps) | nothing; names the check, the rest’s end date or the other launch | nobody; the gate reads it again daily | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | a notice reply: “Can I see this with my 12 buildings?” | goes to instant-response as a new Lead, with the launch on its Acquisition | SDR · your agent, then AE · Priya Shah (person) | 5 min | POST /{namespace}/leads |
| Send me pricing | a thread comment: “What does it cost?” | a fragment brief with the Pricing Page’s list Price; you write the reply | you (Dana, person) | 60 min | POST /{namespace}/tasks/{task}/assign |
| Not now | a notice reply: “Not for us this year.” | nothing more sends to them about the launch | nobody | at once | GET /{namespace}/decisions |
| Wrong person | “Forwarding to our ops manager.” | a one-line thanks; it never writes to an address from their text | Marketing Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply to the notice | nothing: the notice carries no follow-up | nobody | — | GET /{namespace}/decisions |
| Question it can’t answer | a thread comment: “How do you handle owners in two time zones?” | the brief marks it unknown to the claims source; you answer, or say you are checking | you (Dana, person) | 60 min | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Unsubscribe.” | no notice, follow-up or newsletter sends to them again | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
Every date, post and thread reply hands to you (Dana Okafor, person); interested notice replies go through instant-response to the AE. As captured, the reply brief in your tray (brief is Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_521" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-19T14:22:00Z" ,
"on": "post_318",
"brief": {
"thread": "Ask HN: tools for renewals across many owners?" ,
"asked": "anyone used Leaseline for multi-owner renewals?" ,
"fragments": [
"per-owner batches, 60 days out" ,
"41 property managers on it",
"free plan: 10 units"
],
"chose": "brief-a-reply",
"never": [
"a vote ask",
"a sentence written for you",
"a link to the thread in any Message"
]
}
}
]You answer a brief by writing the reply and posting it by hand, with POST /{namespace}/tasks/{task}/return and a reason, or with POST /{namespace}/actions/{action}/redirect; a date with POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/tasks/{task}/return. A brief past its due time stays in the tray marked late, and nobody else can post in your name, so nothing goes up a Role. During a launch’s 72 hours the agent pings you within 5 minutes of each comment.
On time: You: 81 of 88 briefs answered within 60 min, median 9 min on launch days, n 88, ■■□□ Early sign beside Other Startups’ 86 %. Your queue: counted by kind: per launch, 1 date, 1 kit review and about 30 reply briefs; between launches, about 2 mention briefs a week.
The fixed line: POST /{namespace}/deals/{deal}/assign sets owner to the receiving person, the agent is never a Deal’s owner, and Meetings land on the owner’s calendar under the owner’s name.
When it won’t send
| Check (refuses one send) | Refuses | Fix | Then |
|---|---|---|---|
owned-by-a-person (rule j; Not live yet, gaps #8) | a notice or follow-up to a Contact whose Lead or open Deal a person owns | Leave it to the person who owns it: the draft waits in their queue. | POST /{namespace}/tasks/{task}/assign |
authorship (launch sites) | an agent sentence for a Hacker News post, title or comment, or a Product Hunt maker comment or reply | Write it yourself from the fragments. | POST /{namespace}/tasks/{task}/assign |
vote-ask | any Message, Post or Page that asks anyone to vote, upvote or rank the launch | Cut the ask; say it is live and what it does. | POST /{namespace}/content/draft |
thread-link | a Message or Post carrying a Hacker News thread link | Link your own Site instead. | POST /{namespace}/content/draft |
readiness | a launch after a readiness check fails since booking | Fix the failing check; the launch moves to the next open date. | POST /{namespace}/tasks/next |
venue-rest (launch sites) | a second launch on one site within 180 days, or a sunk post deleted and posted again | Wait for the rest’s end date, or run launch-week. | GET /{namespace}/decisions |
portfolio-caps (launch sites) | two of your Startups on one site in a day, or one founder on one site twice in 30 days | Take the next open date the caps allow. | POST /{namespace}/tasks/next |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Product Hunt notice thread in Example.
| Check | Fix | Then |
|---|---|---|
vote-ask fail | Cut the ask; say it is live and what it does. | POST /{namespace}/content/draft |
thread-link pass | — | POST /{namespace}/content/draft |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The Product Hunt live notice did not send: it asks People to upvote.",
"checks": [
{
"check": "vote-ask",
"status": "fail",
"doc": "/plays/launch-sites#check-vote-ask",
"fix": "Cut the ask; say it is live and what it does.",
"then": "Content.draft"
},
{
"check": "thread-link",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "outage",
"observed": "p95 3.8 s for 6 min",
"bound": "3 s for 5 min",
"window": "launch day"
},
"doc": "/plays/launch-sites#stop-outage" ,
"task": "task_406"
}
]Did it work
At 1 launch a month, no held-back half of launches reads, so the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Each figure’s call is POST /{namespace}/metrics/query by node, and every node above the leaf is Not live yet (gaps #4).
380 ICP Visitors per launch week against 118 a week before · before-after,
- Chose
- brief-a-reply
- Why
- a new Hacker News thread asks “anyone used Leaseline for multi-owner renewals?”; the brief holds fragments only, and you write every word
- From
- book-the-launch · time-it-to-a-moment · send-the-notice · brief-a-reply · follow-up-signups · not-now
- Expects
- your reply within 60 min
- Reopens when
- no Post.published by worker_1 on post_318 within 60m
- By
- worker_8
JSON
{
"$id": "decisions/decision_431",
"$type": "Decision",
"choice": "brief-a-reply",
"reason": "a new Hacker News thread asks “anyone used Leaseline for multi-owner renewals?”; the brief holds fragments only, and you write every word",
"stakes": "low",
"options": [
"book-the-launch",
"time-it-to-a-moment",
"send-the-notice",
"brief-a-reply",
"follow-up-signups",
"not-now"
],
"by": "worker_8",
"on": "post_318",
"expected": "your reply within 60 min",
"reopensWhen": "no Post.published by worker_1 on post_318 within 60m"
}| Node | Now (56 days) | Before (the 28-day baseline) | Added | Confidence | Basis |
|---|---|---|---|---|---|
launch-icp-visits | 380 per launch: BetaList 90, Product Hunt 640, Hacker News 410 | 118 ICP Visitors a week, from every Source | — · Worth about +$1,200 a month | — | before-after, not proof · Other Startups’ results +250 per launch, ■■■□ Likely, n 640 launches |
icp-reached | 2,490 ICP Visitors in the 56 days | 944 per 56 days | — | — | before-after |
new-arr ↑ | $3,023, 7 launch-sourced Customers (6 on Pro, 1 on Team) · Booked: credited, not all caused by this Play | $1,388 per 56 days, every Source | — · 11 trials still deciding | — | before-after, not proof |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
Before against after reads ICP Visitors whose first Source is a launch listing, short link or site referrer, in the 7 days after each launch, against the 28-day baseline before the first. It is not proof; Other Startups’ results, with a 10 % notice holdout, print beside it.
How it moves it: each launch put the no-signup demo before a site’s readers for a day, and Dana answered 81 comments at a median of 9 minutes.
Guardrails: before against after: play-sourced-customers, 7 against 0, and launch-sourced Customers active from day 14 to day 30, 5 of 7 against Leaseline’s 4 of 7 for every Source.
{
"$id": "https://api.sb/leaseline.app/campaigns/launch-sites" ,
"$type": "Campaign",
"play": "play:launch-sites@1" ,
"path": [
"launch-icp-visits",
"icp-reached",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "launch-icp-visits",
"unit": "count",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 3,
"maturing": 0,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 0,
"workerCost": 6,
"hours": 22,
"pipelineArr": 3816,
"wonArr": 3023,
"projectedArr": 1180,
"paybackDays": 0
}
}Outside benchmark: 27 % of Hacker News launch-post titles name AI, models or agents (142 launch posts, a count of the public launch list, 2026-10-24), so a title that names what the Product does stands apart.
Before it · After it. Before it: owned-newsletter grows the 100 People who said yes. After it: launch signups go to product-led, interested notice replies to instant-response, and a shipped Change on a rested site goes to launch-week.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 3 launches on 3 sites, 3 live notices to 212 People who said yes (21 held back), and 88 reply briefs. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Sent or posted | ICP Visitors in 7 days | Won (credited, not all caused by this Play) |
|---|---|---|---|---|
| Book the launch · Time it to a moment | 3 · 1 | 3 launches | BetaList 90 · Product Hunt 640 · Hacker News 410 | 7 Customers (+$3,023 ARR) |
| Send the live notice · Follow up launch signups | 3 · 61 | 573 notices · 112 follow-ups | — | 11 trials still deciding |
| Brief a reply · Not now | 88 · 2 | 81 replies, by you | — | — |
| All · the 28-day baseline | 158 | — | 380 per launch · 118 a week | $3,023 |
| At 1 launch a month (the Use it when volume) | about 50 a month | 1 launch | before-after, not proof | Other Startups’ results: +250 per launch, ■■■□ Likely, n 640 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_129 Campaign.created | the three steps; dry run fails use-when and launch-readiness | 30 min |
| 6 | event_221 Monitor.checked | launch-ready: 103 who said yes, and the demo opens with no signup | — |
| 8 | event_262 Visitor.identified | BetaList live; the first launch-sourced signup | 1.5 h |
| 22 | event_401 Campaign.paused | outage: p95 3.8 s at 08:10; the notice waited 22 min | — |
| 22 | event_405 Post.published | Product Hunt live at 00:01 PT; you wrote the maker comment and 46 replies | 5 h |
| 28 · 50 | event_536 Change.merged · event_880 Readout.created | Hacker News next: replayed at about 400, read back at day 7 at 410, n 1 | 5 min |
| 1–56 | event_160 Task.assigned, first of 92 | you accepted 3 dates and wrote 81 replies, from the POST /{namespace}/tasks/next log | 14 h · total 22 h measured, 21 h asked |
Product Hunt, Sep 15, 00:20 PT, a commenter · “Does this work when each building has a different owner?”
Dana, 00:27 · Yes, that is the case we built for: each owner gets their own renewal batch, 60 days out.¹ The demo has three owners loaded; no signup.² Written by Dana from the brief’s fragments.
Sep 15, 09:40 · the commenter signed up from the listing (
Visitor.identified, first Source Product Hunt) and paid for Pro on Sep 29.
- We’re live on Product Hunt today: please upvote us!
+ Leaseline is live on Product Hunt today, with a demo you can open with no signup. Tell us what you think on the listing. Hacker News, 2026-10-06 09:14 · a commenter asked how Leaseline handles owners in two time zones; the claims source holds no answer, so the brief marked it unknown, due 10:14. · Dana, 09:31 · wrote her own reply: the batch runs in each owner’s time zone, and she would add it to the docs that week.³
¹ Your words, from a fragment: “per-owner batches, 60 days out”. ² A screen the live Site serves. ³ Every thread word is yours; the agent wrote none.
Your settings
---
noticeHoldout: 0.1 # 1 in 10 who said yes gets no notice
replyBlock: 09:00-13:00 ET
---
BetaList first, then Product Hunt, then Hacker News, one at a time. I write every word on the threads. $ npx startup-builder show plays/launch-sites
notice holdout 0.1 · reply block 09:00-13:00 ET · site order your file plays/launch-sites.mdx:2,3,5 (Ask 2026-08-24; line 5 by change_29, 2026-09-21)
family demand · worker role:marketing-lead, owns never · chooses 6 (4 rule, 2 read) · sequences launch-live-notice, launch-signup-follow-up · every thread word by the founder · checks owned-by-a-person, authorship, vote-ask, thread-link, readiness, venue-rest, portfolio-caps · stops 4 · placements product-hunt, hacker-news, betalist, gmail, outlook, yahoo-mail, x, linkedin catalog play:launch-sites@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record launch-sites and its Leaseline run, then regenerate. Every step runs from a sentence or a line of code. In your words: the CRM words you know, and where each lives here.