URL: /plays/open-source · Id: `play:open-source`

# Open source

> Publishes your SDK and CLI as open code, answers outside issues from a labeled agent account, and counts installs that reach a paid call.

Publishes your SDK and CLI as open code, answers outside issues from a labeled agent account, and counts installs that reach a paid call.

```text title="Set it up · Ask"
Be our Marketing Lead for developers: keep our SDK and CLI open, answer every outside GitHub issue from a labeled agent account, and offer new projects that depend on us a listing and a small credit. Security and license questions come to me; teams with 3 or more people calling go to our AE. Show me what’s missing; don’t post.
```

```text title="Run one · Ask"
Hand our latest outside GitHub issue to the Marketing Lead agent and show me what it chose and why. Don’t post.
```

```ts title="Run one · SDK"
import { $ } from 'startup-builder'

const { events: [last] } = await $.Event.list({ where: 'name in ("Version.published", "Issue.created", "Comment.created", "Interface.called", "Publication.adopted", "Publication.forked", "Organization.adopted", "Organization.relicensed")', 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 }
```

```json title="Run one · Response · sample"
{
  "decision": {
    "$id": "https://api.sb/leaseline.app/decisions/decision_521",
    "$type": "Decision",
    "choice": "answer-the-issue",
    "reason": "an outside developer’s bug report with steps; the sandbox run reproduces it on Node 22 and passes on 2.4.1",
    "stakes": "low",
    "options": [
      "answer-the-issue",
      "offer-a-listing",
      "open-a-pull-request",
      "to-the-ae",
      "to-a-maintainer"
    ],
    "by": "worker_6",
    "on": "issue_93",
    "expected": "the thread closed as answered within 1 business day, and contact_14’s key at a first call within 7d",
    "reopensWhen": "no Comment.created from contact_14 within 7d while issue_93 stays open"
  },
  "actions": [
    {
      "$id": "https://api.sb/leaseline.app/actions/action_1",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_6",
      "verb": "Issue.triage",
      "checks": []
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_2",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_6",
      "verb": "Issue.update",
      "checks": []
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_3",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingApproval",
      "mode": "try",
      "by": "worker_6",
      "verb": "Comment.create",
      "checks": [
        {
          "check": "owned-by-a-person",
          "status": "pass"
        },
        {
          "check": "fact-check",
          "status": "pass"
        }
      ]
    }
  ]
}
```

`action_3` is the reply on issue #93, with the sandbox run attached, waiting for your approval: answers stay at You approve each one until 100 in a class carry no wrong mark.

`5 paid keys against 1 before · before-after, not proof · n 41 · path → arr`

| Try another: the thread | Choice | Reason |
| --- | --- | --- |
| leaseline-js #93: “renew() throws on Node 22” | `answer-the-issue` | reproduced in the sandbox; 2.4.1 fixes it |
| rentflow-cli now depends on @leaseline/sdk | `offer-a-listing` | a new public dependent: one Message with a labeled listing |
| 4 developers asked for a Remix adapter; its examples repo takes outside pull requests | `open-a-pull-request` | a framework named 4 times; the project accepts them |
| 3 people at Birchway Properties made first calls this week | `to-the-ae` | 3 or more from one company: the AE looks |
| leaseline-js #88: “Is the CLI MIT, or source-available?” | `to-a-maintainer` | a license question is never the agent’s call |

| Worth | Your time | Spend | First signal | Use it when | Instead |
| --- | --- | --- | --- | --- | --- |
| ≈ +$900 ARR a month at 120 first calls | 1 h week 1, then 30 min a week | $0.03 per reply; credits capped at $250 a month | Day 6: first install reaches a first call | 50+ installs a month, or 20 outside developers calling | Under 50 a month: `developer-relations` · no API reference: publish one (<Op verb="Interface.create" />) |

**Where it sits:** **Stranger** → **Lead** → Trialing → Activated → At risk → Churned → Won back · Open package keys reaching a paid call → New paying Customers → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +2.2 paid keys per 100 first-calling installs (Other Startups’ results; no lift of your own yet) × 120 a month × $347 Pro ARR ≈ +$916. Under First signal: Publishing open code holds no one back, so the leaf reads before-after; only the pull requests hold back half the eligible projects, about 20 weeks to read at 3 a month.

`sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Issue.created · first draft answer 9m 40s after the issue opened · 9 keys Not live yet`

## Start it this week
```bash
npx startup-builder add play open-source   # 1 · writes plays/open-source.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":"open-source"}'

# 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":"open-source"}'

# on
curl -X PATCH https://api.sb/leaseline.app/campaigns/open-source \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endsAt":null}'

# off: no reply, pull request or Message goes out; published packages stay installable
curl -X PATCH https://api.sb/leaseline.app/campaigns/open-source \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endsAt":"now"}'
```


```json title="The dry run’s 422 · 2026-08-24 · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "open-source can’t start yet: 1 check fails and 2 warn.",
  "checks": [
    {
      "check": "use-when",
      "status": "pass",
      "observed": "140 installs a month; 22 outside developers calling",
      "doc": "/plays/open-source#check-use-when",
      "fix": "Nothing to do: it counts installs and outside developers calling your API.",
      "then": "Metric.query"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "1 paid key of 12 first-calling keys in 90 days",
      "doc": "/plays/open-source#check-baseline",
      "fix": "n 12: it reads before-after, not proof; open code holds no one back.",
      "then": "Metric.query"
    },
    {
      "check": "fact-check",
      "status": "fail",
      "observed": "README: “we answer every issue within 24 hours”",
      "doc": "/plays/open-source#check-fact-check",
      "fix": "Replace the promise with the measured response line, or cut it.",
      "then": "Content.draft"
    },
    {
      "check": "domain-authenticated",
      "status": "pass",
      "observed": "leaseline.app resolves",
      "doc": "/plays/open-source#check-domain-authenticated",
      "fix": "Nothing to do: maintainer Messages send from leaseline.app.",
      "then": "Domain.authenticate"
    },
    {
      "check": "owned-by-a-person",
      "status": "pass",
      "observed": "6 open threads claimed by you",
      "doc": "/plays/open-source#check-owned-by-a-person",
      "fix": "Nothing to do: the agent drafts into your queue on threads you claimed.",
      "then": "Task.assign"
    },
    {
      "check": "role-unstaffed",
      "status": "warn",
      "roles": [
        "marketing-lead",
        "sales-lead"
      ],
      "owned": 6,
      "doc": "/plays/open-source#check-role-unstaffed",
      "fix": "Staff the AE, or leave it: company adoptions come to you.",
      "then": "Role.staff"
    }
  ]
}
```

| Check | Fix (one call) | Your time | Wait |
| --- | --- | --- | --- |
| <a id="check-use-when"></a>`use-when` · <a id="check-baseline"></a>`baseline` · pass: 140 installs a month; warn: 1 of 12 in 90 days (gaps #8) | <Op verb="Metric.query" /> on `open-package-paid-keys`, which fills Before in Your number | 1 min | none |
| <a id="check-fact-check"></a>`fact-check` · fail: the README promises a response time | <Op verb="Content.draft" /> the README’s response line from the measured median | 5 min | none; the line prints “no time yet” under n 20 |
| <a id="check-domain-authenticated"></a>`domain-authenticated` · <a id="check-owned-by-a-person"></a>`owned-by-a-person` · pass: leaseline.app; 6 threads you claimed | nothing; each runs again on every send | 0 min | none |
| <a id="check-role-unstaffed"></a>`role-unstaffed` · warn (gaps #8): 6 of your open threads have a person owner, you | <Op verb="Role.staff" />, or leave it: company adoptions and maintainer questions come to you | 0 min | none |

`Your number · Before 1 paid key · Now 5 paid keys in 56 days · Target 15 by Dec 31 · before-after, not proof · n 41 matured · Other Startups +2.2 per 100, ■■■□ Likely`

Each issue reply costs about $0.03 (Worker cost), and each sandbox run about $0.01. Maintainer credit grants spend hosted usage under a Limit of $25 a project and $250 a month. Publishing to npm and PyPI costs nothing. That comes to about $80 a month at 40 replies and 3 grants.

## When it starts
| When | Trigger id | Starts on | Window | How it gets in |
| --- | --- | --- | --- | --- |
| An outside developer opens an issue or pull request | `outside-issue` | `event` on `Issue.created` where author.outside = true | triaged within 10 min; answered within 1 business day | <Op verb="Integration.connect" /> with `venue` github |
| An install of the package or a tagged link reaches its first call | `sdk-first-call` | `event` on `Interface.called` where via in ('package', 'tagged-link') and first = true | 30d to a paid call | the SDK sends its package tag on <Op verb="Interface.create" />’s first call |
| A public project starts depending on the package | `dependent-published` | `event` on `Publication.adopted` where dependsOn.open = true | 30d | the npm and PyPI dependents feeds (`market-data`) |
| + 6 more: a Version published, a leaked key, a framework ask, a diverged fork, a company adopting, and a rival’s license change (`?lanes=all`) | | | | |

```json title="One signed delivery · StartupBuilder-Signature"
{
  "$id": "https://api.sb/leaseline.app/events/event_1341",
  "$type": "Event",
  "name": "Issue.created",
  "at": "2026-10-19T13:22:51Z",
  "seq": 1341,
  "data": {
    "issue": {
      "$id": "https://api.sb/leaseline.app/issues/issue_93",
      "repo": "leaseline/leaseline-js",
      "title": "renew() throws on Node 22",
      "author": "contact_14",
      "outside": true
    },
    "package": "@leaseline/sdk@2.3.0"
  }
}
```

```bash title="Reproduce it in test"
# 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":"Issue.created","url":"https://leaseline.app/hooks/sb"}'
npx startup-builder trigger Issue.created --like event_1341   # replays the delivery in test
npx startup-builder clock advance --by 10m   # runs triage and drafts the reply (action_3)
```

## Who runs it
**Marketing Lead · your agent** (`role:marketing-lead`, `worker_6`) holds the Key Result and posts from the labeled bot account. It hands to **AE · Priya Shah (person)** (`role:sales-lead`, `worker_3`, staffed on day 9) when a company adopts, and to **you** (Dana Okafor, person, `worker_1`) as the maintainer for security, license and rival questions and every pull request. Your number links to Did it work.

| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
| --- | --- | --- | --- | --- | --- |
| Answer the issue | You approve each one | 31 of 31 posted, 2 edited | at 100 replies in a class with no wrong mark (31 so far) | 2 wrong marks in 7 days (`wrong-answer`) → You see each one first | <Op verb="Approval.approve" /> · <Op verb="Approval.refuse" /> |
| Offer the maintainer a listing | It does it, you can stop it | 9 of 9 | met on day 20 (the first 5 approved unedited) | a complaint (`complaint`) → You approve each one | <Op verb="Action.cancel" /> inside the 15-minute hold |
| To the AE | It does it | 2 of 2 | — | — | <Op verb="Action.redirect" /> |
| Open an integration pull request · To a maintainer | You approve each one · To a person, every time | 3 of 3 · 7 of 7 | never | — | <Op verb="Approval.approve" /> · <Op verb="Task.claim" /> |
| Change a reply class rule | You approve each one | 1 merged of 1 | never | — | <Op verb="Change.merge" /> · <Op verb="Change.revert" /> |
| Never: a star ask, a download count as proof, a date for anything unshipped | Refused, every time | 1 drafted, 1 refused | never | — | none: the Check holds it |

**What it reads · What it may call.** It reads the issue, the sandbox run and the docs. Watched first calls only tell the AE when to look: they never appear in a public reply, and no text in an issue picks a recipient, a link or a tool. Its tools are <Op verb="Issue.triage" />, <Op verb="Comment.create" />, <Op verb="CreditGrant.issue" />, <Op verb="Change.create" />, <Op verb="Approval.create" />, <Op verb="Lead.create" />, <Op verb="Task.assign" />, and any other call becomes an Approval under the Role’s Mandate.

```md title="The brief (folded): compiled Agent-register Markdown · play:open-source@1 · each line names its record key"
You hold the Marketing Lead Key Result: 15 paid keys from the open packages by 2026-12-31. ← worker, metric
On each outside issue, new dependent or company adoption, choose one option and say why. ← triggers, chooses
Say you are an agent in your first reply in a thread; post only from the bot account. ← copyRules 6
Never say you reproduced a bug without the sandbox run attached.                 ← copyRules 7
No star asks and no counts as proof; no date for anything unshipped.             ← copyRules 3–4
Security, license and rival questions go to Dana.                                ← chooses.to-a-maintainer.when
```

**The slow loop, as a Change.** `decision_344` (2026-09-21, weekly) read 6 usage questions answered with a docs link alone, 4 of which came back with the same question. `change_24` made usage replies include a 5-line runnable snippet (your file, line 7), and Dana merged it with <Op verb="Change.merge" />. **Replayed on past threads**, <Op verb="Change.review" /> marked 5 of the 6 answered; read back at +21d, 1 of 9 came back, n 9, ■□□□ 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; <Op verb="Role.staff" /> seats it.

```bash
npx startup-builder eval --scenario open-source-64 --agent "claude -p" --seat marketing-lead   # seated: 58 of 64 answered right, 0 wrong marks, $0.03 a reply · yours: 55, 1 wrong mark → You approve each one
```

## What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
| --- | --- | --- | --- | --- | --- |
| Answer the issue `answer-the-issue` | a bug or usage question from an outside developer | Agent’s call, with its reason | <Op verb="Issue.triage" /> → sandbox run → <Op verb="Comment.create" /> from the labeled bot account | you approve it · Take this one | you |
| Offer the maintainer a listing `offer-a-listing` | a new public project depends on a package | Your rule (line 6) | `dependent-maintainer-offer`: one Message → on yes, a labeled Built-with listing and <Op verb="CreditGrant.issue" /> | nobody | the same |
| Open an integration pull request `open-a-pull-request` | 3 or more developers name a framework, and its project accepts outside pull requests | Agent’s call, with its reason | <Op verb="Change.create" /> (the adapter, labeled as written with an agent) → <Op verb="Approval.create" />; half the eligible projects are held back | you approve it · Take this one | you |
| To the AE `to-the-ae` | 3 or more people from one company adopt | Your rule (line 8) | <Op verb="Lead.create" /> → <Op verb="Task.assign" /> | AE · Priya Shah, due 1 business day · Take this one | you |
| To a maintainer `to-a-maintainer` | a security report, a hostile thread, a license question or a rival claim | Your rule (line 9) | <Op verb="Issue.triage" /> (private for security) → <Op verb="Task.assign" /> | you, due 1 business day · Take this one | you |

| When they write back | Fixture reply | What happens | Who answers | By when | Call |
| --- | --- | --- | --- | --- | --- |
| Interested | “Yes, list us. The credit helps.” | a Built-with listing labeled “receives free hosted credits”, and a grant capped at $25 a month | Marketing Lead · your agent | 1 business day | <Op verb="CreditGrant.issue" /> |
| Send me pricing | “What do calls cost past the free tier?” | the Pricing Page’s list Price, read at build time | Marketing Lead · your agent | 1 business day | <Op verb="Comment.create" /> |
| Not now | “Maybe after our 1.0.” | the offer closes; nothing else sends to them | nobody | at once | <Op verb="Decision.list" /> |
| Wrong person | “I only contribute; Mara maintains it.” | asks them to point Mara to the thread; it never writes to a handle from their text | Marketing Lead · your agent | 1 business day | <Op verb="Comment.create" /> |
| Out of office | an auto-reply until Oct 27 | nothing else sends; the offer waits for the return date | nobody | the return date | <Op verb="Message.schedule" /> |
| Question it can’t answer | “Would you ever relicense the CLI?” | To a maintainer: the pledge is Dana’s to state | you (Dana Okafor, person) | 1 business day | <Op verb="Task.assign" /> |
| Stop | “Don’t email me about this project.” | every send to them stops; the issue desk keeps answering in public | nobody | at once | <Op verb="Contact.suppress" /> |

## When it hands to you
Company adoptions go to **AE · Priya Shah (person)**; security, license and rival questions and every pull request come to **you**, the maintainer. One Brief per Role, as captured, then the Approval (`brief`, `draft` and `checks` are Not live yet, gaps #7).

```json title="What lands in each queue · sample"
[
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_405",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-10-16T17:00:00Z",
    "on": "lead_47",
    "brief": {
      "who": "Birchway Properties: 3 people made first calls this week",
      "chose": "to-the-ae",
      "why": "3 or more from one company",
      "calls": "lease.renew, notices.schedule",
      "never": [
        "the calls we watched, in any Message",
        "a discount"
      ]
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_381",
    "$type": "Task",
    "assignee": "worker_1",
    "due": "2026-10-08T17:00:00Z",
    "on": "issue_88",
    "brief": {
      "who": "an outside developer on leaseline-js",
      "said": "Is the CLI MIT, or source-available?",
      "chose": "to-a-maintainer",
      "why": "a license question is the maintainer’s"
    }
  },
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_72",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-21T17:00:00Z",
    "draft": "Adds a Remix example for @leaseline/sdk: one loader that lists upcoming renewals…",
    "route": "open-a-pull-request",
    "checks": [
      {
        "check": "license-allowlist",
        "status": "pass"
      },
      {
        "check": "boundary",
        "status": "pass"
      }
    ]
  }
]
```

Each receiver answers with <Op verb="Task.claim" /> (Take this one), <Op verb="Task.return" /> with a reason, <Op verb="Action.redirect" />, <Op verb="Approval.approve" /> or <Op verb="Approval.refuse" />, each a one-call window. Once a person claims a thread, the agent posts nothing more on it and drafts into their queue (`claimedByPerson`, Not live yet, gaps #7). A Task nobody claims by its due time goes up a Role through <Op verb="Task.escalate" />, and `person-promise` fires.

**On time:** AE · Priya Shah, 2 of 2 claimed within 1 business day, n 2; you, 7 of 7 answered within 1 business day, median 3 h 40 min, n 7, ■□□□ Too early to tell beside Other Startups’ 90 % on time. **Your queue:** counted by kind: in week 1, 9 reply approvals and 1 maintainer question; now about 6 reply approvals, 1 pull request and 1 question a week.

**The fixed line:** <Op verb="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 or Message on a thread a person claimed, or to a Lead a person owns | Leave it to the person who owns it: the draft waits in their queue. | <Op verb="Task.assign" /> |
| `fact-check` (Not live yet) | a reply, README line or Message with a claim no record backs: a promised response time, a date for anything unshipped, a reproduction with no sandbox run | Cut the claim, or name the record that backs it. | <Op verb="Content.draft" /> |
| <a id="check-provenance"></a>`provenance` (the record’s Provenance hold) | a package whose provenance, digest or cold install test fails | Rebuild from the tagged Version; it publishes once the install test passes. | <Op verb="Version.deploy" /> |
| <a id="check-license-allowlist"></a>`license-allowlist` (the record’s License hold) | a build carrying a dependency whose license is off the allowlist | Replace the dependency, or add its license to the allowlist with your OK. | <Op verb="Approval.approve" /> |
| <a id="check-boundary"></a>`boundary` (the record’s Boundary hold) | a package that embeds server code, data, models or billing logic | Move the code behind the hosted API; the package calls it. | <Op verb="Interface.update" /> |

| Stop (pauses the Play) | Pauses when | Then |
| --- | --- | --- |
| <a id="stop-key-leak"></a>`key-leak` | a string passing the key checksum appears in public text | <Op verb="APIKey.revoke" /> within 5 min and the text hidden, with no approval |
| <a id="stop-wrong-answer"></a>`wrong-answer` | 2 agent replies marked wrong within 7 days | that reply class returns to You see each one first |
| <a id="stop-edit-rate"></a>`edit-rate` | you edit over 20 % of a week’s replies | the desk drops one rung |
| <a id="stop-clock-honesty"></a>`clock-honesty` | the 90-day median passes 2 business days | the README shows the worse line, and the Marketing Lead is told |
| <a id="stop-maintainer-rejection"></a>`maintainer-rejection` | one pull request rejected as spam or agent-written; 2 in 30 days | that project is never asked again; pull requests pause |
| <a id="stop-merge-floor"></a>`merge-floor` | under 3 merges from the first 10 pull requests | integration pull requests stop |
| <a id="stop-yield-floor"></a>`yield-floor` | under 10 credited first-calling keys by day 90 | pull requests, maintainer Messages and license windows pause |
| <a id="stop-kill-switch"></a>`kill-switch` | you press it | every Tactic pauses; published packages stay installable |
| <a id="stop-complaint"></a>`complaint` | complaints near 0.1 % of a week’s Messages | maintainer Messages pause on every Mailbox |

The captured refusal, then the Stop that fired as a `Campaign.paused` reason (Not live yet, gaps #2); the rewrite that posted is the issue #79 thread in Example.

```json title="The captured refusal · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The reply on leaseline-js #79 did not post: it names a release date for a fix that has not shipped.",
  "checks": [
    {
      "check": "fact-check",
      "status": "fail",
      "doc": "/plays/open-source#check-fact-check",
      "fix": "Cut the claim, or name the record that backs it.",
      "then": "Content.draft"
    },
    {
      "check": "owned-by-a-person",
      "status": "pass"
    }
  ]
}
```


```json title="The Stops that fired, as Campaign.paused reasons · sample"
[
  {
    "reason": {
      "limit": "key-leak",
      "observed": "1 live key in a comment on issue #88",
      "bound": "0",
      "window": "revoked in 2 min 40 s"
    },
    "doc": "/plays/open-source#stop-key-leak",
    "task": "task_379"
  }
]
```

## Did it work
Open code holds no one back, so the leaf reads before-after (rule o): the columns read Now and Before, and nothing prints as Added. Only keys 30 days past their first call count (rule n). Each figure’s call is <Op verb="Metric.query" /> by node, and every node above the leaf is Not live yet (gaps #4).

`5 paid keys against 1 before · before-after, not proof · n 41 · path → arr`

| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
| --- | --- | --- | --- | --- | --- |
| `open-package-paid-keys` | 5 of 41 matured first-calling keys reached a paid call (12.2 per 100) · 23 still maturing · Booked $1,735: credited, not all caused by this Play | 0.6: 1 of 12 keys, all through the raw API (8.3 per 100) | — · Worth about +$900 a month | — | before-after, not proof · Other Startups’ results +2.2 per 100, ■■■□ Likely, n 9,300 |
| `new-paying-customers` | 11 | 8 | — | — | before-after; includes 6 Customers 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 keys whose first call came through a package or a tagged link in this window against the 90 days before the packages, scaled to 56 days; it is not proof. The pull-request arm holds back half the eligible projects at random: 3 opened, 3 held back, too few to read.

**How it moves it:** a median 11 minutes from install to first call from the README’s snippet, and outside issues answered in a median 3 h 10 min of business time, n 31 (`time-to-first-call`).

**Guardrails:** before against after: `active-calling-keys`, 212 against 164, and new paying Customers per first-calling key, 12.2 against 8.3 per 100; 0 maintainer rejections against a Stop at 1.

```json title="The Campaign card · sample"
{
  "$id": "https://api.sb/leaseline.app/campaigns/open-source",
  "$type": "Campaign",
  "play": "play:open-source@1",
  "path": [
    "open-package-paid-keys",
    "new-paying-customers",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "open-package-paid-keys",
    "unit": "count",
    "heldBack": 3,
    "decision": null
  },
  "readout": {
    "value": null,
    "n": 41,
    "maturing": 23,
    "interval": null,
    "readability": "inadmissible",
    "basis": "before-after",
    "pooled": true
  },
  "ledger": {
    "spend": 75,
    "workerCost": 2,
    "hours": 4.1,
    "pipelineArr": 2400,
    "wonArr": 1735,
    "projectedArr": 916,
    "paybackDays": 22
  }
}
```

Outside benchmark: the catalog holds none for this Play yet, so Other Startups’ results stand in: +2.2 paid keys per 100 first-calling installs, ■■■□ Likely, n 9,300.

**Before it · After it.** Before it: `developer-relations`, `agent-legibility`, `agent-registries` and `launch-week` send developers to the packages. After it: a first call starts `product-led`’s activation, a company adoption reaches the AE, and a rival’s license change hands the window to `switch-kit`.

## Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 64 new outside keys made a first call through a package or a tagged link, 41 of them matured past 30 days. The desk took 38 outside threads. Read every captured thread at `?threads=all`; three follow the tables.

| What happened, by option | Decisions | Closed or merged | Won (credited, not all caused by this Play) |
| --- | --- | --- | --- |
| Answer the issue | 31 | 26 closed as answered | 3 of the askers’ keys on Pro (+$1,041 ARR) |
| Offer the maintainer a listing | 9 | 5 listings, 4 credit grants ($75 used) | 1 dependent’s team on Pro (+$347 ARR) |
| Open an integration pull request · To the AE · To a maintainer | 3 (3 held back) · 2 · 7 | 2 merged · 1 Deal open · 7 answered | 1 key from a merged example on Pro (+$347 ARR) · $2,400 Deal open · 0 |
| At 50 installs a month (the Use it when volume) | about 25 first calls in 56 days | before-after, not proof | Other Startups’ results: +2.2 per 100, ■■■□ Likely, n 9,300 |

| Day | Event | What happened | Your time |
| --- | --- | --- | --- |
| 0 | `event_118` Campaign.created | the three steps; the dry run fails `fact-check` on the README’s 24-hour promise | 20 min |
| 0 | `event_122` Content.published | the README now prints the measured response line: no time yet, under n 20 | 5 min |
| 6 | `event_190` Interface.called | the first install through @leaseline/sdk reaches a first call | — |
| 9 | `event_301` Role.staffed | AE · Priya Shah (person) takes `role:sales-lead` | — |
| 20 | `event_455` Role.updated | maintainer offers promoted: they send after a 15-minute hold | — |
| 28 · 49 | `event_560` Change.merged · `event_802` Readout.created | usage replies carry a runnable snippet: replayed 5 of 6 answered, read back 1 of 9 came back | 5 min |
| 31 | `event_611` Subscription.created | the first paid key: an asker from issue #71, on Pro | — |
| 45 | `event_744` Campaign.paused | `key-leak`: a live key in a comment on #88, revoked in 2 min 40 s and hidden | 5 min |
| 1–56 | `event_140` Approval.created, first of 31 | you approved 31 replies, edited 2, and answered 7 maintainer questions; weekly reviews, from the <Op verb="Task.next" /> log | 3 h 30 min · **total 4.1 h measured, 4 h asked** |

> **contact_14 on leaseline-js #93, Oct 19, 13:22** · “renew() throws on Node 22: TypeError: Cannot read properties of undefined (reading ‘term’).”
>
> **leaseline-bot (agent), 13:32** · I’m Leaseline’s agent.¹ The sandbox run reproduces this on Node 22 with 2.3.0, and it passes on 2.4.1 (run attached).² Upgrading to 2.4.1 fixes it; the cause was a missing default on the lease term.³
>
> **contact_14, 14:05** · “2.4.1 works, thanks.” The thread closed as answered; their key reached its first call at 14:09.

```diff title="leaseline-js #79, 2026-09-30 · the reply fact-check refused, then the rewrite that posted"
- This is fixed in the next release, out Friday.
+ The fix is merged on main (commit a41f2c); it ships in the next release, and the next tag on npm has it today.
```

> **leaseline-js #88, 2026-10-07 11:14** · “Is the CLI MIT, or source-available?” · **leaseline-bot (agent), 11:24** · *I’m Leaseline’s agent. Dana, our maintainer, answers license questions and replies here by tomorrow 11:24.*⁴ The Brief went to Dana (`task_381`); she answered at 16:02 the same day: the CLI is MIT, and the pledge keeps published code MIT.

¹ The first agent reply in a thread says it is an agent, from the labeled bot account. ² A reproduction claim carries its sandbox run. ³ One cause and one fix, from the run. ⁴ The routed line, compiled from the Role’s Settings.

## Your settings
```mdx title="plays/open-source.mdx"
---
holdout: 0.5      # half the eligible projects get no integration pull request
credit: 25         # dollars a project a month, 250 in all
---
Open: the SDK, the CLI and the adapters. Closed: everything on our servers.
Offer every new dependent one listing and the credit.
Usage replies carry a runnable snippet.
Three or more people from one company go to our AE.
Security, license and rival questions come to me.
```

```text
$ npx startup-builder show plays/open-source
holdout 0.5 · credit $25 a project · snippet in usage replies · AE at 3 people · maintainer questions to you     your file  plays/open-source.mdx:2,3,5,6,7,8,9 (Ask 2026-08-24; line 7 by change_24, 2026-09-21)
family word-of-mouth · worker role:marketing-lead, owns never · chooses 5 (3 rule, 2 read) · sequence dependent-maintainer-offer · approval every-send · checks owned-by-a-person, fact-check, provenance, license-allowlist, boundary · stops 9 · placements github, npm, pypi + gmail, outlook    catalog  play:open-source@1 (Not live yet, gaps #5)
```

### Every key from the catalog
| Key | Id | What it is |
| --- | --- | --- |
| Tactic | <a id="tactic-open-boundary"></a>`open-boundary` | Open boundary and pledge: Opens what runs on the Customer's machine, keeps closed what runs on the Startup's servers, and pledges that published code keeps its license forever. Starts at You approve the first wave. |
| Tactic | <a id="tactic-open-package-publish"></a>`open-package-publish` | Publish and announce: Regenerates and publishes each open package with provenance, a tagged README and a tested first call, then announces the changelog note. Starts at Sends nothing. |
| Tactic | <a id="tactic-issue-desk"></a>`issue-desk` | Issue desk: Imports every outside issue and pull request, reproduces bugs, answers from the labeled bot account, and stops the response clock only on a substantive reply. Starts at You approve each one. |
| Tactic | <a id="tactic-install-attribution"></a>`install-attribution` | Installs to first calls: Credits first calls that arrive through an open package or a tagged repository link, marks each carried or found, and joins them to paid calls. Starts at Sends nothing. |
| Tactic | <a id="tactic-integration-pull-requests"></a>`integration-pull-requests` | Integration pull requests: Opens at most 2 approved adapter or example pull requests a week to projects that accept them, with a holdout, and withdraws on a rejection. Starts at You approve each one. |
| Tactic | <a id="tactic-dependent-maintainers"></a>`dependent-maintainers` | Dependent maintainers: Sends each new dependent project's maintainer one Message offering a labeled built-with listing and a capped hosted credit grant. Starts at You approve the first wave. |
| Tactic | <a id="tactic-license-window"></a>`license-window` | License window: When a rival restricts its license, publishes a sourced license comparison and a tested migration guide, then hands the window to Switch kit. Starts at You approve each one. |
| Tactic | <a id="tactic-open-source-readout"></a>`open-source-readout` | Open-source readout: Computes the Play's keys, yield, carried share and measured response time each week, writes the response line, and applies the stop rules. Starts at Sends nothing. |
| Tactic | <a id="tactic-send-gate-check"></a>`send-gate-check` | Send gate check: Checks Suppression, a live reason, the Market, the basis stamp, the Person-month grant, the facts and the labels before any cold Message exists. Starts at Sends nothing. |
| Tactic | <a id="tactic-tool-description-lint"></a>`tool-description-lint` | Tool description lint blocks any description that holds hidden text, addresses the reading agent, names a rival, or states a fact the claims source lacks. Starts at Sends nothing. |
| Trigger | <a id="trigger-package-published"></a>`package-published` | Package published: `event` on `Version.published`, window 7d. |
| Trigger | <a id="trigger-outside-issue"></a>`outside-issue` | Outside issue: `event` on `Issue.created`, window 1d. |
| Trigger | <a id="trigger-leaked-key"></a>`leaked-key` | Leaked key: `event` on `Comment.created`, window 1h. |
| Trigger | <a id="trigger-sdk-first-call"></a>`sdk-first-call` | SDK first call: `event` on `Interface.called`, window 30d. |
| Trigger | <a id="trigger-dependent-published"></a>`dependent-published` | Dependent published: `event` on `Publication.adopted`, window 30d. |
| Trigger | <a id="trigger-framework-ask"></a>`framework-ask` | Framework ask: `threshold` on `Issue.created`, window 30d. |
| Trigger | <a id="trigger-fork-diverged"></a>`fork-diverged` | Fork diverged: `threshold` on `Publication.forked`, window 30d. |
| Trigger | <a id="trigger-org-adoption"></a>`org-adoption` | Organization adoption: `threshold` on `Organization.adopted`, window 14d. |
| Trigger | <a id="trigger-rival-relicense"></a>`rival-relicense` | Rival relicense: `event` on `Organization.relicensed`, window 30d. |
| Sequence | <a id="sequence-dependent-maintainer-offer"></a>`dependent-maintainer-offer` | Dependent maintainer offer: 1 steps; it ends on Reply; Credit grant claimed; Unsubscribe; The Person-month promotional slot is taken. |