# Build my app

URL: /products/app/build-my-app · Id: `guide:build-my-app`

> Say "build the app my customers sign in to" and get an App with a screen per kind of record, a form per action, sign-in and a workspace per customer.

Your [App](/business/nouns/app) is built from the [Software](/business/nouns/software) you sell and the people who sign in, and ships to every customer at once. Each kind of person is a [Persona](/business/nouns/persona).

Needs: [Startup](/business/nouns/startup)

**Before it runs**

- Who says yes: You. Your agent shows you the run and waits for your [Approval](/business/nouns/approval).
- You leave the chat: Never: it all happens in the chat.
- First question at Idea: “Who signs in, and what is the first thing they do?”
- First question at Live: “Preview it with one customer first?”

## What you get
- 1 product your customers use (Software)
- 1 app at app.leaseline.app, under your brand (App)
- 1 profile per kind of person who signs in (Persona)
- 1 list and detail screens for each kind of record a person may read (Dashboard)
- 1 form for each action a person may take (Flow)
- 1 access rule behind every button (Role)
- 1 Markdown and JSON form of every screen, for agents (Dashboard)
- 1 install from the browser on any phone (App)

## Your agent does
**For agents**

- Guide: `guide:build-my-app`, status `beta`. Page: [/products/app/build-my-app.md](/products/app/build-my-app.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it.
- Leaves the chat: never.
- Needs first: [Startup](/business/nouns/startup).
- Run: call the steps in order, each through the API, SDK, CLI or MCP tab below; a later step passes the `$id` an earlier one returns. Each value marked example is the sample business’s: pass the founder’s own.

| Step | Verb | Inputs (type, required, this guide’s value) | Returns |
| --- | --- | --- | --- |
| 1 | [`Software.create`](/business/nouns/software/create) (`verb:Software.create`) | `name` string, required: example `"Leaseline"`; `promise` text, required: example `"Every lease renewal date in one place, with a reminder 90 days out."` | `software` Software |
| 2 | [`App.publish`](/business/nouns/app/publish) (`verb:App.publish`) | `app` App (an id), required: the `$id` of the first Interface `Interface.list` returns for `where: kind = app` | `app` App |

Returns: the last call answers with `app` and its `action`, whose `status` is `done`, `pending` (waiting on an Approval or a Worker), `failed`, `canceled` or `refused`:

```json
{
  "api": "https://api.sb/leaseline.app",
  "app": {
    "$id": "https://api.sb/leaseline.app/apps/interface_1",
    "$type": "App"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/action_1",
    "operation": "App.publish",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/action_1"
  }
}
```

Next: offer “Add an owner view that shows every property at once”, or “Hide rent amounts from the maintenance Persona”.

Calls: `Software.create` → `App.publish`

Ask:

```text
Build the app my property managers sign in to.
Give each customer a dashboard of their leases and renewal dates.
Make an app where a manager sees which renewals are due this month.
```

API:

```bash
# 1. Software.create
curl -X POST https://api.sb/leaseline.app/software \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Leaseline","promise":"Every lease renewal date in one place, with a reminder 90 days out."}'

# Look up the Interface: Interface.list
APP=$(curl "https://api.sb/leaseline.app/interfaces?where=kind%20%3D%20app&limit=1" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" | jq -r '.interfaces[0]["$id"] | split("/") | last')

# 2. App.publish
curl -X POST https://api.sb/leaseline.app/apps/$APP/publish \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

SDK:

```ts
import { $ } from 'startup-builder'

await $.Software.create({ name: 'Leaseline', promise: 'Every lease renewal date in one place, with a reminder 90 days out.' })
const [app] = await $.Interface.list({ where: 'kind = app', limit: 1 })
await $.App.publish({ app: app.$id })
```

CLI:

```bash
npx startup-builder do Software.create --json '{"name":"Leaseline","promise":"Every lease renewal date in one place, with a reminder 90 days out."}'
APP=$(npx startup-builder do Interface.list --json '{"where":"kind = app","limit":1}' | jq -r '.interfaces[0]["$id"] | split("/") | last')
npx startup-builder do App.publish --json '{"app":"'"$APP"'"}'
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "await $.Software.create({ name: 'Leaseline', promise: 'Every lease renewal date in one place, with a reminder 90 days out.' })\nconst [app] = await $.Interface.list({ where: 'kind = app', limit: 1 })\nreturn await $.App.publish({ app: app.$id })"
  }
}
```

## Change it
- Add an owner view that shows every property at once.
- Hide rent amounts from the maintenance Persona.
- Add a renewal calendar to the home screen.

## Under the hood
- Systems: [Customer access](/systems/customer-access), [Sites](/products/site/sites)
- Nouns: [Software](/business/nouns/software), [App](/business/nouns/app), [Persona](/business/nouns/persona), [Role](/business/nouns/role), [Permission](/business/nouns/permission), [Dashboard](/business/nouns/dashboard)
- Events: `Software.created`, [`App.published`](/business/events/App.published)