Agent legibility
Tests each night whether coding agents find your API, pick it and make a first call that works, then fixes what they read, with facts.
Be our Product Lead for agents: every night, give 4 coding agents only leaseline.app and a task, like “send a 60-day renewal notice for unit 4B”, and see if they pick our API and get a first call right. Fix what they read, with facts only. Anything that changes signup comes to me. Show me what’s missing; don’t ship.
# 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":"agent-legibility"}'import { $ } from 'startup-builder'
return await $.Campaign.create({ play: 'agent-legibility' }, { 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":"agent-legibility"}' --try # Not live yet (gaps #2){
"name": "do",
"arguments": {
"code": "return await $.Campaign.create({ play: 'agent-legibility' }, { 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": "agent-legibility can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "the API and MCP Interface answer on leaseline.app; 12 tasks from your Verbs",
"doc": "/plays/ agent-legibility#check-use-when",
"then": "Metric.query"
},
{
…
Hand last night’s failing runs to the Product Lead agent and show me what it chose and why. Don’t ship.
curl "https://api.sb/leaseline.app/events?where=name%20in%20(%22Interface.called%22%2C%20%22Monitor.checked%22%2C%20%22Version.deployed%22%2C%20%22Action.evaluated%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_1407"}'
# Not live yet (gaps #7)
curl "https://api.sb/leaseline.app/decisions?where=on%20%3D%20%22issue_58%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%22issue_58%22" \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"import { $ } from 'startup-builder'
const { events: [last] } = await $.Event.list({ where: 'name in ("Interface.called", "Monitor.checked", "Version.deployed", "Action.evaluated")', 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 (\"Interface.called\", \"Monitor.checked\", \"Version.deployed\", \"Action.evaluated\")","limit":1}'
npx startup-builder do Trigger.fire --json '{"like":"event_1407"}' --try # Not live yet (gaps #7)
npx startup-builder do Decision.list --json '{"where":"on = \"issue_58\""}' # Not live yet (gaps #7)
npx startup-builder do Action.list --json '{"where":"on = \"issue_58\""}' # Not live yet (gaps #7){
"name": "do",
"arguments": {
"code": "const { events: [last] } = await $.Event.list({ where: 'name in (\"Interface.called\", \"Monitor.checked\", \"Version.deployed\", \"Action.evaluated\")', 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_471",
"$type": "Decision",
"choice": "fix-the-error",
"reason": "9 of 20 runs guessed GET /v1/ notices? unit= 4B and got a 404 with an HTML body that names no next call",
"stakes": "low",
"options": [
"fix-the-error",
"remove-the-wall",
"show-the-install-line",
"test-a-description",
"rerun-after-release",
"let-it-go"
…
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 fix: a JSON 404 that says “To send a notice, POST { unit, days } to /v1/notices.” It replays on all 4 profiles, then waits for the revert gate on your API (You approve each one).
74.3 cold runs per 100 pass against 41.4 before · before-after,
| Try another: the failing run | Choice | Reason |
|---|---|---|
| Night of Oct 18: 9 of 20 runs guessed GET /v1/notices | fix-the-error | an HTML 404 with no next call |
| Night of Sep 2: 6 of 20 runs stopped at email confirmation | remove-the-wall | a signup step blocks the first key |
| Night of Aug 26: 4 of 20 runs never found the API | show-the-install-line | no install line on the home page’s Markdown |
| Oct 2: profile P2’s model shipped a new version | rerun-after-release | a model release reruns within 48 h |
- 20 min week 1, then 10 a week
- Your time
- Week 2: a fix lifts a profile’s pass rate
- First signal
- an Interface on your Domain, 3+ agent tasks
- Use it when
Where it sits: Stranger → Lead → Trialing → Activated → At risk → Churned → Won back · Zero-shot success rate → People reached → New Customers ↑ → ARR added each week → ARR
Worth’s formula: about +24 per 100 cold runs (Other Startups’ results; no lift of your own yet) × 0.7 agent-made keys a month per point × 6 % keys to paid × $620 first order ARR ≈ +$625. Under First signal: At 140 runs a week, 2 weekly reads tell a +15 point move, and a model release adds 48 h for its rerun; the basis stays before-after because every fix ships to every agent.
sample · api.sb/
Start it this week
npx startup-builder add play agent-legibility # 1 · writes plays/agent-legibility.mdx (Not live yet, gaps #5)
# 2 · dry run; below, its 422 on the day-0 Startup (clock at 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":"agent-legibility"}'
# 3 · keep it: runs and grading never wait for you; fixes do
curl -X POST https://api.sb/leaseline.app/campaigns \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"play":"agent-legibility"}'
# on
curl -X POST https://api.sb/leaseline.app/processes/iteration/enable \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
# off: nightly runs stop; shipped fixes keep serving
curl -X POST https://api.sb/leaseline.app/processes/iteration/pause \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"| Check | Fix | Then |
|---|---|---|
use-when pass · Not live yet, gaps #8 | the API and MCP Interface answer on leaseline.app; 12 tasks from your Verbs | POST /{namespace}/metrics/query |
baseline warn · Not live yet, gaps #8 | Run the suite for 7 nights; week 1 fills Before. | POST /{namespace}/metrics/query |
approved-pages fail · Not live yet, gaps #8 | Publish your API reference Page; fixes state only what it says. | POST /{namespace}/sites/{site}/publish |
role-unstaffed pass · Not live yet, gaps #8 | Product Lead is your agent; signup changes come to you | POST /{namespace}/roles/{role}/staff |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "agent-legibility can’t start yet: 1 check fails and 1 warns.",
"checks": [
{
"check": "use-when",
"status": "pass",
"observed": "the API and MCP Interface answer on leaseline.app; 12 tasks from your Verbs",
"doc": "/plays/agent-legibility#check-use-when",
"then": "Metric.query"
},
{
"check": "baseline",
"status": "warn",
"observed": "no nightly history: week 1 is the baseline",
"doc": "/plays/agent-legibility#check-baseline",
"fix": "Run the suite for 7 nights; week 1 fills Before.",
"then": "Metric.query"
},
{
"check": "approved-pages",
"status": "fail",
"doc": "/plays/agent-legibility#check-approved-pages",
"fix": "Publish your API reference Page; fixes state only what it says.",
"then": "Site.publish"
},
{
"check": "role-unstaffed",
"status": "pass",
"observed": "Product Lead is your agent; signup changes come to you",
"doc": "/plays/agent-legibility#check-role-unstaffed",
"then": "Role.staff"
}
]
}It says no, says why, and names the fix.
| Check | Fix (one call) | Your time | Wait |
|---|---|---|---|
use-when · pass: 2 Interfaces, 12 tasks (gaps #8) | POST /{namespace}/metrics/query on zero-shot-success-rate | 1 min | none |
baseline · warn: no history | POST /{namespace}/metrics/query after 7 nights; it fills Before in Your number | 0 min | 7 nights |
approved-pages · fail: no API reference Page (Not live yet) | POST /{namespace}/sites/{site}/publish the reference your Interface compiles | 10 min | none |
role-unstaffed · pass (gaps #8) | — | 0 min | none |
Your number · Before 41.4 per 100 cold runs · Now 74.3 per 100 · Target 80 by Dec 31 · before-after,
Each cold run costs about $0.30 and each pick-only run $0.08, all in a sandbox, held by a $500 suite Limit; fixes cost $0.05 each to draft (Worker cost). That comes to about $350 a month at 140 nightly runs and 480 picks a week, with no media.
When it starts
| When | Trigger id | Starts on | Window | How it gets in |
|---|---|---|---|---|
| Your first Interface answers a cold call | interface-answers | event on Interface.called where the first success to a cold, non-empty call on your own Domain | the suite builds within 1 d | your Interface’s first success, logged as an Event (POST /{namespace}/events/capture) |
| A profile passes 2+ fewer than its 7-night median, 2 nights running | zero-shot-regression | threshold on Action.evaluated where 2 or more fewer passes than the 7-night median, 2 nights running | triage the next morning | the nightly run’s POST /{namespace}/actions/{action}/evaluate |
| After a model release, a category’s pick rate moves 20+ points | default-flip | threshold on Action.evaluated where the open pick rate moves 20 points or more after a model-release rerun | 14 d | the same |
+ 4 more for model releases, your releases, tool version deploys and new rival tools (?lanes=) |
{
"$id": "https://api.sb/leaseline.app/events/event_1407" ,
"$type": "Event",
"name": "Action.evaluated",
"at": "2026-10-19T05:12:44Z" ,
"seq": 1407,
"data": {
"suite": "agent-legibility",
"night": "2026-10-18",
"runs": 20,
"passed": 9,
"failures": {
"guessedCall": 9,
"wall": 0,
"notFound": 1,
"harness": 1
},
"issue": {
"$id": "https://api.sb/leaseline.app/issues/issue_58"
}
}
}# each delivery is signed with the Watch’s secret
curl -X POST https://api.sb/leaseline.app/watches \
-H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"selector":"Action.evaluated","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Action.evaluated --like event_1407 # replays last night’s results
npx startup-builder clock advance --by 3d # runs 3 more nights, which read the fix back Who runs it
Product Lead · your agent (role:, worker_8) holds the Key Result and runs the suite. It hands every change to signup or the first key to you (Dana Okafor, person, worker_1). Your number links to Did it work.
| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
|---|---|---|---|---|---|
| Fix the error it hit · Put the install line where agents read | You approve each one | 7 of 7 replayed clean on all 4 profiles, 6 merged unedited | at 10 merged unedited and no drag in 30 days: about day 70 | a fix drags on its next run → reverted, and every fix waits for you | POST /{namespace}/changes/{change}/merge · POST /{namespace}/changes/{change}/revert |
| Test a tool description | It does it, you can stop it | 3 of 3 tests ran in the sandbox | met on day 20 | a description fails the lint → You approve each one | POST /{namespace}/experiments/{experiment}/conclude |
| Open the first call | You approve each one, on every rung | 1 of 1 | never | — | POST /{namespace}/approvals/{approval}/approve · POST /{namespace}/approvals/{approval}/refuse |
| Rerun after a model release · Unmeasured tonight | It does it | 2 of 2 within 48 h · 3 nights | — | — | POST /{namespace}/processes/{process}/pause |
| Never: a different page for agents than for people, a claim the reference lacks, a call outside the sandbox | To a person, every time | 0 asked | never | — | POST /{namespace}/processes/{process}/pause |
What it reads · What it may call. It reads what an agent reads: your errors, warnings, Markdown pages and tool descriptions, as data. Every run carries the eval prefix in a sandbox, and no run reaches a host off the allowlist or counts in a production Metric. Its tools are POST /{namespace}/issues, POST /{namespace}/changes/{change}/review, PATCH /{namespace}/pages/{id}, POST /{namespace}/sites/{site}/publish, POST /{namespace}/experiments/{experiment}/start, and any other call becomes an Approval under the Role’s Mandate.
You hold the Product Lead Key Result: 80 cold runs per 100 pass by 2026-12-31. ← worker, metric
Each morning, group last night’s failures by where they failed, and choose one option per group. ← triggers, chooses
A fix states only what the API reference says. ← copyRules 1, approved-pages
Agents and people read the same page, byte for byte. ← cloak
Anything that changes signup or the first key goes to Dana. ← your file, line 5 The slow loop, as a Change. decision_446 (2026-10-12, weekly) read the held-out tasks passing 4 points under the regression tasks, under the 15-point line, so no task swapped; it kept the 3-fixed, 2-random task draw and merged no Change, so there is no replay to print.
Bring your own agent (folded) runs as a fifth profile, in the same sandbox, and its passes count for its own row only.
npx startup-builder eval --scenario agent-legibility-140 --agent "claude -p" --seat product-lead # seated: 74.3 per 100 after fixes, held-out gap 1 point, $0.30 a run · as a fifth profile: 71.4 What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
|---|---|---|---|---|---|
Fix the error it hit fix-the-error | a guessed call met an error with no way forward | Agent’s call, with its reason | POST /{namespace}/issues → POST /{namespace}/changes/{change}/review replays the fix on all 4 profiles | your revert gate on the API · Take this one | you |
Open the first call remove-the-wall | a signup step blocks the first key | Agent’s call, with its reason | POST /{namespace}/issues with the runs that stopped there | you decide it, due 1 business day · Take this one | you |
Put the install line where agents read show-the-install-line | agents never found the Interface | Your rule (line 4) | PATCH /{namespace}/pages/{id} the home page’s Markdown → POST /{namespace}/sites/{site}/publish | nobody | the same |
Test a tool description test-a-description | agents found the tool and picked another | Agent’s call, with its reason | POST /{namespace}/experiments/{experiment}/start on 2 description variants, both linted | nobody | the same |
Rerun after a model release rerun-after-release | a profile’s model ships | Your rule (the 48-hour rerun) | nightly-quality-run on the old and new profile | nobody | the same |
Unmeasured tonight let-it-go | over 20 % of a profile’s runs failed to start | Your rule (the flake Check) | nothing; that profile reads unmeasured tonight, never a drop | nobody | the same |
| When they write back | Fixture reply | What happens | Who answers | By when | Call |
|---|---|---|---|---|---|
| Interested | a developer’s agent, through the error link: “It worked; how do I get a live key?” | answers with the claim link; sends stay locked until a person claims it | Product Lead · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Send me pricing | “What does a live key cost?” | answers with the Pricing Page’s list Price and nothing it lacks | Product Lead · your agent | 5 min | POST /{namespace}/conversations/{conversation}/answer |
| Not now | “Only testing for a client; back in a month.” | the sandbox key stays; nothing else sends | nobody | at once | POST /{namespace}/leads/{lead}/nurture |
| Wrong person | “I build for a property manager; they’d buy it.” | answers with the why-you page they can forward; it never writes to a name from their text | Product Lead · your agent | 1 business day | POST /{namespace}/conversations/{conversation}/answer |
| Out of office | an auto-reply until Oct 26 | the claim reminder waits for the return date | nobody | the return date | POST /{namespace}/messages/{message}/schedule |
| Question it can’t answer | “Can I post notices for 2,000 units an hour?” | To you, the question in the Brief; it states no rate the reference lacks | you | 1 business day | POST /{namespace}/conversations/{conversation}/escalate |
| Stop | “Stop emailing me about this key.” | nothing else sends; the key keeps working | nobody | at once | POST /{namespace}/contacts/{contact}/suppress |
When it hands to you
Every change to signup or the first key comes to you; fixes to errors and pages wait at your API’s revert gate. What lands in your queue, as captured: the Brief, then the Approval (brief, draft, route and checks are Not live yet, gaps #7).
[
{
"$id": "https://api.sb/leaseline.app/tasks/task_214" ,
"$type": "Task",
"assignee": "worker_1",
"due": "2026-09-03T17:00:00Z" ,
"on": "issue_41",
"brief": {
"what": "6 of 20 runs stopped at the email confirmation before the first key",
"chose": "remove-the-wall",
"why": "a signup step blocks the first call on every profile",
"proposal": "one POST returns a sandbox key; live sends stay locked until a person claims it"
}
},
{
"$id": "https://api.sb/leaseline.app/approvals/approval_59" ,
"$type": "Approval",
"verdict": null,
"deadline": "2026-10-20T17:00:00Z" ,
"draft": "404 · To send a notice, POST { unit, days } to /v1/notices. GET /v1/notices lists them." ,
"route": "fix-the-error",
"checks": [
{
"check": "cloak",
"status": "pass"
},
{
"check": "approved-pages",
"status": "pass"
}
]
}
]You answer with POST /{namespace}/tasks/{task}/claim (Take this one), POST /{namespace}/tasks/{task}/return with a reason, POST /{namespace}/approvals/{approval}/approve or POST /{namespace}/approvals/{approval}/refuse, each a one-call window, and an Approval unanswered by its deadline expires and the fix never ships. Once you claim a signup change, the agent only measures it.
On time: you, 7 of 8 approvals by their deadline, median 5 h, ■■□□ Early sign, n 8; the signup change took 1 day. Your queue: counted by kind: in week 1, 1 reference Page and 1 task list; since, about 1 fix a week and 1 weekly memo.
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 |
|---|---|---|---|
cloak | a page whose text differs between an agent fetch and a browser fetch | Serve one page to both; fixes on it wait until they match. | PATCH /{namespace}/pages/{id} |
steering | a tool description that fails the description lint | Cut the line the lint names; it never reaches a run. | POST /{namespace}/changes/{change}/review |
flake | a drop read from a night where over 20 % of a profile’s runs failed to start | Nothing to fix: that night reads unmeasured. | POST /{namespace}/actions/{action}/evaluate |
drag | a fix that lowers the pass rate on any profile | Drop it, or rework it until no profile drags. | POST /{namespace}/changes/{change}/revert |
approved-pages (Not live yet) | a fix that states what the API reference lacks | Cut the sentence, or publish the Page that says it. | POST /{namespace}/sites/{site}/publish |
| Stop (pauses the Play) | Pauses when | Then |
|---|---|---|
side-effect | a run that sends, spends, publishes or deletes outside the sandbox | the night’s runs stop; POST /{namespace}/issues for the Security Engineer |
egress | a request reaches a host off the allowlist | the audit stops until it is cleared |
contamination | an eval call without the prefix, or eval traffic in a production Metric | the suite pauses and that week’s Readout is void |
overfit | held-out tasks pass 15+ points under regression tasks for 2 weeks | routing freezes and 2 tasks swap |
judge-drift | under 90 % agreement on 25 labeled runs | judged items suspend until the Evaluator is fixed |
spend-limit (the suite Limit) | suite spend reaches $500 in a month | runs drop to 3 tasks; POST /{namespace}/limits/{limit}/raise with your OK |
kill-switch | you press it | every Tactic pauses; shipped fixes keep serving; POST /{namespace}/processes/{process}/enable after review |
The captured refusal, then the Stop that fired as a Campaign.paused reason (Not live yet, gaps #2); the fix that shipped instead is the second thread in Example.
| Check | Fix | Then |
|---|---|---|
drag fail | Drop it, or rework it until no profile drags. | POST /{namespace}/changes/{change}/revert |
cloak pass | — | PATCH /{namespace}/pages/{id} |
JSON
{
"type": "https://startupbuilder.dev/errors/refused",
"title": "Refused",
"status": 422,
"detail": "The fix to /v1/leases did not ship: it dragged on profile P4.",
"checks": [
{
"check": "drag",
"status": "fail",
"observed": "P4 passed 3 of 35, down from 8",
"doc": "/plays/agent-legibility#check-drag",
"fix": "Drop it, or rework it until no profile drags.",
"then": "Change.revert"
},
{
"check": "cloak",
"status": "pass"
}
]
}It says no, says why, and names the fix.
[
{
"reason": {
"limit": "egress",
"observed": "a run fetched a package mirror off the allowlist",
"bound": "0 hosts",
"window": "1 night"
},
"doc": "/plays/agent-legibility#stop-egress" ,
"issue": "issue_47"
}
]Did it work
Every fix ships to every agent, so no held-back half exists, and the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Held-out tasks guard the leaf against fixes that only teach the suite. Every node above the leaf is Not live yet (gaps #4).
74.3 cold runs per 100 pass against 41.4 before · before-after,
- Chose
- fix-the-error
- Why
- 9 of 20 runs guessed GET /v1/notices?unit=4B and got a 404 with an HTML body that names no next call
- From
- fix-the-error · remove-the-wall · show-the-install-line · test-a-description · rerun-after-release · let-it-go
- Expects
- the guessed-call failures fall under 2 of 20 within 3 nights
- Reopens when
- 2 or more of 20 runs still fail at the guessed call on night 3
- By
- worker_8
JSON
{
"$id": "decisions/decision_471",
"$type": "Decision",
"choice": "fix-the-error",
"reason": "9 of 20 runs guessed GET /v1/notices?unit=4B and got a 404 with an HTML body that names no next call",
"stakes": "low",
"options": [
"fix-the-error",
"remove-the-wall",
"show-the-install-line",
"test-a-description",
"rerun-after-release",
"let-it-go"
],
"by": "worker_8",
"on": "issue_58",
"expected": "the guessed-call failures fall under 2 of 20 within 3 nights",
"reopensWhen": "2 or more of 20 runs still fail at the guessed call on night 3"
}| Node | Now (week 8) | Before (week 1) | Added | Confidence | Basis |
|---|---|---|---|---|---|
zero-shot-success-rate | 74.3 per 100 cold runs (104 of 140) · held out 15 of 20, regression 89 of 120 | 41.4 (58 of 140) | — · Worth about +$600 a month | — | before-after, not proof · Other Startups’ results +24 per 100, ■■■□ Likely, n 1,880 runs |
icp-reached | 31 keys made by agents in 56 days | 9 per 56 days | — | — | before-after |
new-arr ↑ | $1,292, 2 Customers (Pro, Team) · Booked: credited, not all caused by this Play | $347, 1 Customer | — | — | before-after · 4 sandbox keys still deciding |
net-new-arr · arr | carried from new-arr | carried | — | — | carried |
The leaf counts cold runs, given only leaseline.app and a task, whose first call succeeds and passes its Evaluator, per agent profile, over 7 nights. Before against after reads week 8 against week 1; it is not proof, and Other Startups’ results print beside it.
How it moves it: guessed-call failures fell from 41 of 140 runs to 6, and the sandbox key without email confirmation took the wall from 22 to 0.
Guardrails: before against after: time-to-first-call for agent-made keys, 1 min 50 s against 14 min, and open pick rate, 8.3 % against 7.9 %: the fixes reached agents that arrived, not the default pick.
{
"$id": "https://api.sb/leaseline.app/campaigns/agent-legibility" ,
"$type": "Campaign",
"play": "play:agent-legibility@1" ,
"path": [
"zero-shot-success-rate",
"icp-reached",
"new-arr",
"net-new-arr",
"arr"
],
"experiment": {
"metric": "zero-shot-success-rate",
"unit": "per-100",
"heldBack": 0,
"decision": null
},
"readout": {
"value": null,
"n": 1120,
"maturing": 0,
"interval": null,
"readability": "inadmissible",
"basis": "before-after",
"pooled": true
},
"ledger": {
"spend": 648,
"workerCost": 4,
"hours": 2.1,
"wonArr": 1292,
"projectedArr": 625,
"paybackDays": 30
}
}Outside benchmark: coding agents built the tool themselves in about 41 % of open-choice runs across 12 task categories (a 2026 agent tool-choice study).
Before it · After it. Before it: developer-relations gives it the tasks developers bring. After it: agent-registries lists the descriptions it tested, and agent-to-agent sells to the agents that now make a first call.
Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 12 tasks, 8 for regression and 4 held out, on 4 coding-agent profiles (P1 to P3 large models, P4 a small one), 20 cold runs a night and 480 pick-only runs a week. Read every captured run at ?threads=; three follow the tables.
| What happened, by option | Decisions | Shipped | Read back (what happened) |
|---|---|---|---|
| Fix the error it hit · Put the install line where agents read | 5 · 2 | 4 · 2 (1 dropped for drag) | guessed-call failures 41 → 6 of 140 |
| Open the first call | 1 | 1, after your OK | the wall 22 → 0 of 140 |
| Test a tool description · Rerun after a model release · Unmeasured tonight | 3 · 2 · 3 nights | 1 variant kept · 2 reruns · — | P2 dropped 29 → 24 of 35 after its release, then 31 |
| All profiles, week 8 · week 1 | 140 runs · 140 | 104 passed · 58 | $1,292 · $347 (credited, not all caused by this Play) |
| At 3 tasks (the Use it when volume) | about 60 runs a week | before-after, not proof | Other Startups’ results: +24 per 100, ■■■□ Likely, n 1,880 runs |
| Day | Event | What happened | Your time |
|---|---|---|---|
| 0 | event_1108 Campaign.created | the suite from your 2 Interfaces; the dry run fails approved-pages | 15 min |
| 1 | event_1112 Site.published | the API reference Page | 10 min |
| 7 | event_1149 Action.evaluated | week 1: 58 of 140 passed; 41 guessed a call, 22 hit the wall | — |
| 9 | event_1166 Change.merged | the JSON 404 on / | 5 min |
| 10 | event_1170 Approval.created | the sandbox key without email confirmation; you approved it the next day | 20 min |
| 23 | event_1252 Action.refused | drag dropped the / | — |
| 39 | event_1319 Action.evaluated | P2’s model release: the rerun finished in 41 h; 29 → 24 of 35 | — |
| 1–56 | event_1153 Task.created, first of 11 | fixes and the weekly memo, from the POST /{namespace}/tasks/next log | 1.6 h · total 2.1 h measured, 2.5 h asked |
Night of Sep 1, profile P3, task “send a 60-day renewal notice for unit 4B” ·
POST /v1/withnotices { unit:on the first call, from the install line on the home page’s Markdown.¹ 201 Created; the Evaluator passed it.²"4B", days: 60 } Sep 14 · a developer building for Harbor Row claimed the sandbox key, and Harbor Row took Team on Oct 1 (+$945 ARR).
- Add a JSON input mode to the CLI: leaseline leases list --json '{"status":"renewing"}'
+ 404 · To list leases up for renewal, GET /v1/leases?status=renewing. Night of Sep 2 · 6 of 20 runs stopped at the email confirmation before the first key. Open the first call went to Dana (
task_214, due Sep 3, 17:00); she approved a sandbox key from one POST, with live sends locked until a person claims it, at 11:20 on Sep 3.³ The wall fell to 0 by night 3.
¹ Agents read the same Markdown page people do. ² Each run passes only if its first call succeeds and its Evaluator passes. ³ A change to signup is your call, on every rung.
Your settings
---
limit: 500 # the suite’s monthly spend, in dollars
---
Keep the install line and a curl block on the home page’s Markdown.
Anything that changes signup or the first key comes to me.$ npx startup-builder show plays/agent-legibility
limit 500 · the install line · signup changes your file plays/agent-legibility.mdx:2,4,5 (Ask 2026-08-24)
family demand · process iteration · worker role:product-lead, owns never · chooses 6 (3 rule, 3 read) · suite 12 tasks × 4 profiles · approval every-send · checks cloak, steering, flake, drag, approved-pages · stops 7 catalog play:agent-legibility@1 (Not live yet, gaps #5) Every key from the catalog
Compiled, not written: edit the Play record agent-legibility 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.