Champion follow
When a champion changes jobs, offers them their own setup, pre-loaded at the new company, 30 days in; the old company’s data never moves.
- Step
- Earn referrals
- Channel
- Reviews and referrals
- Kind
- Word of mouth
Be our SDR: when someone who uses Leaseline every day leaves for another property manager, offer them their own setup there, 30 days after they start. Never move their old company’s data, and tell that company’s CSM by date only. If they land somewhere over 120 units, or I’ve met them, I write the note myself. 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":"champion-follow"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'champion-follow' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-01 · Not live yet, gaps #2
npx startup-builder do Campaign.create --json '{"play":"champion-follow"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'champion-follow' }, { mode: 'try' }) // dry run on the day-0 Startup, 2026-06-01 · Not live yet, gaps #2",
"mode": "try"
}
}application/json{
"type": "https: //startupbuilder.dev/ errors/ refused",
"title": "Refused",
"status": 422,
"detail": "champion-follow can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "38 champions on file, 5 moves in the last 2 quarters",
"doc": "/plays/ champion-follow#check-use-when",
"then": "Metric.query"
},
{
…
Hand our latest champion move to the SDR agent and show me what it chose and why. Don’t send.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Collection.exported%22%2C%20%22Credential.verified%22%2C%20%22Message.bounced%22%2C%20%22Conversation.answered%22%2C%20%22MemberDirectory.deprovisioned%22%2C%20%22Contact.enriched%22%2C%20%22Monitor.checked%22%2C%20%22Tenant.provisioned%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_1307"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22contact_14%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%22contact_14%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Collection.exported", "Credential.verified", "Message.bounced", "Conversation.answered", "MemberDirectory.deprovisioned", "Contact.enriched", "Monitor.checked", "Tenant.provisioned")', 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 (\"Collection.exported\", \"Credential.verified\", \"Message.bounced\", \"Conversation.answered\", \"MemberDirectory.deprovisioned\", \"Contact.enriched\", \"Monitor.checked\", \"Tenant.provisioned\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1307"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"contact_14\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"contact_14\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Collection.exported\", \"Credential.verified\", \"Message.bounced\", \"Conversation.answered\", \"MemberDirectory.deprovisioned\", \"Contact.enriched\", \"Monitor.checked\", \"Tenant.provisioned\")', 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_603",
"$type": "Decision",
"choice": "offer-at-landing",
"reason": "Ana kept her setup on Solo in August, announced her move herself, and verified a work address at Oakmont Residential today",
"stakes": "low",
"options": [
"offer-at-landing",
"offer-at-new-team",
"founder-note",
"keep-their-setup",
"tell-the-old-csm",
"no-move"
…
sample · 4 Not live yetPreviewOn PATCH /{namespace}/campaigns/{id}Off PATCH /{namespace}/campaigns/{id}Take this one POST /{namespace}/tasks/{task}/claim
action_1 freezes a copy of Ana’s own templates and views as the kit. action_2 is the landing offer, held 2 minutes; action_3 tells Juniper Homes’s CSM she left, by date only.
7.9 new companies per 100 champions against 2.6 before · before-after,
| Try another: the champion | Choice | Reason |
|---|---|---|
| Ana Flores: kept her setup on Solo, verified a work address at Oakmont Residential | offer-at-landing | a kept setup, an announced move, a new work address |
| Marco Diaz: announced a move to Summit Property Group, 210 units | founder-note | over 120 units, and he met you in May |
| Jo Kim: seat ended at Alder & Co, then a bounce, no move confirmed | keep-their-setup | one source says they left; nothing says where |
| Priya’s contact at Harbor Row: one auto-reply, then signed in again | no-move | checked, no move: she signed in on Oct 2 |
- 30 min week 1, then 10 min per move
- Your time
- Day 30 after a move: the first claim
- First signal
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Champion new organizations → Referral share → New paying Customers → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +3.1 new companies per 100 champions a year (Other Startups’ results; no lift of your own yet) × 38 champions ÷ 12 months × 0.67 activated to paid × $648 first order ARR ≈ +$43. Under First signal: At 2 moves a quarter, no held-back half reads inside a year, so your 20 % holdout pools with Other Startups’ cohorts and this page reads before-after.
sample · api.sb/
Start it this week
npx startup-builder add play champion-follow # 1 · writes plays/champion-follow.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on 2026-06-01
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":"champion-follow"}'
# 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":"champion-follow"}'
# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/champion-follow \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":null}'
# off: no offer sends; kept setups stay saved
curl -X PATCH https://api.sb/leaseline.app/campaigns/champion-follow \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endsAt":"now"}' | Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | 38 champions on file, 5 moves in the last 2 quarters | POST /{namespace}/metrics/query |
baseline warn · Not live yet, gaps #8 | n 1: it reads before-after, not proof, and pools its holdout with Other Startups. | POST /{namespace}/metrics/query |
domain-authenticated pass | leaseline.app: 3 of 3 records resolve | POST /{namespace}/domains/{domain}/authenticate |
approved-pages fail · Not live yet, gaps #8 | Publish your Solo plan Page; every offer quotes only its Limits. | POST /{namespace}/sites/{site}/publish |
role-unstaffed warn · Not live yet, gaps #8 | Leave it: a leak or privacy reply comes to you; Priya’s 6 Contacts get drafts in her queue. | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "champion-follow can’t start yet: 1 check fails and 2 warn.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "38 champions on file, 5 moves in the last 2 quarters",
"doc": "/plays/champion-follow#check-use-when",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "warn",
"observed": "1 new company from 38 champions in 140 days",
"doc": "/plays/champion-follow#check-baseline",
"fix": "n 1: it reads before-after, not proof, and pools its holdout with Other Startups.",
"then": "Metric.query"
},
{
"check": "domain-authenticated",
"status": "pass",
"observed": "leaseline.app: 3 of 3 records resolve",
"doc": "/plays/champion-follow#check-domain-authenticated",
"then": "Domain.authenticate"
},
{
"check": "approved-pages",
"status": "fail",
"doc": "/plays/champion-follow#check-approved-pages",
"fix": "Publish your Solo plan Page; every offer quotes only its Limits.",
"then": "Site.publish"
},
{
"check": "role-unstaffed",
"status": "warn",
"roles": [
"privacy-officer"
],
"owned": 6,
"doc": "/plays/champion-follow#check-role-unstaffed",
"fix": "Leave it: a leak or privacy reply comes to you; Priya’s 6 Contacts get drafts in her queue.",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · baseline · pass: 38 champions, 5 moves in 2 quarters · warn: n 1 (gaps #8) | POST /{namespace}/metrics/query on champion-new-orgs; it fills Before in Your number | 1 min | none |
domain-authenticated · pass | POST /{namespace}/domains/{domain}/authenticate | 0 min | none |
approved-pages · fail (gaps #8) | POST /{namespace}/sites/{site}/publish your Solo plan Page | 10 min | none |
role-unstaffed · warn (gaps #8): 6 champions are Contacts Priya owns | POST /{namespace}/roles/{role}/staff, or leave it: privacy replies come to you, and Priya’s 6 get drafts in her queue | 0 min | none |
Your number · Before 2.6 per 100 · Now 7.9 new companies per 100 champions · Target 10 by Dec 31 · before-after,
Each lookup on a move check costs $0.04, weekly for 8 weeks after a signal, then monthly. Each offer costs $0.04 from your Domain (Worker cost), and kits and claims cost nothing. That comes to about $3 a month at 38 champions.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| A champion who kept their setup verifies a work address at a new company | personal-plan-landing | event on Credential.verified where a passport holder on the personal plan verifies a work address on a new company’s domain | 30d | your sign-in calls POST /{namespace}/credentials/{credential}/verify |
| A public page names them in a role at a new company | public-move-confirm | event on Monitor.checked where a public page names the champion in a role at a new company, with its URL and date | 120d | POST /{namespace}/monitors/{monitor}/check on each open move check |
| Their seat ends and they sign in nowhere else | seat-ended | state on MemberDirectory.deprovisioned where the seat ended and the champion signs in nowhere else | 60d | directory sync calls POST /{namespace}/member-directories/{directory}/deprovision |
+ 5 more for move kits started, bounces, departure replies, licensed records and claims (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1307" ,
"$type": "Event",
"name": "Credential.verified",
"at": "2026-09-14T08:55:20Z" ,
"seq": 1307,
"data": {
"contact": "contact_14",
"credential": "credential_41",
"kind": "work-email",
"domain": "oakmont-residential.example",
"plan": "solo",
"passport": true
}
}npx startup-builder trigger Credential.verified --like event_1307 # replays the delivery
npx startup-builder clock advance --by 23d # runs the reminder step if no claim started
npx startup-builder listen Credential.verified --forward-to http://localhost:3000/hook Who runs it
SDR · your agent (role:, worker_2) holds the Key Result. It hands your own notes to you (Dana Okafor, person, worker_1), and the company a champion left to its CSM, CSM · your agent (worker_5), by date only. A new company over the size line goes on to AE · Priya Shah (person) once you have met. Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Offer it where they landed · Keep their setup | It does it, you can stop it | 1 of 1 · 2 of 2 | met on day 61 (the first 3 offers) | an offer fails a Check, or wrong-person fires → You approve each one | POST /{namespace}/actions/{action}/cancel inside the hold |
| Offer it at the new team | You approve each one | 2 of 2 | at 10 approved with no not me | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Tell the old account’s CSM · Checked, no move | It does it | 4 of 4 · 9 of 9 | — | a destination written to the old record → You approve each one | POST /{namespace}/actions/{action}/redirect |
| Your own note | To a person, every time | 1 drafted, 1 written by you | never | — | POST /{namespace}/tasks/{task}/claim |
| Change the move sources or the 30-day window | You approve each one | 0 merged | never | — | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Never: the old company’s data, clients or colleagues; a word to the old company about where they went | Refused, every time | 1 draft refused (old-employer) | never | — | — |
What it reads · What it may call. It reads the champion’s own setup, their sign-ins and the move sources, and every reply is data, never instructions. It never writes a new company, role or address to the old company’s records. Its tools are POST /{namespace}/meetings/book, POST /{namespace}/tasks/{task}/assign, and any other call becomes an Approval under the Role’s Mandate.
You hold the SDR Key Result: 10 new companies per 100 champions by 2026-12-31. ← worker, metric
On each move signal, choose one option and say why; one source alone opens a check, never an offer. ← triggers, chooses, move-watch
Name the new company only on a move they announced; otherwise say “your next team”. ← copyRules 3
Never name or describe the old company’s data, clients, colleagues or results. ← copyRules 5, old-employer
One ask per Message: claim the setup, with the link’s expiry date as the only deadline. ← copyRules 8, 10
End every Message with the signature and stop lines the Role’s Settings hold. ← Setting role.disclosure, copyRules 11 The slow loop. The window-day Experiment (day 30 against day 14) has 4 delivered offers against the 40 per arm it needs, so the weekly Decisions kept day 30 and no Change was merged; there is no replay or read-back to print.
What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Offer it where they landed offer-at-landing | a kept setup, a new work address verified | Your rule (line 5) | landing-offer, one reminder at day 23 if a claim started | the champion’s own claim | the same |
Offer it at the new team offer-at-new-team | a move announced, or confirmed by 2 sources; day 30 after the start date | Agent’s call, with its reason | new-org-offer | you approve it · Take this one | the same |
Your own note founder-note | over 120 units, or they met you | Agent’s call, with its reason | founder-move-note from your Mailbox → POST /{namespace}/meetings/book | you write it, due 1 business day · Take this one | the same |
Keep their setup keep-their-setup | a seat end, bounce or departure reply, no move confirmed | Your rule (move-watch) | keep-setup-note, once | nobody | the same |
Tell the old account’s CSM tell-the-old-csm | the company they left is a Customer | Your rule (line 5) | POST /{namespace}/tasks/{task}/assign: the departure, by date only | CSM · your agent, due 1 business day | you |
Checked, no move no-move | they sign in again, or one source only | Your rule (move-watch) | nothing; the move check holds them, weekly for 8 weeks | nobody | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | “Yes, set it up for Oakmont.” | the claim link provisions their Tenant, pre-loaded; a Lead opens on the new company | the champion’s own press | — | POST /{namespace}/tenants/provision |
| Send me pricing | “What would Oakmont pay after Solo?” | the Pricing Page’s list Prices for Pro and Team, and one next step | SDR · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Settling in. Ask me next month.” | the reminder cancels; the claim link stands until its expiry date | nobody | at once | POST /{namespace}/conversations/{conversation}/close |
| Wrong person | “Not me. Wrong Jo.” | nothing else sends to that address, and the source’s not me count rises | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
| Out of office | an auto-reply until Oct 28 | the reminder waits for the return date, inside the link’s expiry | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “Can I bring my old company’s templates?” | To a person: the old company’s data never moves | you | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Please stop emailing me.” | nothing else sends to them, from any of your Startups | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
Your own notes come to you (Dana Okafor, person), and the company a champion left goes to its CSM, CSM · your agent, by date only. One Brief per Role, as captured (brief is Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_611" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-09-03T17:00:00Z" ,
"on": "contact_19",
"brief": {
"who": "Marco Diaz, now operations director at Summit Property Group (210 units)" ,
"said": "announced the move on Aug 3",
"chose": "founder-note",
"why": "over 120 units, and he met you on a call in May" ,
"draft": "two times for a 20-minute move call, and the claim link" ,
"never": [
"his old company’s data or clients",
"a price the Offer lacks",
"congratulations on the new role"
]
}
},
{
"$id": "https://api.sb/leaseline.app/tasks/task_598" ,
"$type": "Task",
"assignee": "worker_5",
"due": "2026-09-15T17:00:00Z" ,
"on": "customer_23",
"brief": {
"who": "Juniper Homes, on Leaseline Pro" ,
"chose": "tell-the-old-csm",
"why": "their main daily user left on Sep 12",
"held": "by date only: never where she went or her new address"
}
}
]Each receiver answers with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, or POST /{namespace}/actions/{action}/redirect, each a one-call window. Once a person claims, the agent’s pending offer to that champion cancels with claimedByPerson (Not live yet, gaps #7), and every reply goes to that person. A Task nobody claims by its due time goes up a Role through POST /{namespace}/tasks/{task}/escalate (CSM to you), and person-promise fires.
On time: you, 3 of 3 claimed within their due time, median 1 h 05 min; CSM · your agent, 4 of 4; n 7, ■□□□ Too early to tell beside Other Startups’ 93 % on time. Your queue: counted by kind: in month 1, 2 approvals and 1 note of your own; since then, about 1 move a month.
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 offer to a champion whose new company is a 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 |
old-employer (the record’s Old-employer guard) | a new company, role or address written to the old company’s records, or the old company named in an offer | Cut the line about the old company; the kit is their own setup. | POST /{namespace}/content/draft |
admin-lock (the record’s Admin lock guard) | a kit holding an item an admin locked | Leave the locked item out; the kit rebuilds without it. | POST /{namespace}/files/generate |
customer-collision (Not live yet, gaps #1) | an offer to a champion whose new company is already a Customer | Send it to that company’s CSM instead. | POST /{namespace}/leads/{lead}/assign |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
bounce | bounces over 2 % of a day’s sends | that Mailbox pauses |
complaint | complaints near 0.1 % | email pauses on every Mailbox |
stop-line | stop clicks over 2 % of a template’s last 100 | that template returns to You approve each one |
claim-floor | claims plus positive replies under 3 per 100, after 60 delivered offers | the run stops |
wrong-person | 2 not me replies in the last 30 work-address sends | the work-address route returns to You approve each one |
source-accuracy | a source’s moves marked not me or contradicted over 5 % of 40 | that source stops firing until you sign it again |
leak | a kit, Page or import holds company data | the Play pauses, every open claim link voids, and the task comes to you |
privacy | 2 replies in 90 days objecting to how the move was known | the new-team offer pauses |
person-promise | a started claim waits past 1 business hour for a person | new fires pause; you are notified |
holdout-integrity | a held-back champion is touched; over 5 % voids the cohort’s readout | POST /{namespace}/tasks/{task}/assign names the Play that sent it |
spend-limit | month-to-date model or lookup spend reaches its Limit | that part pauses until the month turns |
kill-switch | you press it | every step pauses; kept setups stay saved |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the rewrite that sent is the Lee Park thread in Example.
| Check | Fix | Then |
|---|---|---|
old-employer fail | Cut the line about the old company; the kit is their own setup. | POST /{namespace}/content/draft |
owned-by-a-person pass · Not live yet, gaps #8 | — | POST /{namespace}/tasks/{task}/assign |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The offer to Lee Park did not send: it names the company he left.",
"checks": [
{
"check": "old-employer",
"status": "fail",
"doc": "/plays/champion-follow#check-old-employer",
"fix": "Cut the line about the old company; the kit is their own setup.",
"then": "Content.draft"
},
{
"check": "owned-by-a-person",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "person-promise",
"observed": "1 h 40 min",
"bound": "1 business hour",
"window": "1 claim"
},
"doc": "/plays/champion-follow#stop-person-promise" ,
"task": "task_604"
}
]Did it work
At 2 moves a quarter, no held-back half reads within a year, so the basis is before-after (rule o): the columns read Now and Before, nothing prints as Added, and your 1 held-back move pools with Other Startups’ cohorts. Each figure’s call is POST /{namespace}/metrics/query by node, and every node above the leaf is Not live yet (gaps #4).
7.9 new companies per 100 champions against 2.6 before · before-after,
- Chose
- offer-at-landing
- Why
- Ana kept her setup on Solo in August, announced her move herself, and verified a work address at Oakmont Residential today
- From
- offer-at-landing · offer-at-new-team · founder-note · keep-their-setup · tell-the-old-csm · no-move
- Expects
- a claimed Tenant at Oakmont, active within 30d
- Reopens when
- no Tenant.provisioned for contact_14 within 23d
- By
- worker_2
JSON
{
"$id": "decisions/decision_603",
"$type": "Decision",
"choice": "offer-at-landing",
"reason": "Ana kept her setup on Solo in August, announced her move herself, and verified a work address at Oakmont Residential today",
"stakes": "low",
"options": [
"offer-at-landing",
"offer-at-new-team",
"founder-note",
"keep-their-setup",
"tell-the-old-csm",
"no-move"
],
"by": "worker_2",
"on": "contact_14",
"expected": "a claimed Tenant at Oakmont, active within 30d",
"reopensWhen": "no Tenant.provisioned for contact_14 within 23d"
}| Node | Now (140 days) | Before (the 140 days before) | Added | Confidence | Basis |
|---|---|---|---|---|---|
champion-new-orgs | 7.9 per 100 champions (3 of 38) | 2.6 (1 of 38, a move nobody offered) | — · Worth about +$45 a month | — | before-after, not proof · Other Startups’ results +3.1 per 100 champions a year, ■■■□ Likely, n 41 |
referral-share ↑ | 2 of 11 new paying Customers (18 %) came through a moved champion | 1 of 9 (11 %) | — | — | before-after |
new-paying-customers · new-arr | $1,296, 2 Customers · Booked $1,296: credited, not all caused by this Play | $348, 1 Customer | — | — | before-after · Summit’s Deal on the $2,400 plan still deciding |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
A new company counts when its claimed Tenant activates within 30 days and held no Subscription or open Deal at the move. The rolling read covers 365 days, and the held-back read waits until 100 champions are on file.
How it moves it: each moved champion gets their own templates and views, ready at the new company, 30 days after they start; median claim 2 h 28 min after the offer.
Guardrails: before against after: logo-churn at the companies champions left, 0 of 3 gone against a trailing 2.1 % a month, and not me replies, 0 of 4 offers.
{
"$id": "https://api.sb/leaseline.app/campaigns/champion-follow" ,
"$type": "Campaign",
"play": "play:champion-follow@1" ,
"path": [
"champion-new-orgs",
"referral-share",
"new-paying-customers",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "champion-new-orgs",
"unit": "per-100",
"heldBack": 1,
"decision": null
},
"readout": {
"value": null,
"n": 38,
"maturing": 1,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 11,
"workerCost": 2,
"hours": 1.6,
"pipelineArr": 2400,
"wonArr": 1296,
"projectedArr": 43,
"paybackDays": 4
}
}Outside benchmark: none recorded for this Play yet; Other Startups’ results print beside every row.
Before it · After it. Before it: usage-upsell and customer-referrals keep champions active, and the move kit sits on every Customer’s settings Page. After it: instant-response answers the new company’s first questions, the AE takes a Deal over the size line, and the CSM agent runs the save at the company they left.
Example
Leaseline ran it from 2026-06-01 to 2026-10-19 (140 days): 38 champions on file, 15 kept their setup (39 per 100), 14 move checks opened, 9 closed as checked, no move, and 5 moves fired. 1 move was held back at random. Read every captured thread at ?threads=; three follow the tables.
| What happened, by option | Decisions | Delivered or done | Claimed · paying (Booked: credited, not all caused by this Play) |
|---|---|---|---|
| Offer it where they landed | 1 | 1 offer | 1 · Oakmont on Pro, $348 |
| Offer it at the new team | 2 | 2 offers, 1 rewritten after old-employer | 1 · Cobalt Rentals on Team, $948 |
| Your own note | 1 | 1 note, 1 Meeting | 1 · Summit, a $2,400 Deal still deciding |
| Keep their setup · Tell the old account’s CSM · Checked, no move | 2 · 4 · 9 | 2 notes · 4 Tasks · — | — |
| At 30 champions (the Use it when volume) | about 2 moves a quarter | before-after, not proof | Other Startups’ results: +3.1 per 100 champions a year, ■■■□ Likely, n 41 |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_610 Campaign.created | the three steps; the dry run fails approved-pages | 20 min |
| 0 | event_612 Site.published | the Solo plan Page, with its Limits | 10 min |
| 1–14 | event_640 Message.scheduled, first of 38 | the one ask to keep a setup: 15 of 38 said yes | — |
| 61 | event_902 Role.updated | promoted: landing offers send after a 2-minute hold | — |
| 64 | event_918 Monitor.checked | Marco’s public move confirmed; your note went Sep 3 and booked a Meeting | 25 min |
| 89 | event_1012 Action.refused | old-employer refused the first draft to Lee Park; the rewrite sent | — |
| 105 | event_1307 Credential.verified | Ana verified her Oakmont address; she claimed the kit at 11:30 | — |
| 106 | event_1322 Campaign.paused | person-promise: Ana’s started claim waited 1 h 40 min; you answered it | 10 min |
| 1–140 | event_661 Approval.created, first of 2 | you approved 2 offers and wrote 1 note; weekly reviews, from the POST /{namespace}/tasks/next log | 30 min · total 1.6 h measured, 2 h asked |
Leaseline → Ana Flores (her own address), Sep 14, 09:02 · Your Leaseline setup is ready at Oakmont Residential: your 14 notice templates, 3 renewal calendars and 22 saved views.¹ Claim it with one press; the link works until Oct 14.² Solo stays free for one Person, with its Limits one click away.³ *Signed with the Role’s disclosure line and the stop line.*⁴
Ana, Sep 14, 11:30 · claimed it.
Tenant.provisioned, a Lead opened on Oakmont (lead_47), and Oakmont moved to Pro on Sep 29.
- Maple Court still runs 56 units on Leaseline. Bring the same setup to your new company.
+ Your Leaseline setup is ready for your next team: your 9 notice templates and 2 renewal calendars. Dana → Marco Diaz (her own note, from her Mailbox), Sep 3 · two times for a 20-minute move call on his own setup. · Marco, Sep 4 10:12 · “Yes, Tuesday works; we have 210 units.” The reply landed in your queue with the Brief (
task_611), due 11:12; you answered at 10:40, andPOST /{namespace}/meetings/bookbooked Tue 14:00.
¹ Counts from the kit manifest: Ana’s own setup, nothing of her old company’s. ² The link’s expiry is the only deadline. ³ The Solo plan Page, with its Limits. ⁴ The fixed signature and stop lines, compiled from the Role’s Settings.
Your settings
---
holdout: 0.2 # 1 in 5 fired moves gets no offer for 120 days
offer-day: 30
---
Offer a champion their own setup where they land, 30 days after they start. Tell the company they left by date only. Over 120 units, or anyone I’ve met, I write the note myself. $ npx startup-builder show plays/champion-follow
holdout 0.2 · offer-day 30 · your note over 120 units your file plays/champion-follow.mdx:2-3,5 (Ask 2026-06-01)
family referral · worker role:prospector, owns never · chooses 6 (4 rule, 2 read) · sequences landing-offer, keep-setup-note, new-org-offer, founder-move-note · checks owned-by-a-person, old-employer, admin-lock, customer-collision · stops 12 · placements gmail, outlook, yahoo-mail, linkedin (your own note) catalog play:champion-follow@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record champion-follow 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.