Organic social
Turns your own facts and shipped changes into one post a week per account, and drafts first-person posts that you send yourself.
- Channel
- Social
- Kind
- Social & video
- Summary
- startupbuilder.dev
Be our Content Lead: each week, turn one fact from our own records or one thing we shipped into a post on our LinkedIn page and our labeled X account. Draft my own LinkedIn posts from the sentences I record, for me to send. Never post an opinion to fill a slot. Show me what’s missing; don’t post.
# 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":"organic-social"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'organic-social' }, { 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":"organic-social"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'organic-social' }, { 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": "organic-social can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "3 first-party facts a week; LinkedIn page 1, 840 followers, X 620",
"doc": "/plays/ organic-social#check-use-when",
"fix": "Nothing to do: it counts new facts and shipped changes a week.",
"then": "Metric.query"
},
…
Hand our latest recorded fact to the Content Lead agent and show me what it chose and why. Don’t post.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Fact.recorded%22%2C%20%22Version.deployed%22%2C%20%22Content.drafted%22%2C%20%22Handle.mentioned%22%2C%20%22Post.published%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_1355"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22fact_31%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%22fact_31%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Fact.recorded", "Version.deployed", "Content.drafted", "Handle.mentioned", "Post.published")', 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 (\"Fact.recorded\", \"Version.deployed\", \"Content.drafted\", \"Handle.mentioned\", \"Post.published\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1355"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"fact_31\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"fact_31\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Fact.recorded\", \"Version.deployed\", \"Content.drafted\", \"Handle.mentioned\", \"Post.published\")', 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_538",
"$type": "Decision",
"choice": "post-the-fact",
"reason": "a first-party fact recorded Oct 18 from your own records: Customers sent 1, 204 renewal notices 60 days out in September, against 790 in August; Thursday’s Company Page slot is open",
"stakes": "low",
"options": [
"post-the-fact",
"draft-for-you",
"answer-the-tag",
"hand-the-angle-on",
"to-a-person",
"not-now"
…
sample · 4 Not live yetPreviewOn POST /{namespace}/processes/{process}/enableOff POST /{namespace}/processes/{process}/pauseTake this one POST /{namespace}/tasks/{task}/claim
action_3 is the 6-page document Post for Thursday 09:00, which you can stop until 08:45. action_2 adds the fact to the fact Page the Post ends at, where a reader leaves their email.
0.44 per 1,
| Try another: the fact | Choice | Reason |
|---|---|---|
| Fact: 1,204 renewal notices sent 60 days out in September, against 790 in August | post-the-fact | a fresh first-party fact; Thursday’s slot is open |
| Dana’s seed: “Most late renewals I’ve seen start with one owner who never got the notice.” | draft-for-you | a seed you recorded: a first-person draft for you to send |
| @rentops_kim tagged the X account: “Does Leaseline handle owner approvals?” | answer-the-tag | the claims source answers it: owner approvals shipped Sep 15 |
| The Sep 11 renewal-timing Post: 9 Contacts on 4,100 impressions, 4 times the account’s median | hand-the-angle-on | an outlier on Contacts; the angle goes on with its Evidence |
| Week of Oct 5: no new fact, no seed | not-now | the slot stays empty; nothing fills it with an opinion |
- 45 min week 1, then 25 a week
- Your time
- Day 4: first Contact from a Post
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Social-sourced Contacts → New Leads → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +0.25 consented Contacts per 1,000 impressions (Other Startups’ results; no lift of your own yet) × 26,000 impressions a month × 0.12 Contacts to paid × $347 Pro ARR ≈ +$271. Under First signal: At about 3 consented Contacts a week, alternating weeks cannot read, so your file reads before-after; every 6th week stays dark for the comparison Other Startups pool.
sample · api.sb/
Also runs as: Engagement bridge.
Start it this week
npx startup-builder add play organic-social # 1 · writes plays/organic-social.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":"organic-social"}'
# 3 · keep it, at You approve each one
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"organic-social"}'
# on
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/enable \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# off: scheduled Posts move back to draft
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: it counts new facts and shipped changes a week. | POST /{namespace}/metrics/query |
baseline warn · Not live yet, gaps #8 | n 4: it reads before-after, not proof, until volume allows alternating weeks. | POST /{namespace}/metrics/query |
claims-resolve fail | Publish the facts Page; a Post may state only what it lists. | POST /{namespace}/content/draft |
owned-by-a-person pass · Not live yet, gaps #8 | Nothing to do: replies there draft into your queue. | POST /{namespace}/tasks/{task}/assign |
role-unstaffed warn · Not live yet, gaps #8 | Staff the Marketing Lead, or leave it: angles and replies come to you. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "organic-social can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "3 first-party facts a week; LinkedIn page 1,840 followers, X 620",
"doc": "/plays/organic-social#check-use-when",
"fix": "Nothing to do: it counts new facts and shipped changes a week.",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "warn",
"observed": "4 consented Contacts from social in 90 days, on 36,000 impressions",
"doc": "/plays/organic-social#check-baseline",
"fix": "n 4: it reads before-after, not proof, until volume allows alternating weeks.",
"then": "Metric.query"
},
{
"check": "claims-resolve",
"status": "fail",
"observed": "no facts Page: 0 facts a Post may cite",
"doc": "/plays/organic-social#check-claims-resolve",
"fix": "Publish the facts Page; a Post may state only what it lists.",
"then": "Content.draft"
},
{
"check": "owned-by-a-person",
"status": "pass",
"observed": "2 Conversations on X claimed by you",
"doc": "/plays/organic-social#check-owned-by-a-person",
"fix": "Nothing to do: replies there draft into your queue.",
"then": "Task.assign"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"content-lead",
"marketing-lead"
],
"owned": 2,
"doc": "/plays/organic-social#check-role-unstaffed",
"fix": "Staff the Marketing Lead, or leave it: angles and 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: 3 facts a week; warn: 4 Contacts in 90 days (gaps #8) | POST /{namespace}/metrics/query on social-sourced-contacts, which fills Before in Your number | 1 min | none |
claims-resolve · fail: no facts Page | POST /{namespace}/content/draft the facts Page from your records, then POST /{namespace}/pages | 20 min | none |
owned-by-a-person · pass: 2 Conversations you claimed | nothing; it runs again on every reply | 0 min | none |
role-unstaffed · warn (gaps #8): 2 Conversations have a person owner, you | POST /{namespace}/roles/{role}/staff, or leave it: winning angles and person replies come to you | 0 min | none |
Your number · Before 0.11 per 1,
Each Post draft costs about $0.02 (Worker cost), and the voice judge and the fabrication veto about $0.01 more for a first-person draft. Posting on your own accounts costs nothing. That comes to under $1 a month at 8 Posts and 4 first-person drafts.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A first-party fact lands in your records | fact-recorded | event on Fact.recorded where source = 'first-party' | fills a slot within 14d | POST /{namespace}/content on the facts Page, or a fact from POST /{namespace}/metrics/query |
| A change your Customers can see ships | version-shipped | event on Version.deployed where visibleToCustomers = true | 72h | POST /{namespace}/versions/{version}/deploy |
| You record a raw sentence for your own profile | seed-recorded | event on Content.drafted where kind = 'seed' | 7d | POST /{namespace}/content/draft with kind seed, from chat |
+ 2 more: a tag on the agent account, and a Post that beat its account’s median on Contacts (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1355" ,
"$type": "Event",
"name": "Fact.recorded",
"at": "2026-10-18T16:40:02Z" ,
"seq": 1355,
"data": {
"fact": {
"$id": "https://api.sb/leaseline.app/facts/fact_31" ,
"text": "Leaseline Customers sent 1,204 renewal notices 60 days out in September, against 790 in August." ,
"source": "metrics/renewal-notices-sent" ,
"asOf": "2026-09-30"
}
}
}npx startup-builder trigger Fact.recorded --like event_1355 # replays the delivery in test
npx startup-builder clock advance --to thursday-09:00 # publishes the scheduled Post (action_3)
npx startup-builder listen Consent.created --forward-to http://localhost:3000/hook Who runs it
Content Lead · your agent (role:, worker_7) holds the Key Result and posts as the Startup from the Company Page and the labeled X account. It hands to you (Dana Okafor, person, worker_1) for every first-person Post, which you send, for replies that need a person, and as the Marketing Lead for winning angles, because that Role has no person. Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Post it from the Startup | It does it, you can stop it | 14 of 15 approved unedited | met on day 29 (the first 10 approved unedited, no Stop) | any Stop on the account → You approve each one | POST /{namespace}/posts/{post}/withdraw or POST /{namespace}/actions/{action}/cancel before the slot |
| Answer the tag · Not now | It does it, you can stop it | 6 of 6 · 2 of 2 | the same | a summons-flood → You approve each one | the same |
| Draft it for your profile | You approve and send each one | 7 sent of 8 drafts | never: a first-person Post is yours to send | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Hand the angle on · To a person | It does it | 2 of 2 · 3 of 3 | — | — | POST /{namespace}/actions/{action}/redirect |
| Change a slot rule | You approve each one | 1 merged of 1 | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: a like or follow ask, an outcome without the Customer’s OK, the agent as a person | Refused, every time | 1 drafted, 1 refused | never | — | none: the Check holds it |
What it reads · What it may call. It reads your facts Page, your Versions and your own seeds, and never a watched Event. The agent account never writes in the first person, and no text in a tag picks a link or a tool. Its tools are POST /{namespace}/posts/{post}/schedule, POST /{namespace}/content/draft, POST /{namespace}/approvals, POST /{namespace}/posts, POST /{namespace}/evidence, POST /{namespace}/tasks/{task}/assign, and any other call becomes an Approval under the Role’s Mandate.
You hold the Content Lead Key Result: 0.5 consented Contacts per 1,000 impressions by 2026-12-31. ← worker, metric
On each fact, Version, seed or tag, choose one option and say why. ← triggers, chooses
State only what the facts Page lists; a Customer outcome needs their OK and their words. ← copyRules 1, 3
The agent account never writes as a person or claims a feeling. ← copyRules 2
No like, repost or follow asks; no two accounts publish the same text. ← copyRules 5, 8
No fresh fact and no seed: leave the slot empty. ← chooses.not-now.when The slow loop, as a Change. decision_310 (2026-09-21, weekly) read 4 LinkedIn document Posts with 11 Contacts and 3 text Posts with 1. change_23 made the Company Page slot a document Post by default (your file, line 6), and Dana merged it with POST /{namespace}/changes/{change}/merge. Replayed on past weeks, POST /{namespace}/changes/{change}/review put the page at 0.52 per 1,000; read back at +21d it is 0.48, n 9 Contacts, ■□□□ Too early to tell (Example, day 49).
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; POST /{namespace}/roles/{role}/staff seats it.
npx startup-builder eval --scenario organic-social-48 --agent "claude -p" --seat content-lead # seated: 0 claims failed sent, 1 sameness rejection, $0.02 a Post · yours: 1 claim failed → You approve each one What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Post it from the Startup post-the-fact | a fresh fact, an open slot this week | Your rule (line 5) | publish-content → POST /{namespace}/posts/{post}/schedule, ending at the facts Page | nobody | the same |
Draft it for your profile draft-for-you | you recorded a seed | Your rule (line 7) | POST /{namespace}/content/draft (voice judge, fabrication veto) → POST /{namespace}/approvals | you approve and send it from your profile · Take this one | you |
Answer the tag answer-the-tag | someone tagged the agent account with a question the facts Page answers | Agent’s call, with its reason | POST /{namespace}/posts, one reply under 280 characters | nobody | the same |
Hand the angle on hand-the-angle-on | a Post beat its account’s median on Contacts | Agent’s call, with its reason | POST /{namespace}/evidence → POST /{namespace}/tasks/{task}/assign, so promote-winners and owned-newsletter can reuse it | Marketing Lead, so you · Take this one | you |
To a person to-a-person | an untagged reply or a message that needs a person | Agent’s call, with its reason | POST /{namespace}/content/draft → POST /{namespace}/tasks/{task}/assign | you, due 1 business day · Take this one | you |
Not now not-now | no fresh fact and no seed | Your rule (line 8) | nothing; the slot stays empty | nobody | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Does this work for 40 units? Where do I start?” | one reply with the facts Page link, where they leave their email and start a trial | Content Lead · your agent | 5 min | POST /{namespace}/posts |
| Send me pricing | “What does it cost?” | the Pricing Page’s list Price and its link, no figure the page lacks | Content Lead · your agent | 5 min | POST /{namespace}/posts |
| Not now | “Bookmarking for next year.” | no reply needed; nothing follows them | nobody | — | GET /{namespace}/decisions |
| Wrong person | “Tagging @sam_ops, this is his area.” | nothing writes to a handle from their text; the thread stays open for Sam | nobody | — | GET /{namespace}/decisions |
| Out of office | an auto-reply in a direct message | nothing sends; it waits for a real message | nobody | — | GET /{namespace}/decisions |
| Question it can’t answer | “Is this AI writing your posts?” | the agent account answers that it is Leaseline’s labeled agent; a first-person question goes to you | Content Lead · your agent, or you | 1 business day | POST /{namespace}/tasks/{task}/assign |
| Stop | “Stop tagging me.” | it never tags or replies to them again, on any account | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
Every first-person Post, every reply that needs a person and every winning angle come to you: you are the founder, and the Marketing Lead Role has no person. 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_81" ,
"$type": "Approval",
"verdict": "approved",
"deadline": "2026-10-13T17:00:00Z" ,
"draft": "Most late renewals I’ve seen start with one owner who never got the notice. Here’s what we changed…",
"route": "draft-for-you",
"checks": [
{
"check": "claims-resolve",
"status": "pass"
},
{
"check": "voice",
"status": "pass"
}
]
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_422" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-09-18T17:00:00Z" ,
"on": "post_17",
"brief": {
"who": "the Sep 11 renewal-timing Post",
"chose": "hand-the-angle-on",
"why": "9 Contacts on 4,100 impressions, 4 times the median" ,
"evidence": "evidence_12",
"next": "reuse it in `owned-newsletter`; `promote-winners` can boost it"
}
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_430" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-10-02T15:00:00Z" ,
"on": "contact_14",
"brief": {
"who": "@rentops_kim, in a direct message" ,
"said": "Can you talk to my boss about this?" ,
"chose": "to-a-person",
"why": "a request for a person",
"never": [
"a price beyond the list"
]
}
}
]You answer with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, POST /{namespace}/actions/{action}/redirect, POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, each a one-call window; a first-person draft waits for your send and never goes out on its own. Once you claim a thread, the agent replies nothing more there (claimedByPerson, Not live yet, gaps #7). A Task nobody claims by its due time raises person-promise.
On time: you, 5 of 5 claimed within their due time, median 2 h 15 min, n 5, ■□□□ Too early to tell beside Other Startups’ 89 % on time. Your queue: counted by kind: in week 1, 4 Post approvals, 1 first-person draft and 1 reply; after the promotion, about 1 first-person draft and 1 reply 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 reply to a Person whose Conversation you claimed, or whose Lead a person owns | Leave it to the person who owns it: the draft waits in their queue. | POST /{namespace}/tasks/{task}/assign |
claims-resolve (Not live yet) | a Post with a claim that resolves to no live record on the facts Page | Cut the claim, or name the record that backs it. | POST /{namespace}/content/draft |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
claims | a published claim turns out to sit outside the claims source | POST /{namespace}/posts/{post}/withdraw within 1 h; the account drops to You approve each one |
venue-warning | a Venue warning, restriction or removed label on an account | that account pauses and drops to You approve each one |
low-quality-flag | a Venue note that a Post drew low-quality or AI-content reports | drafting on that account pauses 7 days |
unfollow | unfollows within 24 h of a Post pass 0.5 % of followers | that account pauses 7 days |
sameness | three drafts in a row fail the sameness pass | drafting on that account pauses |
contact-floor | under 0.2 Contacts per 1,000 impressions after 50,000 over 60 days | the Play stops on that account |
owner-silence | no review from you for 3 business days | every draft holds at its rung |
kill-switch | you press it | POST /{namespace}/processes/{process}/pause on content-marketing; scheduled Posts move back to draft |
summons-flood | over 20 tags in an hour from accounts under 30 days old | tag replies pause 24 h |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that posted is the Sep 4 thread in Example.
| Check | Fix | Then |
|---|---|---|
claims-resolve fail | Cut the claim, or name the record that backs it. | POST /{namespace}/content/draft |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The Sep 4 Company Page Post did not schedule: one claim resolves to no record on the facts Page.",
"checks": [
{
"check": "claims-resolve",
"status": "fail",
"doc": "/plays/organic-social#check-claims-resolve",
"fix": "Cut the claim, or name the record that backs it.",
"then": "Content.draft"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "owner-silence",
"observed": "3 business days with no review",
"bound": "3 business days",
"window": "Sep 29 to Oct 1"
},
"doc": "/plays/organic-social#stop-owner-silence" ,
"task": "task_441"
}
]Did it work
At about 3 consented Contacts a week, neither a held-back half nor alternating weeks can read within 90 days, 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).
0.44 per 1,
- Chose
- post-the-fact
- Why
- a first-party fact recorded Oct 18 from your own records: Customers sent 1,204 renewal notices 60 days out in September, against 790 in August; Thursday’s Company Page slot is open
- From
- post-the-fact · draft-for-you · answer-the-tag · hand-the-angle-on · to-a-person · not-now
- Expects
- consented Contacts carrying the Post’s code within 30d
- Reopens when
- no Consent.created carrying the Post’s code within 14d: its angle is not handed on
- By
- worker_7
JSON
{
"$id": "decisions/decision_538",
"$type": "Decision",
"choice": "post-the-fact",
"reason": "a first-party fact recorded Oct 18 from your own records: Customers sent 1,204 renewal notices 60 days out in September, against 790 in August; Thursday’s Company Page slot is open",
"stakes": "low",
"options": [
"post-the-fact",
"draft-for-you",
"answer-the-tag",
"hand-the-angle-on",
"to-a-person",
"not-now"
],
"by": "worker_7",
"on": "fact_31",
"expected": "consented Contacts carrying the Post’s code within 30d",
"reopensWhen": "no Consent.created carrying the Post’s code within 14d: its angle is not handed on"
}| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
|---|---|---|---|---|---|
social-sourced-contacts | 0.44 per 1,000: 21 consented Contacts on 48,000 impressions · Booked $694 from 2 of them on Pro: credited, not all caused by this Play | 0.11: 2.5 on 22,400 | — · Worth about +$270 a month | — | before-after, not proof · Other Startups’ results +0.25 per 1,000, ■■■□ Likely, n 31 Startups |
new-leads | 133 | 101 | — | — | before-after; includes Leads this Play never touched |
new-arr ↑ | $5,210 | $3,850 | — | — | before-after |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
Before against after reads Contacts whose Consent landed within 30 days of a first Visit carrying a Post code, or whose form names a social Venue, in this window against the 90 days before it, scaled to 56 days; it is not proof. Every 6th week stays dark, so the pooled comparison across Other Startups has Leaseline’s weeks in it.
How it moves it: one fact from your own records per Post, 15 of them, each ending at the facts Page; before, 6 Posts in 90 days and none ended at a page that asked for an email (social-sourced-contacts by Post kind).
Guardrails: before against after: Contacts to paid, 2 of 21 against 0 of 4, and unfollows after a Post, a peak of 0.1 % against a 0.5 % Stop.
{
"$id": "https://api.sb/leaseline.app/campaigns/organic-social" ,
"$type": "Campaign",
"play": "play:organic-social@1" ,
"path": [
"social-sourced-contacts",
"new-leads",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "social-sourced-contacts",
"unit": "per-1000",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 21,
"maturing": 6,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 0,
"workerCost": 1,
"hours": 4.2,
"pipelineArr": 0,
"wonArr": 694,
"projectedArr": 271,
"paybackDays": 1
}
}Outside benchmark: the catalog holds none for this Play yet, so Other Startups’ results stand in: +0.25 consented Contacts per 1,000 impressions, ■■■□ Likely, n 31 Startups.
Before it · After it. Before it: data-stories, free-tools, review-requests, launch-week and founder-voice feed it facts and seeds. After it: a winning angle goes to promote-winners, and consented Contacts reach owned-newsletter and lead-nurture. engagement-bridge runs inside it as the reply step.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 24 Decisions, 15 Posts as the Startup, 7 first-person Posts you sent, 48,000 impressions and 21 consented Contacts. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Impressions | Consented Contacts | Won (credited, not all caused by this Play) |
|---|---|---|---|---|
| Post it from the Startup | 15 | 31,200 | 14 | 1 on Pro (+$347 ARR) |
| Draft it for your profile | 8 (7 sent) | 15,900 | 6 | 1 on Pro (+$347 ARR) |
| Answer the tag · Hand the angle on · To a person · Not now | 6 · 2 · 3 · 2 | 900 · — · — · — | 1 · — · — · — | 0 |
| At 2 facts a week (the Use it when volume) | about 16 Posts in 56 days | before-after, not proof | — | Other Startups’ results: +0.25 per 1,000, ■■■□ Likely, n 31 Startups |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_118 Campaign.created | the three steps; the dry run fails claims-resolve: no facts Page | 15 min |
| 0 | event_124 Page.created | the facts Page goes live with 12 facts from your records | 20 min |
| 4 | event_177 Consent.created | the first Contact from a Post: a reader of the Aug 27 notices Post | — |
| 18 | event_390 Evidence.created | the Sep 11 renewal-timing Post beat the median 4 times; its angle went to you | 5 min |
| 28 · 49 | event_560 Change.merged · event_802 Readout.created | document Posts by default on the page: replayed at 0.52 per 1,000, read back at 0.48 | 5 min |
| 29 | event_571 Role.updated | promoted: Company Page and X Posts publish unless you stop them | — |
| 36 | event_655 Campaign.paused | owner-silence: 3 business days with no review while you travelled; drafts held, nothing lost | — |
| 1–56 | event_140 Approval.created, first of 15 | you approved 15 Posts, sent 7 first-person Posts and answered 3 replies; weekly reviews, from the POST /{namespace}/tasks/next log | 3 h 30 min · total 4.2 h measured, 4 h asked |
Leaseline on LinkedIn, Sep 11, 09:00, a 6-page document · In August, Leaseline Customers sent 790 renewal notices 60 days out.¹ Page 2: the three steps teams took before the first notice went out. Page 6: the facts behind each number, with how to get the same report for your portfolio.²
Rosa Lin, a property manager, 11:40 · “We’re at 40 units and this is exactly our mess.” She opened the facts Page from the Post’s code and left her email (
Consent.created, 11:52); her trial started Sep 14 and paid on Pro Sep 29.
- Leaseline cuts late renewals by 40%.
+ Leaseline Customers sent 790 renewal notices 60 days out in August, the first month the report covers. @rentops_kim, in a direct message on X, 2026-10-01 14:10 · “Can you talk to my boss about this?” · Leaseline (agent), 14:12 · *I’m Leaseline’s agent. Dana, our founder, replies here by tomorrow 15:00.*³ The Brief went to Dana (
task_430); she replied at 09:20 the next morning and booked a call for Oct 6.
¹ One fact from the facts Page, with its month. ² The Post ends at the facts Page, where Consent is recorded. ³ The routed line, compiled from the Role’s Settings.
Your settings
---
accounts: [linkedin-page, x-agent]
dark: every 6th week
---
One Post a week per account, from one fact in our records or one thing we shipped.
On the LinkedIn page, a document Post by default.
My own LinkedIn posts start from the sentences I record, and I send them.
No fresh fact and no seed: leave the slot empty. $ npx startup-builder show plays/organic-social
accounts linkedin-page, x-agent · dark every 6th week · document Posts on the page · empty slots stay empty your file plays/organic-social.mdx:2,3,5,6,7,8 (Ask 2026-08-24; line 6 by change_23, 2026-09-21)
family social · process content-marketing · worker role:content-lead, owns never · chooses 6 (3 rule, 3 read) · approval every-send · checks owned-by-a-person, claims-resolve · stops 9 · runs engagement-bridge as its reply step catalog play:organic-social@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record organic-social 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.