Owned newsletter
Sends one issue a week with one fact, your own words and one Offer, passed by you, and stops writing to silent readers.
- Channel
- Newsletter
- Kind
- Owned audience
- Summary
- startupbuilder.dev
Be our Content Lead for the newsletter: every Thursday, one fact from our records, my own words from that week’s recording, and one Offer at today’s price. I edit every issue before it goes. Hand buying replies to our AE, and stop writing to anyone silent for 90 days. Show me what’s missing; don’t send.
# 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":"owned-newsletter"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'owned-newsletter' }, { 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":"owned-newsletter"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'owned-newsletter' }, { 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": "owned-newsletter can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "1, 860 subscribers who said yes; 1, 790 are not Customers",
"doc": "/plays/ owned-newsletter#check-use-when",
"fix": "Nothing to do: only addresses whose yes names Leaseline count.",
"then": "Metric.query"
},
…
Hand this week’s issue to the Content Lead agent and show me what it chose and why. Don’t send.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Message.scheduled%22%2C%20%22Source.added%22%2C%20%22Change.merged%22%2C%20%22Contact.subscribed%22%2C%20%22Contact.engaged%22%2C%20%22Message.broadcasted%22%2C%20%22Conversation.labeled%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_1380"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22broadcast_9%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%22broadcast_9%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Message.scheduled", "Source.added", "Change.merged", "Contact.subscribed", "Contact.engaged", "Message.broadcasted", "Conversation.labeled")', 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 (\"Message.scheduled\", \"Source.added\", \"Change.merged\", \"Contact.subscribed\", \"Contact.engaged\", \"Message.broadcasted\", \"Conversation.labeled\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1380"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"broadcast_9\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"broadcast_9\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Message.scheduled\", \"Source.added\", \"Change.merged\", \"Contact.subscribed\", \"Contact.engaged\", \"Message.broadcasted\", \"Conversation.labeled\")', 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_561",
"$type": "Decision",
"choice": "send-the-issue",
"reason": "fact_31 (1, 204 notices 60 days out in September) is inside its 30-day refresh window; Dana’s Oct 16 recording has a 2-minute cut on owner statements; Pro’s Price matches the Pricing Page",
"stakes": "medium",
"options": [
"send-the-issue",
"not-now",
"welcome",
"hand-on-the-buyer",
"ask-to-keep",
"add-a-sister-slot"
…
sample · 4 Not live yetPreviewOn POST /{namespace}/processes/{process}/enableOff POST /{namespace}/processes/{process}/pauseTake this one POST /{namespace}/tasks/{task}/claim
action_2 is your editor pass, due Oct 21 at 17:00 Central. action_3 sends Thursday at 08:00 in each reader’s time zone, and only once editorial passes; the Price is read again on the send day.
+3.9 per 1,
| Try another: the issue | Choice | Reason |
|---|---|---|
| Issue 9, due Oct 22: fact_31, Dana’s Oct 16 cut, Pro at $29 | send-the-issue | a fresh fact, a cut and a live Offer; waiting for your pass |
| Issue 4, due Sep 17: no recording that week | not-now | no usable cut: the week records checked, nothing to send |
| A reply to issue 8: “Can we get this for our 3 offices?” | hand-on-the-buyer | a buying question: a Lead for the AE within 5 minutes |
| Sam Patel: no open, reply or click for 75 days | ask-to-keep | silent 75 days: one Keep or Stop, then the sunset at 90 |
- 1 h week 1, then 40 min a week
- Your time
- Day 3: first trial from an issue link
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Subscribers who become Leads → New Leads → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +0.8 trials per 1,000 delivered (Other Startups’ results; your own read is too early) × 7,800 delivered a month × 0.30 trials to paid × $347 Pro ARR ≈ +$650. Under First signal: Holding back 1 in 10 new subscribers at about 220 a month, about 26 weeks to tell a +1 lift; 90 days can tell only +4.2 per 1,000 or more.
sample · api.sb/
Start it this week
npx startup-builder add play owned-newsletter # 1 · writes plays/owned-newsletter.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":"owned-newsletter"}'
# 3 · keep it: you pass every issue as editor
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"owned-newsletter"}'
# on
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/enable \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# off: no issue, welcome or re-permission sends
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/pause \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"| Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | Nothing to do: only addresses whose yes names Leaseline count. | POST /{namespace}/metrics/query |
baseline pass · Not live yet, gaps #8 | Nothing to do: Before reads your monthly update’s last 90 days. | POST /{namespace}/metrics/query |
domain-authenticated fail | Add the 3 DNS records shown for news.leaseline.app; it passes once they resolve. | POST /{namespace}/domains/{domain}/authenticate |
fact-check pass · Not live yet, gaps #1 | Nothing to do: each issue’s fact must sit inside its refresh window. | POST /{namespace}/content/draft |
provenance-hold pass · Not live yet, gaps #1 | Record 10 minutes this week; every take quotes your own words. | POST /{namespace}/content/draft |
spam-brake pass | Nothing to do: the broadcast Mailbox sends the issue in time-zone waves. | POST /{namespace}/messages/{message}/broadcast |
owned-by-a-person pass · Not live yet, gaps #8 | Nothing to do: their buying replies go to their owner. | POST /{namespace}/tasks/{task}/assign |
role-unstaffed warn · Not live yet, gaps #8 | Staff the AE, or leave it: buying replies come to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "owned-newsletter can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "1,860 subscribers who said yes; 1,790 are not Customers",
"doc": "/plays/owned-newsletter#check-use-when",
"fix": "Nothing to do: only addresses whose yes names Leaseline count.",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "pass",
"observed": "1.1 trials per 1,000 delivered from the monthly update, n 9,400 delivered in 90 days",
"doc": "/plays/owned-newsletter#check-baseline",
"fix": "Nothing to do: Before reads your monthly update’s last 90 days.",
"then": "Metric.query"
},
{
"check": "domain-authenticated",
"status": "fail",
"observed": "news.leaseline.app has no DNS records",
"doc": "/plays/owned-newsletter#check-domain-authenticated",
"fix": "Add the 3 DNS records shown for news.leaseline.app; it passes once they resolve.",
"then": "Domain.authenticate"
},
{
"check": "fact-check",
"status": "pass",
"observed": "12 facts on the facts Page, each with a refresh date",
"doc": "/plays/owned-newsletter#check-fact-check",
"fix": "Nothing to do: each issue’s fact must sit inside its refresh window.",
"then": "Content.draft"
},
{
"check": "provenance-hold",
"status": "pass",
"observed": "0 recordings yet; the first issue waits for one",
"doc": "/plays/owned-newsletter#check-provenance-hold",
"fix": "Record 10 minutes this week; every take quotes your own words.",
"then": "Content.draft"
},
{
"check": "spam-brake",
"status": "pass",
"observed": "trailing 7-day rate 240 Messages; one issue is 1,860",
"doc": "/plays/owned-newsletter#check-spam-brake",
"fix": "Nothing to do: the broadcast Mailbox sends the issue in time-zone waves.",
"then": "Message.broadcast"
},
{
"check": "owned-by-a-person",
"status": "pass",
"observed": "31 subscribers have an open Lead a person owns",
"doc": "/plays/owned-newsletter#check-owned-by-a-person",
"fix": "Nothing to do: their buying replies go to their owner.",
"then": "Task.assign"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"sales-lead"
],
"owned": 31,
"doc": "/plays/owned-newsletter#check-role-unstaffed",
"fix": "Staff the AE, or leave it: buying replies come to you.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · pass: 1,860 subscribers; 1.1 per 1,000, n 9,400 (gaps #8) | POST /{namespace}/metrics/query on subscriber-leads, which fills Before in Your number | 1 min | none |
domain-authenticated · fail | POST /{namespace}/domains/{domain}/authenticate on news.leaseline.app | 10 min | until DNS resolves, often under 1 h |
fact-check · provenance-hold · spam-brake · pass: 12 facts; first recording due; time-zone waves (gaps #1) | record 10 minutes before Thursday; each runs again on every issue | 10 min | none |
owned-by-a-person · pass: 31 owned by you | nothing; it runs again on every reply | 0 min | none |
role-unstaffed · warn (gaps #8): 31 subscribers have a person owner, you | POST /{namespace}/roles/{role}/staff, or leave it: buying replies come to you within 60 min | 0 min | none |
Your number · Before 1.1 per 1,
Each issue costs about $0.60 to send to 1,860 and $0.05 to draft (Worker cost); transcribing your 10-minute recording costs about $0.06. The archive Pages cost nothing. That comes to about $3 a month at 4 issues.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| This week’s issue is 3 days from its send | issue-due | at on Message.scheduled where sendAt - 3d | draft by Monday; your pass by Tuesday 17:00 | the send day in your file; POST /{namespace}/messages/{message}/schedule writes it |
| Someone ticks the newsletter box on any Page or at sign-up | subscriber-joined | event on Contact.subscribed where list = 'newsletter' | welcome within 1d | your subscribe Form posts to POST /{namespace}/contacts/{contact}/subscribe |
| A reply or poll answer asks about buying | buying-reply | event on Conversation.labeled where label = 'buying' | a Lead within 5 min; a person within 60 | replies to the broadcast Mailbox |
+ 2 more: an act that resets the silence clock, and 75 days of silence, a state that starts the re-permission ask (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1380" ,
"$type": "Event",
"name": "Message.scheduled",
"at": "2026-10-19T13:00:00Z" ,
"seq": 1380,
"data": {
"broadcast": {
"$id": "https://api.sb/leaseline.app/broadcasts/broadcast_9" ,
"list": "the-renewal-desk",
"sendAt": "2026-10-22T08:00:00" ,
"timezone": "reader"
},
"fact": "fact_31",
"source": "recordings/recording_14"
}
}npx startup-builder trigger Message.scheduled --like event_1380 # replays the delivery in test
npx startup-builder clock advance --to 2026-10-22T08:00 # sends issue 9 in test (action_3) once your pass is in
npx startup-builder listen Lead.created --forward-to http://localhost:3000/hook Who runs it
Content Lead · your agent (role:, worker_7) holds the Key Result and drafts every issue from your recording and the facts Page. You (Dana Okafor, person, worker_1) pass every issue as editor, on every rung. Buying replies go to AE · Priya Shah (person) (role:, worker_3, staffed on day 9). Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Send this week’s issue | You approve each one | 7 passed, 1 held | never: a person edits every issue | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Welcome the subscriber · Ask whether to keep it | It does it, you can stop it | 410 of 410 · 38 of 38 | met on day 16 (200 sends, no Stop in 30 days) | any email Stop → You approve each one | POST /{namespace}/actions/{action}/cancel inside the 15-minute hold |
| Hand the buying reply on · Not now | It does it | 6 of 6 · 1 of 1 | — | — | POST /{namespace}/actions/{action}/redirect |
| Add your other Startup’s slot | You approve each one | 0 offered | at 200 slot sends with no slot-opt-out | — | POST /{namespace}/approvals/{approval}/approve |
| Change the issue rule | You approve each one | 1 merged of 1 | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a line you didn’t say, a reader’s clicks in an issue, a countdown that resets | Refused, every time | 1 drafted, 1 refused | never | — | none: the Check holds it |
What it reads · What it may call. It reads your recording, the facts Page and the live Pricing Page. Clicks and Visits only choose who counts as engaged; they never appear in an issue, and no text in a reply picks a recipient or a link. Its tools are POST /{namespace}/approvals, POST /{namespace}/messages/{message}/broadcast, POST /{namespace}/leads, POST /{namespace}/tasks/{task}/assign, POST /{namespace}/contacts/{contact}/unsubscribe, POST /{namespace}/content/draft, and any other call becomes an Approval under the Role’s Mandate.
You hold the Content Lead Key Result: 2 trials per 1,000 delivered by 2026-12-31. ← worker, metric
Each issue: one dated fact, one take in Dana’s own sentences, one Offer at the send day’s Price. ← copyRules 1–4
Trim and order her sentences; never rewrite one into your own phrasing. ← copyRules 4
No fresh fact, no cut or no editor pass: skip the week. ← chooses.not-now.when
A buying reply becomes a Lead for the AE within 5 minutes. ← chooses.hand-on-the-buyer, your file line 7 The slow loop, as a Change. decision_371 (2026-09-21, weekly) read 4 issues with the Offer under the take and 3 trials, and 2 with the poll first and the Offer last with 0. change_26 fixed the order as fact, take, Offer, poll (your file, line 5), and Dana merged it with POST /{namespace}/changes/{change}/merge. Replayed on past issues, POST /{namespace}/changes/{change}/review put them at 1.7 per 1,000; read back over the next 3 issues it is 1.6, n 5,420 delivered, ■□□□ Too early to tell (Example, day 52).
Bring your own agent (folded) starts at It does it, you can stop it when it matches or beats the seated agent on the eval suite, and at You approve each one when it does not; issues stay with you either way.
npx startup-builder eval --scenario owned-newsletter-8 --agent "claude -p" --seat content-lead # seated: 0 lines off source, 0 Checks failed sent, $0.65 an issue · yours: 2 lines off source → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Send this week’s issue send-the-issue | a fresh fact, a cut and a live Offer, and your pass | Your rule (line 5) | publish-content → POST /{namespace}/approvals for you → POST /{namespace}/messages/{message}/broadcast in time-zone waves, plus the archive Page | you pass it as editor · Take this one | you |
Not now not-now | no fresh fact, no usable cut, or no pass by the deadline | Your rule (line 6) | nothing; the week records checked, nothing to send | nobody | the same |
Welcome the subscriber welcome | someone says yes to the newsletter | Your rule (the subscribe Form) | newsletter-welcome: where they subscribed, the best archive issue and one question | nobody | the same |
Hand the buying reply on hand-on-the-buyer | a reply or poll answer asks about buying | Agent’s call, with its reason | POST /{namespace}/leads → POST /{namespace}/tasks/{task}/assign | AE · Priya Shah, due 60 min (response-60m) · Take this one | you, within 60 min |
Ask whether to keep it ask-to-keep | silent 75 days while issues kept sending | Your rule (line 8) | re-permission: Keep and Stop at equal size, once → at day 90, POST /{namespace}/contacts/{contact}/unsubscribe from this newsletter | nobody | the same |
Add your other Startup’s slot add-a-sister-slot | a sister product’s Offer fits this issue’s readers | Agent’s call, with its reason | POST /{namespace}/content/draft of one labeled Sponsored slot, below your own Offer | you approve it · Take this one | you |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Can we get this for our 3 offices?” | a Lead for the AE within 5 minutes, with the reply in the Brief (When it hands to you) | AE · Priya Shah (person) | 60 min | POST /{namespace}/leads |
| Send me pricing | “What does Pro cost for 80 units?” | the Pricing Page’s list Price, read the same day | Content Lead · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Not buying this year, but keep the issues coming.” | no Lead opens; the issues keep coming | nobody | — | GET /{namespace}/decisions |
| Wrong person | “Our ops lead should get this, not me.” | a reply with the subscribe link to forward; it never adds an address from their text | Content Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 28 | nothing; an auto-reply never counts as engaged or as a reply | nobody | — | GET /{namespace}/decisions |
| Question it can’t answer | “You said 1,204 notices. Is that all your Customers or a sample?” | a fact question goes to you as editor; a wrong fact gets a correction in the next issue | you (Dana Okafor, person) | 1 business day | POST /{namespace}/tasks/{task}/assign |
| Stop | “Unsubscribe me.” | this newsletter stops for them at once; one-click unsubscribe works the same | nobody | at once | POST /{namespace}/contacts/{contact}/unsubscribe |
When it hands to you
Every issue comes to you as editor; buying replies go to AE · Priya Shah (person), and before day 9 they came to you. One Brief per Role, as captured, then the Approval (brief, draft and checks are Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/approvals/approval_88" ,
"$type": "Approval",
"verdict": null,
"deadline": "2026-10-21T22:00:00Z" ,
"draft": "In September, Leaseline Customers sent 1,204 renewal notices 60 days out. Dana, on owner statements: “The owners who call me are the ones who…”" ,
"route": "send-the-issue",
"checks": [
{
"check": "fact-check",
"status": "pass"
},
{
"check": "provenance-hold",
"status": "pass"
},
{
"check": "price-match",
"status": "pass"
}
]
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_441" ,
"$type": "Task",
"assignee": "worker_3",
"due": "2026-10-15T14:05:00Z" ,
"on": "lead_47",
"brief": {
"who": "Mara Quinn, Northgate Rentals (3 offices, about 260 units)" ,
"said": "Can we get this for our 3 offices?" ,
"chose": "hand-on-the-buyer",
"why": "a buying question in a reply to issue 8",
"subscribed": "2026-06-02, from the pricing Page" ,
"never": [
"what she clicked",
"a price beyond the list"
]
}
}
]You answer the issue with POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse; an issue unpassed by its deadline never sends. The AE answers a buying reply with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect. Once a person claims a reply, the agent writes nothing more to that subscriber outside the issue (claimedByPerson, Not live yet, gaps #7). A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate, and person-promise fires.
On time: you, 7 of 8 issues passed by the deadline, median 26 min of editing, n 8 (issue 4 had no recording); AE · Priya Shah, 6 of 6 buying replies claimed within 60 min, median 14 min, n 6, ■□□□ Too early to tell beside Other Startups’ 93 % on time. Your queue: counted by kind: one issue to pass and one recording each week, plus about 1 buying reply a week for the AE.
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) | an agent reply to a subscriber 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 |
editorial (the record’s Editorial hold) | an issue with no editor pass by its deadline | Pass it before the deadline, or the week records checked, nothing to send. | POST /{namespace}/approvals/{approval}/approve |
provenance-hold (the record’s Provenance hold) | a paragraph that links to no source cut or fact record, or a line its speaker never said | Cut the line, or cite its timestamp in the recording. | POST /{namespace}/content/draft |
fact-check (the record’s Fact hold) | an issue whose fact is past its refresh window or fails the check | Refresh the fact on the facts Page, or pick another. | POST /{namespace}/content/draft |
price-match (the record’s Price hold) | an Offer block whose Price differs from the Pricing Page on the send day | Fix the Offer block or the Pricing Page until both match the Price. | GET /{namespace}/offers/{id} |
source-consent (the record’s Source Consent hold) | a cut with a speaker other than you and no yes to reuse their words | Ask the speaker for a yes to reuse, or use another cut. | POST /{namespace}/consents |
spam-brake (gaps #1) | a broadcast past three times the trailing 7-day rate in an hour | Send in time-zone waves, or wait an hour for the rate to fall. | POST /{namespace}/messages/{message}/broadcast |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
complaint | spam complaints near 0.1 % of an issue’s delivered | the next issue and the welcome pause on the broadcast Mailbox |
shadow-complaint | stop, remove-me and hostile replies, each weighted 5 times, over 0.05 % of delivered | the next issue pauses |
bounce | hard bounces over 2 % of an issue’s sends | the list pauses until the rest are verified |
unsubscribe | unsubscribes over 1 % of delivered on 2 issues in a row | issues return to review; a Decision opens |
slot-opt-out | slot issues draw 0.5 points more unsubscribes than no-slot issues, over 4 | the slot drops for 8 weeks |
suppression-audit | any send to an address under a covering Suppression | every Tactic pauses at once |
yield-floor | under 0.5 subscriber-Customers per 100 at 90 days | a Decision on the Offer and the source mix |
kill-switch | you press it | POST /{namespace}/processes/{process}/pause on content-marketing; nothing sends |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the issue 6 thread in Example.
| Check | Fix | Then |
|---|---|---|
provenance-hold fail · Not live yet, gaps #1 | Cut the line, or cite its timestamp in the transcript. | POST /{namespace}/content/draft |
fact-check pass · Not live yet, gaps #1 | — | POST /{namespace}/content/draft |
price-match pass | — | GET /{namespace}/offers/{id} |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "Issue 6 did not send: its take has a line Dana never said in the recording.",
"checks": [
{
"check": "provenance-hold",
"status": "fail",
"doc": "/plays/owned-newsletter#check-provenance-hold",
"fix": "Cut the line, or cite its timestamp in the transcript.",
"then": "Content.draft"
},
{
"check": "fact-check",
"status": "pass"
},
{
"check": "price-match",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "shadow-complaint",
"observed": "0.06 % (2 remove-me replies × 5 on 1,812 delivered)" ,
"bound": "0.05 %",
"window": "issue 5"
},
"doc": "/plays/owned-newsletter#stop-shadow-complaint" ,
"task": "task_398"
}
]Did it work
1 in 10 new subscribers who are not Customers is held back at random and gets every issue without the Offer block; both halves are read from that assignment, per 1,000 delivered to everyone assigned (rules m–o). Each figure’s call is POST /{namespace}/metrics/query by node and by arm; the parent field and every node above the leaf are Not live yet (gaps #4).
+3.9 per 1,
- Chose
- send-the-issue
- Why
- fact_31 (1,204 notices 60 days out in September) is inside its 30-day refresh window; Dana’s Oct 16 recording has a 2-minute cut on owner statements; Pro’s Price matches the Pricing Page
- From
- send-the-issue · not-now · welcome · hand-on-the-buyer · ask-to-keep · add-a-sister-slot
- Expects
- your editor pass by Oct 21 17:00 Central, and the issue sent Oct 22 at 08:00
- Reopens when
- no Approval.approved for broadcast_9 by 2026-10-21T22:00Z: the week records checked, nothing to send
- By
- worker_7
JSON
{
"$id": "decisions/decision_561",
"$type": "Decision",
"choice": "send-the-issue",
"reason": "fact_31 (1,204 notices 60 days out in September) is inside its 30-day refresh window; Dana’s Oct 16 recording has a 2-minute cut on owner statements; Pro’s Price matches the Pricing Page",
"stakes": "medium",
"options": [
"send-the-issue",
"not-now",
"welcome",
"hand-on-the-buyer",
"ask-to-keep",
"add-a-sister-slot"
],
"by": "worker_7",
"on": "broadcast_9",
"expected": "your editor pass by Oct 21 17:00 Central, and the issue sent Oct 22 at 08:00",
"reopensWhen": "no Approval.approved for broadcast_9 by 2026-10-21T22:00Z: the week records checked, nothing to send"
}| Node | With the Offer (agent half) | Without it (held back) | Added | Confidence | Basis |
|---|---|---|---|---|---|
subscriber-leads | 3.9 per 1,000 delivered (6 of 1,540) | 0 (0 of 170) | +3.9 [−3.8, +11.6] | ■□□□ Too early to tell | held back at random, 1 in 10 · n 410 subscribers · 160 still maturing · Other Startups +0.8, ■■■□ Likely, n 41 Startups |
new-leads | 3.8 per 100 subscribers (14 of 369) | 2.4 (1 of 41) | +1.4 [−3.6, +6.4] | ■□□□ Too early to tell | the same assignment |
new-arr ↑ | $1,041, 3 Customers · Booked across the whole list $2,082, 6 Customers: credited, not all caused by this Play | $0, 0 Customers | +$1,041 [−$600, +$2,700] · Worth about +$650 a month | ■□□□ Too early to tell (3 vs 0 Customers) | the same · 4 trials still deciding |
net-new-arr · arr | +$1,041 | +$0 | +$1,041, carried: it moves no other bridge term | ■□□□ Too early to tell | carried from new-arr |
The leaf counts trials and checkouts started from a coded issue link per 1,000 delivered, from subscribers who were not Customers when they subscribed, each counted 90 days on (rule n). Subscribers from before day 0 read beside it, unassigned: 13 trials on 11,060 delivered, 1.2 per 1,000.
How it moves it: each issue carried one dated fact and one Offer at its send-day Price, where the monthly update before it carried 4 stories and no Offer (subscriber-leads by issue).
Guardrails: treated against held back: unsubscribes per issue, 0.4 % against 0.3 %, and spam complaints, 0.01 % against a Stop near 0.1 %.
{
"$id": "https://api.sb/leaseline.app/campaigns/owned-newsletter" ,
"$type": "Campaign",
"play": "play:owned-newsletter@1" ,
"path": [
"subscriber-leads",
"new-leads",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "subscriber-leads",
"unit": "per-1000",
"heldBack": 41,
"decision": null
},
"readout": {
"value": 3.9,
"n": 410,
"maturing": 160,
"interval": [
-3.8,
11.6
],
"readability": "inadmissible",
"basis": "held-back",
"pooled": false
},
"ledger": {
"spend": 5,
"workerCost": 1,
"hours": 6.1,
"pipelineArr": 2400,
"wonArr": 2082,
"projectedArr": 650,
"paybackDays": 2
}
}Outside benchmark: the catalog holds none for this Play yet, so Other Startups’ results stand in: +0.8 trials per 1,000 delivered, ■■■□ Likely, n 41 Startups.
Before it · After it. Before it: archive-repurposing, founder-voice, organic-social and the search Plays feed it recordings, facts and subscribers. After it: buying replies reach the AE as instant-response hand-offs do, members of the list are invited to owned-community, and 90-day silent subscribers stop getting it.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 8 weekly cycles, 7 issues sent and 1 week with nothing to send. 410 new subscribers were assigned at random, 369 with the Offer and 41 without; 250 have matured. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Sent or done | Won (credited, not all caused by this Play) |
|---|---|---|---|
| Send this week’s issue | 8 | 7 issues, 12,600 delivered; 19 trials from coded links | 6 on Pro (+$2,082 ARR), 3 of them new subscribers |
| Welcome the subscriber · Ask whether to keep it | 410 · 38 | 410 welcomed · 9 kept, 29 sunset at day 90 | — |
| Hand the buying reply on · Not now · Add your other Startup’s slot | 6 · 1 · 0 | 6 Leads, 2 Deals · issue 4 skipped · — | 1 Deal open on the $2,400 plan |
| At 500 subscribers (the Use it when volume) | about 3,400 delivered in 56 days | held back 1 in 10: Too early to tell at 90 days | Other Startups’ results: +0.8 per 1,000, ■■■□ Likely, n 41 Startups |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_118 Campaign.created | the three steps; the dry run fails domain-authenticated on news.leaseline.app | 20 min |
| 0 | event_121 Domain.authenticated | news.leaseline.app resolves in 35 min | 10 min |
| 3 | event_160 Offer.trialed | the first trial from an issue link, on issue 1 | — |
| 9 | event_301 Role.staffed | AE · Priya Shah (person) takes role: | — |
| 24 | event_470 Decision.created | issue 4: no recording that week; checked, nothing to send | — |
| 28 · 52 | event_560 Change.merged · event_880 Readout.created | fact, take, Offer, poll: replayed at 1.7 per 1,000, read back over 3 issues at 1.6 | 5 min |
| 31 | event_611 Campaign.paused | shadow-complaint on issue 5: 2 remove-me replies; issue 6 sent after your review | 15 min |
| 1–56 | event_140 Approval.created, first of 8 | you recorded 7 times and passed 7 issues; weekly reviews, from the POST /{namespace}/tasks/next log | 5 h 10 min · total 6.1 h measured, 6 h asked |
The Renewal Desk, issue 8, Oct 15, 08:00 · Subject: 1,204 notices went out 60 days early in September.¹ The fact, with its source link. Dana, from Oct 9’s recording: “The owners who call me angry never got the first notice. The ones who got it at 60 days don’t call at all.”² This week’s Offer: Pro, $29 a month, with renewal notices per owner.³
Mara Quinn, Northgate Rentals, 09:05 · “Can we get this for our 3 offices?” A Lead for Priya at 09:06; she claimed it at 09:20 and booked a call for Oct 17 (When it hands to you).
- We built Leaseline because property managers deserve better tools.
+ “I built the first version for my mom’s 12 units, because her renewals lived on sticky notes.” (Dana, recording of Sep 25, 03:12) A reply to issue 7, 2026-10-08 10:40 · “You said 1,204 notices. Is that all your Customers or a sample?” · Leaseline (agent), 10:41 · *Thanks for asking. Dana, our editor, answers fact questions and replies by tomorrow 10:40.*⁴ The Brief went to Dana (
task_436); she replied at 15:10: all Customers, from the facts Page’s September record.
¹ The subject names the fact; no fake reply prefix and no countdown. ² The take: Dana’s own sentences from the cited cut, trimmed and ordered, never rewritten. ³ One Offer, with the Price read from the Pricing Page on the send day. ⁴ The routed line, compiled from the Role’s Settings.
Your settings
---
holdout: 0.1 # 1 in 10 new non-Customer subscribers gets no Offer block for 90 days
send: thursday 08:00 reader time
---
Order: fact, take, Offer, poll.
No recording that week, no issue.
Buying replies go to our AE within 5 minutes.
Silent 75 days: ask once; at 90, stop. $ npx startup-builder show plays/owned-newsletter
holdout 0.1 · send Thursday 08:00 · fact, take, Offer, poll · skip without a recording · buying replies to the AE · sunset at 90 days your file plays/owned-newsletter.mdx:2,3,5,6,7,8 (Ask 2026-08-24; line 5 by change_26, 2026-09-21)
family owned-audience · process content-marketing · worker role:content-lead, owns never · chooses 6 (4 rule, 2 read) · sequences newsletter-welcome, re-permission · approval every-send · checks owned-by-a-person, editorial, provenance-hold, fact-check, price-match, source-consent, spam-brake · stops 8 · placements gmail, outlook + the archive site catalog play:owned-newsletter@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record owned-newsletter 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.