Skip to content

Nouns

A file in nouns/ declares one Noun the Startup adds or refines, with its properties, Verbs and states, and compiles to its API.

A file in nouns/ declares one Noun the Startup adds or refines. ls nouns/ lists the Startup's own API, and Nouns shows every Noun it inherits.

  • nouns/
  • Lease.mdxthe Lease Noun: properties, Verbs, states; the body is its docs
  • Lease.renew.tsthe Function behind Lease.renew
  • Lease.renew.test.tsits cases

Reference

The file name is the Noun's name, capitalized as it is written in code. Frontmatter is the record, and the body is the Noun's documentation on every Interface.

KeyTypeHolds
extendsNoun namesThe Nouns it inherits from, such as Thing or Task; several are allowed
propertiesmapEach property's type: a scalar, A | B for an enum, or a Noun name for a reference. A name ending in ? is optional
verbsmapThe Verbs it declares beyond create, get, list, update and delete, each with its inputs
stateslistThe lifecycle, compiled from the Verbs; write it only where the compiled order is wrong

Verb inputs

Each key under verbs is a Verb, and its value maps each input to a type. Inputs take the same types as properties, and a name ending in ? is optional. {} declares a Verb that takes only the record.

YAML
verbs:
  renew: { months: integer, increase?: number }
  notify: {}

The record comes first, named for the Noun, so renew takes lease, months and increase. Each Verb compiles to one input type in .sb/types/, named for the Noun and Verb:

.sb/types/Lease.d.ts
interface LeaseRenewInput {
  lease: SB.Id
  months: number
  increase?: number
}

$.Lease.renew checks its input against that type, and the Verb function takes it as its second argument.

Examples

Minimal

nouns/Lease.mdx
---
properties:
  unit: string
---

Leaseline

Leaseline tracks lease renewals for small property managers. It declares a Lease Noun.

nouns/Lease.mdx
---
extends: [Thing]
properties:
  unit: string
  resident?: Contact
  endsOn: date
  rent?: money
  status: active | renewing | renewed | ended
verbs:
  renew: { months: integer, increase?: number }
  notify: {}
---
A Lease is one resident's agreement on one unit, from signing to renewal.

What it builds

The SoftwareBuilder compiles the file. One Lease.mdx produces:

  • the Lease Noun with create, get, list, update and delete
  • Lease.renew, which takes lease, months and an optional increase, and Lease.notify, which takes lease, each in every form: renew, renewing, renewed, renewedBy
  • the Events Lease.created, Lease.renewed and Lease.notified
  • typed SDK methods, CLI operations, MCP tools and OpenAPI paths, with types in .sb/types/
  • a screen per record and a form per Verb in every App that mounts the Noun

Routing

InterfaceForm
APIGET /leaseline.app/leases, GET /leaseline.app/leases/{id}, POST /leaseline.app/leases/{lease}/renew
SDK$.Lease.list(), $.Lease.get({ id }), $.Lease.renew({ lease, months: 12 })
CLInpx startup-builder do Lease.renew --json '{"lease":"lease_1","months":12}'
MCPdo with $.Lease.renew({ lease: 'lease_1', months: 12 })

get, update and delete name the record id; renew, notify and every other Verb name it by the Noun, lease. The API spec has the rule.

A Verb is a path segment and never a suffix. A record or Collection named like a declared Verb is refused at write time.

Good to know

  • status holds the states. create starts it at its first value, and only a Verb or an Event moves it: no create or update input takes it.
  • Nouns sit at the root even when one Product uses them, so two Products share one Noun.
  • A file named for an inherited Noun refines it: its properties add to the inherited ones.
  • The Function behind a Verb lives beside the Noun in Verb functions.