The definition
Four files define Leaseclock. Every key you write has an anchor, and each lists the outputs it generates.
- Reads
Startup·Noun·Offer- Generates
- all 34 outputs
The sample
---$type: Startup$id: leaseclock.comname: Leaseclockdescription: Tracks lease renewals for small property managers.pitch: No renewal slips past its date.icp: small property managersbrand: Leaseclock------$type: Noun$id: leaseclock.com/nouns/Unitname: Unitfields: label: { type: text, required: true } building: { type: text }------$type: Noun$id: leaseclock.com/nouns/Leasename: Leasefields: unit: { type: link, target: Unit, required: true } renter: { type: email, required: true } endsOn: { type: date, required: true, indexed: true } status: { type: choice, options: [{ key: active }, { key: ended }] }verbs: renew: does: Move the end date forward input: { endsOn: { says: the new end date, type: date, required: true } } from: [active] fn: { kind: code, body: replace } end: { does: End the lease, from: [active], to: ended }------$type: Offer$id: leaseclock.com/offers/proname: Leaseclock Proprice: { amount: 29, currency: USD, unit: month }limits: { Unit: 200 }personas: Property manager, Leasing coordinatorstatus: Live---Each key line is an anchor: #definition--Noun.Lease.name.
Fields
A field's type sets its filter and its schemas on every Interface.
| Type | In Leaseclock | Filter | JSON Schema · Zod |
|---|---|---|---|
text | Unit.label, Unit.building | exact, in, prefix | string · z.string() |
email | Lease.renter | exact, in | format: email · z.email() |
date | Lease.endsOn | exact and range: endsOn[lte]=2026-11-30 | format: date · z.iso.date() |
link | Lease.unit | exact, in | string, link: Unit · z.string() |
choice | Lease.status | is, is not, in, not in, by option key: status=active | enum · z.enum(["active", "ended"]) |
money | Lease.rent, from Change one line | exact and range | number · z.number() |
Money is an amount in major units plus a currency, as the Offer writes its price: amount: 29 is $29.
indexed: true on endsOn adds sort=endsOn and the Admin's Ends before filter.
Verbs
What you write as says: is what your agent reads.
type LeaseRenewInput = { /** the new end date */ endsOn: string }
/** Move the end date forward · active · modes try|do */| You write | It generates |
|---|---|
input: { endsOn: … } | LeaseRenewInput, the Renew dialog's form, and the body of POST /leases/4b/renew |
from: [active] | active in the doc line; Renew disabled on an ended Lease, with the reason; 422 Refused on any other call |
to: ended | End sets status to ended, and an End button on each Lease |
fn: { kind: code, body: replace } | The Function renew runs on commit. Override its body, and its URL, preview, undo, button and agent call stay generated |
Names
Name it once. The name is the address.
| You write | It becomes |
|---|---|
name: Lease | the Collection leases; /leaseclock.com/leases; $.Lease, with 8 methods; show /leaseclock.com/leases on the CLI; the Admin's "Leases" list |
does: Move the end date forward | the doc line your agent reads on $.Lease.renew, and the Renew button's tooltip |
says: the new end date | the Renew dialog's one field, and the Docs page's input label |
The engine refuses a name that breaks this grammar with 400 Invalid input, and the message names the fix.
| You write | The refusal |
|---|---|
name: lease | name is a Noun's name: PascalCase, letters and digits, at most 64 (got "lease") |
EndsOn: { type: date } | field "EndsOn": a field key is camelCase, starting with a lower-case letter |
Renew: { … } | verb Renew: a Verb is named by its action form: camelCase |
What a definition generates
Write four files: a Startup, its Nouns and Verbs, and an Offer. They generate the App, API, CLI, MCP, SDK, Site, Docs and Blog, with Stripe billing.
One Lease, every Interface
One grammar reaches the Lease on the API, SDK, CLI, MCP and Docs. Every Verb returns one Action, and every refusal names its fix.