URL: /plays/request-desk · Id: `play:request-desk`

# Tools on request

> Asks your niche each week for one annoying problem, builds the top 10 as free tools within 24 hours, and you answer every asker.

Asks your niche each week for one annoying problem, builds the top 10 as free tools within 24 hours, and you answer every asker.

```text title="Set it up · Ask"
Be our Content Lead: each Friday, ask property managers for one annoying problem, build the top 10 as free tools within 24 hours, and draft a reply to every asker for me to post. Show me what’s missing; don’t post.
```

```text title="Run one · Ask"
Hand the latest request to the Content 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 ("Schedule.fired", "Post.replied", "Post.published", "Tool.used", "Tool.called", "Version.deployed")', 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_602",
    "$type": "Decision",
    "choice": "build-the-tool",
    "reason": "“I rebuild our turnover calendar from a spreadsheet every January” scored 8.4, 3rd of this week’s 10; Leaseline’s calendar Verb builds it from a CSV",
    "stakes": "low",
    "options": [
      "build-the-tool",
      "send-a-sample",
      "answer-in-writing",
      "not-this-week",
      "not-ours",
      "to-the-ae"
    ],
    "by": "worker_6",
    "on": "problem_23",
    "expected": "an entry Offer start from the asker within 30d",
    "reopensWhen": "the tool not live 24h after the pick"
  },
  "actions": [
    {
      "$id": "https://api.sb/leaseline.app/actions/action_1",
      "$type": "Action",
      "status": "done",
      "mode": "try",
      "by": "worker_6",
      "verb": "Problem.rank",
      "checks": []
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_2",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingTime",
      "mode": "try",
      "by": "worker_6",
      "verb": "App.publish",
      "checks": [
        {
          "check": "correctness",
          "status": "pass"
        }
      ]
    },
    {
      "$id": "https://api.sb/leaseline.app/actions/action_3",
      "$type": "Action",
      "status": "pending",
      "reason": "awaitingApproval",
      "mode": "try",
      "by": "worker_6",
      "verb": "Conversation.answer",
      "checks": [
        {
          "check": "owned-by-a-person",
          "status": "pass"
        },
        {
          "check": "claims-resolve",
          "status": "pass"
        },
        {
          "check": "consent-stop",
          "status": "pass"
        },
        {
          "check": "seeded-request",
          "status": "pass"
        }
      ]
    }
  ]
}
```

`action_2` publishes the turnover-calendar tool once its known-answer cases pass. `action_3` is the reply in the asker’s own thread, waiting in your send tray: you post every reply by hand.

`12.1 entry starts per 100 askers against 4.5 before · before-after, not proof · n 58 · path → arr`

| Try another: the request | Choice | Reason |
| --- | --- | --- |
| u/rentroll_rita: “I rebuild our turnover calendar from a spreadsheet every January.” | `build-the-tool` | 3rd of the weekly 10; one Verb builds it |
| A manager drops their listings URL in the Friday thread | `send-a-sample` | 14th of 30 in the thread |
| “Is there a template for an owner’s monthly report?” | `answer-in-writing` | the template is already on the Site |
| “Can someone build a tenant screening scorer?” | `not-ours` | not something Leaseline builds; the reply says why |
| Kai at Westbrook Lofts, 180 units: “Does Leaseline do this for a portfolio?” | `to-the-ae` | over 100 units, asking about the product itself |

| Worth | Your time | Spend | First signal | Use it when | Instead |
| --- | --- | --- | --- | --- | --- |
| ≈ +$400 ARR a month at 35 | 1 h week 1, then 40 min a week | $0.60 per tool, ~$12 a month at 20 | Day 1: the first tool live | 2+ communities, 20+ problems posted a week | No community: `community-answers` · no one-day build: `free-tools` |

**Where it sits:** **Stranger** → **Lead** → Trialing → Activated → At risk → Churned → Won back · Requester entry rate → People reached → New Customers ↑ → ARR added each week → ARR

Worth’s formula: about +6 entry starts per 100 askers (Other Startups’ results; no lift of your own yet) × 35 askers a month × 0.55 entry to paid × $347 Pro ARR ≈ +$401. Under First signal: Every asker gets an answer, so nothing is held back: it reads before-after, not proof, beside Other Startups’ results.

`sample · api.sb/leaseline.app · 41 Customers at 2026-10-19 · on Post.replied · first tool live 19 h after the ask · 8 keys Not live yet`

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

# 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":"request-desk"}'

# on
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/enable \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"

# off: no call posts; live tools stay up and open requests still get an answer
curl -X POST https://api.sb/leaseline.app/processes/content-marketing/pause \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```


```json title="The dry run’s 422 · 2026-08-24 · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "request-desk can’t start yet: 1 check fails and 2 warn.",
  "checks": [
    {
      "check": "use-when",
      "status": "pass",
      "observed": "2 communities, 41 problems posted a week",
      "doc": "/plays/request-desk#check-use-when",
      "fix": "Keep 2 communities with 20 or more problems a week, or run community-answers.",
      "then": "Metric.query"
    },
    {
      "check": "owner",
      "status": "fail",
      "observed": "no booked founder reply slot",
      "doc": "/plays/request-desk#check-owner",
      "fix": "Book a weekly 45-minute reply slot; no call posts without one.",
      "then": "Task.assign"
    },
    {
      "check": "baseline",
      "status": "warn",
      "observed": "1 entry start of 22 askers you answered by hand in 90 days",
      "doc": "/plays/request-desk#check-baseline",
      "fix": "n 22: it reads before-after, not proof; every asker gets an answer.",
      "then": "Metric.query"
    },
    {
      "check": "role-unstaffed",
      "status": "warn",
      "roles": [
        "marketing-lead",
        "sales-lead"
      ],
      "owned": 0,
      "doc": "/plays/request-desk#check-role-unstaffed",
      "fix": "Staff the AE, or leave it: product questions from big askers 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: 2 communities, 41 problems a week; warn: 1 of 22 in 90 days (gaps #8) | <Op verb="Metric.query" /> on `requester-entry-rate`, which fills Before in Your number | 1 min | none |
| <a id="check-owner"></a>`owner` · fail: no booked reply slot | <Op verb="Task.assign" /> a weekly 45-minute reply slot to you | 2 min | none |
| <a id="check-role-unstaffed"></a>`role-unstaffed` · warn (gaps #8): no AE or Marketing Lead | <Op verb="Role.staff" />, or leave it: those routes come to you | 0 min | none |

`Your number · Before 4.5 · Now 12.1 entry starts per 100 askers · Target 15 by Dec 31 · before-after, not proof · n 58 matured`

Each tool costs about $0.60 in build compute and each Sample $0.08 (Worker cost), under the $25 monthly build Limit; posting from your own profile costs nothing. That comes to about $12 a month at 20 tools.

## When it starts
| When | Trigger id | Starts on | Window | How it gets in |
| --- | --- | --- | --- | --- |
| Someone answers the Friday call with a problem | `request-posted` | `event` on `Post.replied` where a reply to an open call, inside its 48-hour window | built within 24 h; answered within 72 h of the cutoff | <Op verb="Handle.connect" /> on the Rooms where you post the call |
| Someone drops a URL in the thread | `url-dropped` | `event` on `Post.replied` where a URL in a reply to an open drop-your-URL thread, under its cap of 30 | a Sample within 48 h; 30 a thread | the same Handle |
| An asker runs their tool 3 times in 7 days, or shares it | `requester-repeat-use` | `threshold` on `Tool.used` where an asker runs their tool 3 or more times in 7 days, or shares it | 7d | the tool reports <Op verb="Event.capture" /> on each run |
| + 5 more for the weekly slot, tool wishes, day 30, repeat use and day 90 (`?lanes=all`) | | | | |

```json title="One signed delivery · StartupBuilder-Signature"
{
  "$id": "https://api.sb/leaseline.app/events/event_6107",
  "$type": "Event",
  "name": "Post.replied",
  "at": "2026-10-17T15:22:09Z",
  "seq": 6107,
  "data": {
    "post": "post_88",
    "room": "r/PropertyManagement",
    "reply": "I rebuild our turnover calendar from a spreadsheet every January.",
    "problem": "problem_23",
    "window": "48h"
  }
}
```

```bash title="Reproduce it in test"
npx startup-builder trigger Post.replied --like event_6107   # replays the request
npx startup-builder clock advance --by 1d   # runs the build clock’s 24-hour check
npx startup-builder listen Post.replied --forward-to http://localhost:3000/hook
```

## Who runs it
**Content Lead · your agent** (`role:content-lead`, `worker_6`) holds the Key Result: it reads, ranks and builds. **You** (Dana Okafor, person, `worker_1`) post every call and every reply by hand from your own profile. Askers at companies over 100 units who ask about Leaseline go to **AE · Priya Shah (person)** (`role:sales-lead`, `worker_3`). Your number links to Did it work.

| Option | Rung today | Evidence (passed of n) | Moves up at | Drops back when | You can |
| --- | --- | --- | --- | --- | --- |
| Build it in 24 hours · Send a Sample | It does it, you can stop it | 62 of 64 (2 missed the clock) · 29 of 29 | met on day 8 (the first 10 builds) | any tool fails its known-answer cases → You approve each one | <Op verb="Action.cancel" /> before the link goes out |
| Answer in writing · Not this week · Not ours to build | You approve each one | 21 of 21 · 33 of 33 · 9 of 9 | never: every reply goes out under your hand | — | <Op verb="Approval.approve" /> · <Op verb="Approval.refuse" /> |
| To the AE | It does it | 3 of 3 | — | — | <Op verb="Action.redirect" /> |
| Change the scoring rule | You approve each one | 1 merged of 1 | never | — | <Op verb="Change.merge" /> · <Op verb="Change.revert" /> |
| Never: an asker named without their OK, a seeded request, a reply about what it watched | Refused, every time | 1 seeded request refused | never | — | nothing; the Checks hold it |

**What it reads · What it may call.** It reads the replies to your call and the URLs dropped in the thread, and fetches at most 20 public pages a Sample, never past a login or a form (`public-fetch`). A run count, a visit or an asker’s reach never appears in a reply. Its tools are <Op verb="Problem.rank" />, <Op verb="App.publish" />, <Op verb="Page.create" />, <Op verb="Conversation.answer" />, <Op verb="Problem.suggest" />, <Op verb="Lead.assign" />, <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:request-desk@1 · each line names its record key"
You hold the Content Lead Key Result: 15 entry starts per 100 askers by 2026-12-31. ← worker, metric
On each request, choose one option and say why; every asker gets an answer.      ← triggers, chooses, copyRules 3
Build the weekly 10 within 24 hours; the last 3 slots are a logged draw.         ← your file, line 4
Name an asker only after they agree.                                             ← copyRules 6; consent-stop
Name the entry Offer only when the asker asked about price.                      ← copyRules 12
Draft every reply for Dana to post by hand.                                      ← tactic request-reply
```

**The slow loop, as a Change.** `decision_571` (2026-09-21, weekly) read that requests naming a file people already keep (a spreadsheet, a rent roll) led to 5 of the first 7 entry starts, so `change_33` added 1 point to the score for them (your file, line 4) and Dana merged it with <Op verb="Change.merge" />. **Replayed on past requests**, <Op verb="Change.review" /> put entry starts at 13.0 per 100; read back at +28d it is 12.1, n 31, before-after, not proof (Example, day 56).

**Bring your own agent** (folded) starts at It does it, you can stop it for builds when it matches the seated agent on the eval suite; every reply stays yours to post. <Op verb="Role.staff" /> seats it.

```bash
npx startup-builder eval --scenario request-desk-64 --agent "claude -p" --seat content-lead   # seated: 62 of 64 inside 24 h, 0 Checks failed posted, $0.60 a tool · yours: 57 of 64, 1 known-answer fail
```

## What it can do next
| Option | Picked when | Decided by | Runs | Hands to | If it’s just you |
| --- | --- | --- | --- | --- | --- |
| Build it in 24 hours `build-the-tool` | a buildable request in the weekly 10 | Your rule (line 4) | <Op verb="Problem.rank" /> → <Op verb="App.publish" /> within 24 h → `requester-check-in` | you post the reply · Take this one | you |
| Send a Sample `send-a-sample` | a URL in the thread, under its cap of 30 | Your rule (the Sample cap) | <Op verb="Page.create" />: a noindex Sample of the checks it ran | you post the reply | you |
| Answer in writing `answer-in-writing` | the answer already exists | Agent’s call, with its reason | <Op verb="Conversation.answer" />, drafted | you post it | you |
| Not this week `not-this-week` | buildable, but outside the weekly 10 | Agent’s call, with its reason | <Op verb="Problem.suggest" /> → <Op verb="Conversation.answer" />: not this week, and when | you post it | you |
| Not ours to build `not-ours` | outside what Leaseline builds | Agent’s call, with its reason | <Op verb="Conversation.answer" />: what it is not, and why | you post it | you |
| To the AE `to-the-ae` | over 100 units, asking about Leaseline itself | Agent’s call, with its reason | <Op verb="Lead.assign" /> → <Op verb="Task.assign" /> | <Op verb="Task.assign" /> → AE · Priya Shah, due 1 business day · Take this one | you, within 1 business day |

| When they write back | Fixture reply | What happens | Who answers | By when | Call |
| --- | --- | --- | --- | --- | --- |
| Interested | “This is great. Does Leaseline do this every month?” | the entry Offer, because they asked; over 100 units, To the AE | you, from the draft | 1 business day | <Op verb="Conversation.answer" /> |
| Send me pricing | “What does the full thing cost?” | the Pricing Page’s list Price, in their thread | you, from the draft | 1 business day | <Op verb="Conversation.answer" /> |
| Not now | “Thanks, the free tool is all I need.” | nothing more; the check-in at day 30 still asks how it went | nobody | at once | <Op verb="Decision.list" /> |
| Wrong person | “I’m asking for my boss, she runs the portfolio.” | thanks them; it never writes to anyone they name | you, from the draft | 1 business day | <Op verb="Conversation.answer" /> |
| Out of office | an auto-reply to the day-30 check-in | the Interview ask waits for the return date | nobody | the return date | <Op verb="Message.schedule" /> |
| Question it can’t answer | “Can the tool read our old system’s export?” | To a person, with the file type in the Brief | you | 1 business day | <Op verb="Conversation.escalate" /> |
| Stop | “Please don’t message me again.” | the check-in and the Interview ask stop; the tool stays theirs | nobody | at once | <Op verb="Contact.suppress" /> |

## When it hands to you
Every reply lands in **your** send tray, because you post them all by hand; askers over 100 units who ask about Leaseline go to **AE · Priya Shah (person)**. One Brief per Role, as captured (`brief` is Not live yet, gaps #7).

```json title="What lands in each queue · sample"
[
  {
    "$id": "https://api.sb/leaseline.app/approvals/approval_95",
    "$type": "Approval",
    "verdict": null,
    "deadline": "2026-10-19T17:00:00Z",
    "draft": "Built it: drop your spreadsheet in and it lays out every turnover for the year…",
    "route": "build-the-tool",
    "checks": [
      {
        "check": "claims-resolve",
        "status": "pass"
      },
      {
        "check": "consent-stop",
        "status": "pass"
      }
    ]
  },
  {
    "$id": "https://api.sb/leaseline.app/tasks/task_644",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-10-07T15:00:00Z",
    "on": "lead_102",
    "brief": {
      "who": "Kai, Westbrook Lofts, 180 units",
      "said": "Does Leaseline do this for a whole portfolio?",
      "chose": "to-the-ae",
      "why": "over 100 units, asking about the product itself",
      "got": "the owner-report tool, built Oct 3",
      "never": [
        "a price beyond the list",
        "what the tool’s runs show"
      ]
    }
  }
]
```

You answer with <Op verb="Approval.approve" /> (you post it), <Op verb="Approval.refuse" />, <Op verb="Task.claim" /> (Take this one) or <Op verb="Task.return" /> with a reason, each a one-call window. A reply unposted 72 hours after the cutoff pages you once (`answer-clock`). A Task nobody claims by its due time goes up a Role through <Op verb="Task.escalate" />, and `person-promise` fires.

**On time:** you, 121 of 124 replies posted inside 72 h, median 26 h, n 124; AE · Priya Shah, 3 of 3 within 1 business day, n 3, ■□□□ Too early to tell beside Other Startups’ 96 % on time. **Your queue:** about 15 replies to post a week, in your Friday and Monday slots, plus 1 weekly review and the next call.

**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 |
| --- | --- | --- | --- |
| <a id="check-owned-by-a-person"></a>`owned-by-a-person` (rule j; gaps #8) | a reply or check-in to a Contact whose Lead or open Deal a person owns | Leave it to the person who owns it: the draft waits in their queue. | <Op verb="Task.assign" /> |
| <a id="check-correctness"></a>`correctness` (the record’s Correctness stop) | a link to a tool that fails a known-answer case | Fix the tool until its known-answer cases pass, then link it. | <Op verb="App.publish" /> |
| <a id="check-consent-stop"></a>`consent-stop` (gaps #3) | a tool Page or Sample that names the asker before they agreed | Ask the asker first, or leave their name off. | <Op verb="Message.schedule" /> |
| <a id="check-claims-resolve"></a>`claims-resolve` (hub) | a Sample sentence for a check it never ran, or a count with no date | Cut the sentence, or link the page and date it checked. | <Op verb="Content.draft" /> |
| <a id="check-seeded-request"></a>`seeded-request` (the record’s Seeded request stop) | a request from one of your own Handles, or anyone acting for you | Leave it out of the weekly 10; it is logged. | <Op verb="Problem.rank" /> |
| <a id="check-room-cadence"></a>`room-cadence` (Reddit and Hacker News) | a third call in one Room in a month, or a call to a Room whose last call drew no request | Skip that Room this time; it returns next month. | <Op verb="Post.schedule" /> |
| <a id="check-public-fetch"></a>`public-fetch` (the record’s Public fetch only) | a Sample past 20 pages, faster than 1 a second, or behind a login | Fetch only public pages, slowly; the Sample states what it skipped. | <Op verb="Page.create" /> |

| Stop (pauses the Play) | Pauses when | Then |
| --- | --- | --- |
| <a id="stop-build-clock"></a>`build-clock` | a picked request not live at 24 h; 3 misses in a week | one honest delay reply; next week’s count drops to 5 |
| <a id="stop-owner"></a>`owner` | no booked reply slot, or 7 days with no tray action | the next call does not post |
| <a id="stop-demand-floor"></a>`demand-floor` | 2 calls in a row with under 5 qualifying requests on a placement | that placement rests 4 weeks |
| <a id="stop-answer-clock"></a>`answer-clock` | a request unanswered 72 h after the cutoff | it pages you once |
| <a id="stop-room"></a>`room` (Reddit and Hacker News) | a moderator removes a call or a reply | that Room rests 30 days and is read again; it restarts at You approve each one |
| <a id="stop-venue-warning"></a>`venue-warning` | a restriction notice or an automated flag on any Handle | the Mandate on that Venue pauses at once |
| <a id="stop-sample-cap"></a>`sample-cap` | a drop-your-URL thread reaches 30 Samples or 48 h | the thread closes |
| <a id="stop-spend-limit"></a>`spend-limit` (the record’s Cost stop) | build or Sample compute reaches its Limit | new builds hold; raising it is an Approval (<Op verb="Limit.raise" />) |
| <a id="stop-entry-floor"></a>`entry-floor` | after 8 weeks and 50 shipped requests, 0 entry starts | the Play run stops |
| <a id="stop-kill-switch"></a>`kill-switch` | you press it | every Tactic and the Mandate pause; live tools stay up |
| + 1 more for the X lane: summons only (`?lanes=all`) | | |

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

```json title="The captured refusal · sample"
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The reply to u/glenwood_pm did not post: it says how many times their tool ran.",
  "checks": [
    {
      "check": "claims-resolve",
      "status": "fail",
      "doc": "/plays/request-desk#check-claims-resolve",
      "fix": "Cut the sentence, or link the page and date it checked.",
      "then": "Content.draft"
    },
    {
      "check": "consent-stop",
      "status": "pass"
    }
  ]
}
```


```json title="The Stops that fired, as Campaign.paused reasons · sample"
[
  {
    "reason": {
      "limit": "build-clock",
      "observed": "26h 10m",
      "bound": "24h",
      "window": "1 picked request"
    },
    "doc": "/plays/request-desk#stop-build-clock",
    "task": "task_627"
  }
]
```

## Did it work
Every asker gets an answer, so no half is held back and the basis is before-after (rule o): the columns read Now and Before, and nothing prints as Added. Each figure’s call is <Op verb="Metric.query" /> by node; the leaf and every node above it are Not live yet (gaps #4).

`12.1 entry starts per 100 askers against 4.5 before · before-after, not proof · n 58 · path → arr`

| Node | Now (56 days) | Before (the 90 days, per 56) | Added | Confidence | Basis |
| --- | --- | --- | --- | --- | --- |
| `requester-entry-rate` | 12.1 per 100 (7 of 58 matured askers) · 6 still maturing | 4.5 (1 of 22 answered by hand) | — · Worth about +$400 a month | — | before-after, not proof · Other Startups’ results +6.0 per 100, ■■■□ Likely, n 1,880 |
| `icp-reached` | 1,140 people reached by the calls and tools | 310 | — | — | before-after; first visits only |
| `new-arr` ↑ | $1,388, 4 Customers on Pro · Booked: credited, not all caused by this Play | $347, 1 Customer | — | — | before-after · 2 entry starts still deciding |
| `net-new-arr` · `arr` | carried from `new-arr` | carried | — | — | carried |

Before against after reads the 56 days against the 90 days before them, scaled to 56; it is not proof, and Other Startups’ results print beside it. The leaf counts entry Offer starts within 30 days per 100 askers who got a shipped tool or Sample link.

**How it moves it:** each asker got the tool they asked for at a median of 19 h, in their own thread, posted by you.

**Guardrails:** before against after: paid per entry start, 0.57 against 1.00 (`new-paying-customers` per entry; 1 of 1 before), and removed posts, 0 of 16 calls against none posted before.

```json title="The Campaign card · sample"
{
  "$id": "https://api.sb/leaseline.app/campaigns/request-desk",
  "$type": "Campaign",
  "play": "play:request-desk@1",
  "path": [
    "requester-entry-rate",
    "icp-reached",
    "new-arr",
    "net-new-arr",
    "arr"
  ],
  "experiment": {
    "metric": "requester-entry-rate",
    "unit": "per-100",
    "heldBack": 0,
    "decision": null
  },
  "readout": {
    "value": null,
    "n": 58,
    "maturing": 6,
    "interval": null,
    "readability": "inadmissible",
    "basis": "before-after",
    "pooled": true
  },
  "ledger": {
    "spend": 0,
    "workerCost": 41,
    "hours": 5.6,
    "pipelineArr": 2400,
    "wonArr": 1388,
    "projectedArr": 401,
    "paybackDays": 11
  }
}
```

Outside benchmark: this Play’s catalog record carries no sourced range yet, so Other Startups’ results stand in: +6.0 entry starts per 100 askers, ■■■□ Likely, n 1,880.

**Before it · After it.** Before it: `community-answers` finds the Rooms where your buyers post. After it: `free-tools` keeps the tools people return to, `signup-interviews` hears the day-30 Interview asks, and `product-led` holds the entry starts.

## Example
Leaseline ran it from 2026-08-24 to 2026-10-19 (56 days): 8 Friday calls in 2 communities, 156 requests, 64 tools built and 29 Samples sent, and every asker answered. Read every captured thread at `?threads=all`; three follow the tables.

| What happened, by option | Decisions | Answered within 72 h | Entry starts (credited, not all caused by this Play) |
| --- | --- | --- | --- |
| Build it in 24 hours | 64 | 64 (62 built inside 24 h) | 6 |
| Send a Sample | 29 | 29 | 1 |
| Answer in writing · Not this week · Not ours to build | 21 · 33 · 9 | 21 · 32 · 9 | 0 · 0 · 0 |
| To the AE | 3 | 3 | 1 Quote open ($2,400) |
| **All askers** · before | **156** · 22 answered by hand | **121** of 124 posted inside 72 h | **7** of 58 matured · 1 of 22 |

| Day | Event | What happened | Your time |
| --- | --- | --- | --- |
| 0 | `event_6003` Campaign.created | the three steps; the dry run fails `owner` | 15 min |
| 0 | `event_6005` Task.assigned | your Friday and Monday reply slots, 45 min each | 2 min |
| 1 | `event_6019` App.published | the first tool live: a vacancy-cost calculator, 19 h after the ask | — |
| 8 | `event_6061` Role.updated | promoted: builds and Samples ship after the known-answer cases pass | — |
| 23 | `event_6088` Campaign.paused | `build-clock`: one build took 26 h; you posted the delay reply | 4 min |
| 28 · 56 | `event_6094` Change.merged · `event_6131` Readout.created | a point for files people already keep: replayed at 13.0 per 100, read back at +28d at 12.1, n 31 | 5 min |
| 1–56 | `event_6012` Approval.created, first of 124 | you posted 124 replies in your slots; `claims-resolve` refused 2 drafts, each rewritten once and posted; weekly reviews | 5 h · **total 5.6 h measured, 6 h asked** |

> **u/rentroll_rita, r/PropertyManagement, Oct 17 15:22** · “I rebuild our turnover calendar from a spreadsheet every January.”
>
> **Dana, Oct 18 10:05** · Built it: drop your spreadsheet in and it lays out every turnover for the year, free.¹ leaseline.app/tools/turnover-calendar *Posted with the Role’s disclosure line.*²
>
> **Rita, Oct 18 11:40** · ran it 4 times that week, then started a Pro trial on Oct 19.

```diff title="u/glenwood_pm, 2026-09-14 · the reply claims-resolve refused, then the rewrite that posted"
- Glad it helped: you’ve run the owner report 23 times this week!
+ Glad it helped. If you want it to run every month on its own, say the word and I’ll show you how.
```

> **Kai at Westbrook Lofts, 2026-10-06 15:00** · “Does Leaseline do this for a whole portfolio? We have 180 units.” · **Dana, 15:20** · *Good question. Priya, our account lead, answers by tomorrow 15:00.*³ The Brief went to Priya (`task_644`), who replied at 10:12 the next day with a Quote.

¹ The promise kept exactly: the tool, free, within the 24-hour window the call stated. ² The disclosure line, compiled from the Role’s Settings; Dana posts it by hand. ³ The routed line, compiled from the Role’s Settings.

## Your settings
```mdx title="plays/request-desk.mdx"
---
holdout: 0        # every asker gets an answer; it reads before-after
call: friday      # one call a week, in r/PropertyManagement and Dana’s LinkedIn
---
Build the weekly 10 within 24 hours; the last 3 slots are a logged draw. A point more for files people already keep.
Draft every reply for Dana to post by hand.
```

```text
$ npx startup-builder show plays/request-desk
holdout 0 · call friday · weekly 10, 3 drawn · a point for kept files · Dana posts every reply     your file  plays/request-desk.mdx:2,3,5,6 (Ask 2026-08-24; line 5 by change_33, 2026-09-21)
worker role:content-lead, owns never · chooses 6 (2 rule, 4 read) · sequence requester-check-in · approval every-send, first-send · checks owned-by-a-person, correctness, consent-stop, claims-resolve, seeded-request, public-fetch · stops 10 · placements linkedin, x, reddit, hacker-news, github, google-search, mcp-registry    catalog  play:request-desk@1 (Not live yet, gaps #5)
```

### Every key from the catalog
| Key | Id | What it is |
| --- | --- | --- |
| Tactic | <a id="tactic-request-call"></a>`request-call` | Request call: Posts one weekly call per placement asking the niche for an annoying problem or a URL, with an exact promise and a 48-hour window. Starts at You approve each one. |
| Tactic | <a id="tactic-request-intake"></a>`request-intake` | Request intake: Reads every call reply and tool wish, refuses suppressed and seeded requests, and restates each as a merged Problem in the asker's words. Starts at Sends nothing. |
| Tactic | <a id="tactic-request-triage"></a>`request-triage` | Request triage: Classifies and routes each request, scores the buildable ones, and fills the weekly 10, drawing the last 3 slots by logged lottery. Starts at You approve each one. |
| Tactic | <a id="tactic-sample-fulfil"></a>`sample-fulfil` | Sample fulfilment: Runs the Startup's Verb or the sample kit on one dropped URL's public pages, and renders a noindex sample page claiming only what it checked. Starts at You approve the first wave. |
| Tactic | <a id="tactic-request-reply"></a>`request-reply` | Request reply: Queues one reply per asker in their own thread, with the link, the answer or the reason, and the founder posts each one by hand. Starts at You approve each one. |
| Tactic | <a id="tactic-request-agent-post"></a>`request-agent-post` | Agent Handle posts: Sends the call from the labeled agent Handle and the Startup's own Channel, and replies once with the link to each request that summoned it. Starts at You approve each one. |
| Tactic | <a id="tactic-requester-follow-through"></a>`requester-follow-through` | Requester follow-through: Checks each link, shows the entry Offer in the tool on repeat use, and sends one check-in and one Interview request by the founder’s hand. Starts at You approve each one. |
| Tactic | <a id="tactic-tool-three-faces"></a>`tool-three-faces` | Three faces: Builds one Tool as a Page, a keyless JSON endpoint and an MCP tool under one name, tested, limited and described for agents. Starts at You approve each one. |
| Tactic | <a id="tactic-tool-capture-handoff"></a>`tool-capture-handoff` | Capture and handoff: Shows the full result first, turns each save, watch or send into a Lead, and hands each user and agent caller the paid next step. Starts at You approve the first wave. |
| Tactic | <a id="tactic-tool-portfolio-review"></a>`tool-portfolio-review` | Tool portfolio review: Scores every live tool weekly on use, signups, citations and agent calls, and retires those below the line at day 90 to a public graveyard. Starts at Sends nothing. |
| Tactic | <a id="tactic-community-listening"></a>`community-listening` | Community listening reads licensed feeds for a watch list, drops what Suppression or the room’s record excludes, and ranks one candidate per thread. Starts at Sends nothing. |
| Tactic | <a id="tactic-room-rules-compile"></a>`room-rules-compile` | Room read reads each community place’s sidebar, pinned posts and top answers weekly into its room record and sets the room’s mode. Starts at You approve each one. |
| Tactic | <a id="tactic-room-check"></a>`room-check` | Room check is the Guard every community answer passes: mode, caps, karma floor, mention budget, links, duplicates and siblings, downgrading what it refuses. Starts at Sends nothing. |
| Tactic | <a id="tactic-founder-send-tray"></a>`founder-send-tray` | Founder send tray shows each approved draft with its source trail; the founder presses post by hand or through the Venue’s own posting path. Starts at You approve each one. |
| 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. |
| Trigger | <a id="trigger-request-call-due"></a>`request-call-due` | Request call due: `at` on `Schedule.fired`, window 1d. |
| Trigger | <a id="trigger-request-posted"></a>`request-posted` | Request posted: `event` on `Post.replied`, window 2d. |
| Trigger | <a id="trigger-url-dropped"></a>`url-dropped` | URL dropped: `event` on `Post.replied`, window 2d. |
| Trigger | <a id="trigger-tool-wish"></a>`tool-wish` | Tool wish: `event` on `Post.published`, window 1d. |
| Trigger | <a id="trigger-requester-repeat-use"></a>`requester-repeat-use` | Requester repeat use: `threshold` on `Tool.used`, window 7d. |
| Trigger | <a id="trigger-request-day-30"></a>`request-day-30` | Request day 30: `at` on `Schedule.fired`, window 7d. |
| Trigger | <a id="trigger-repeat-tool-use"></a>`repeat-tool-use` | Repeat tool use: `threshold` on `Tool.called`, window 7d. |
| Trigger | <a id="trigger-tool-day-90"></a>`tool-day-90` | Tool day 90: `at` on `Version.deployed`, window 14d. |
| Sequence | <a id="sequence-requester-check-in"></a>`requester-check-in` | Requester check-in: 2 steps; it ends on Reply; Entry Offer started; Opt-out; Suppression; Tool retired; Fewer than 3 runs by day 30, before the Interview ask. |