Apps on the Service
Declare an app’s entities and flows in app.yml, keep its records on the service, run published blueprints over them, and build pages that read and post to it with a scoped key.
After reading this guide, you will know:
- What an
app.ymldeclares: entities, their fields, and flows. - How to check, push and pull an app with
reckoning app. - How to describe an app for building a page, and make a key a page may use.
- How to list an app’s records.
- How to build a page for an app with the
reckoning-app-pageskill, and where a page can be opened from.
What an App Is
A blueprint works out values from facts. An app on the hosted service keeps the facts too: it declares entities, the kinds of structured data it stores (rooms, bookings, invoices), records of them saved on the service, and flows that gather records as facts, run a published definition and save its outputs back as records, linked to the run that made them.
Pages are yours. A page is plain HTML and JavaScript kept wherever you like (a file, a static host, an artifact) that reads and posts to the service’s JSON API with a scoped key, from an origin the key allows. The service never stores pages.
The service defines apps; the engine only talks to it. The full description, every endpoint and every answer are in the service’s Apps guide and OpenAPI spec at reason-me-this.com, where the Apps page lists each app’s records.
app.yml
app: hall # the app's name, unique in a workspace
name: Hall hire
entities:
room:
label: name # the field shown when a record is referred to
fields:
name: {type: string}
hourly_rate: {type: number}
booking:
label: hirer
fields:
room: {type: reference, to: room}
hirer: {type: string}
start: {type: time}
finish: {type: time}
invoice:
label: booking
fields:
booking: {type: reference, to: booking}
hours: {type: number}
total: {type: number}
flows:
invoice:
blueprint: hall_invoice # a definition in the workspace: its live version, or hall_invoice@3
start: booking # the entity whose record starts the flow
facts: # each input of the blueprint, and where its value comes from
hourly_rate: start.room.hourly_rate
from: start.start
to: start.finish
save: # records to make from the outputs
invoice:
booking: start.id
hours: outputs.hours
total: outputs.total
A field is declared as a blueprint input is, with the same types (number, string, date, time,
boolean, list) and options (optional, one_of, default), plus reference, a record of another
entity of the same app (to:). The service checks a record as a blueprint checks facts, so a record that
saves is one a blueprint can take.
A fact can also gather records into a list input: sessions: {records: booking, where: {room: start.room},
fields: {from: start, to: finish}} gives each booking of the starting record’s room as {from, to}.
The Commands
Set RECKONING_API_KEY (and RECKONING_API_URL for a service other than the hosted one), as for the
other service commands.
| Command | Request | Prints | Exit |
|---|---|---|---|
reckoning app check FILE |
POST /apps/check |
{"problems": [...]}, without saving |
0, 2 for problems |
reckoning app push FILE |
PUT /apps/APP, APP from the file’s app |
{"app", "entities", "flows", "warnings"} |
0, 2 for problems |
reckoning app pull APP [-o FILE] |
GET /apps/APP |
the app.yml, or writes FILE (never over a file) | 0, 1 |
reckoning app describe APP |
GET /apps/APP/describe |
entities, fields, JSON Schemas, flows and paths (a summary in text) | 0, 1 |
reckoning app key APP --origin URL ... |
POST /keys |
the new key, shown once | 0, 1 |
reckoning app records APP ENTITY [--where FIELD=VALUE] |
GET /apps/APP/ENTITY |
the records | 0, 1 |
Each answers in text at a terminal and in JSON elsewhere, or as --json and --text choose, and exits
1 when the service has no such app or entity, 69 when it cannot be reached and 77 when it refuses the key.
$ reckoning app check app.yml
✓ No problems
$ reckoning app push app.yml
✓ Saved hall: 3 entities (room, booking, invoice), 1 flow (invoice)
$ reckoning app describe hall
Hall hire (hall) at https://reason-me-this.com/api
Entities
room, shown by name
name string
hourly_rate number
booking, shown by hirer
room reference to room
hirer string
start time
finish time
...
Flows
invoice runs hall_invoice from a booking, saving invoice
$ reckoning app records hall booking --where room=3
ID ROOM HIRER START FINISH RUN
7 3 Riverside Choir 2026-11-02T16:00:00+11:00 2026-11-02T22:00:00+11:00
A push that removes or retypes a field that records already hold says so as a warning; it saves, and the records keep what they hold. A push that removes an entity with records is refused.
Keys for Pages
A page should never hold a full key. reckoning app key makes one that may only describe the app and do
what you grant, from the origins you list:
$ reckoning app key hall --origin https://hall.example.com --read room --write booking --run invoice
✓ Made key hall page
key rmt_...
grants apps:read:hall, records:read:hall/room, records:write:hall/booking, flows:run:hall/invoice
origins https://hall.example.com
The key is shown only now; keep it.
| Option | Grants |
|---|---|
| (always) | apps:read:APP, describing the app |
--read ENTITY |
records:read:APP/ENTITY |
--write ENTITY |
records:write:APP/ENTITY, which reads them too |
--run FLOW |
flows:run:APP/FLOW, which saves the records the flow makes |
--origin URL |
a page served from URL may use the key: https://..., http://localhost:PORT, or null for a page opened from a file |
--name NAME |
the key’s name, APP page unless given |
The key in RECKONING_API_KEY must be a full key to make one.
Building a Page
The engine repository holds a Claude Code skill that writes a page for
an app: skills/reckoning-app-page. Install it by linking (or copying) the folder into your own skills,
or into a project’s:
ln -s /path/to/reckoning/skills/reckoning-app-page ~/.claude/skills/reckoning-app-page
# or, for one project
mkdir -p .claude/skills && cp -r /path/to/reckoning/skills/reckoning-app-page .claude/skills/
Then ask Claude Code for a page (“make me a bookings page for the hall app”). The skill runs
reckoning app describe APP --json, asks which screens the page needs, makes a key with just the grants
those screens use, and writes one HTML file from its template.html: no build step and no external
scripts. The file has a config block at the top for the service’s address, the key (or leave it blank and
the page asks once and keeps it in that browser), the offset new times are written in, and its screens.
A page lists, adds, edits and deletes an entity’s records, with a form built from the field types and a
select for each reference filled from the referenced entity, shown by its label. A flow screen runs a
flow from one of its start records (Run saves, Try does not), and shows the outputs, the records it saved
and the run that made them. The service’s problems and error answers are shown as they come. It has
light and dark themes and fits a phone.
Where a Page Can Be Opened From
The key’s origins are where the page is opened from: null for a file opened from disk,
http://localhost:PORT while developing, https://... for a static host. The page’s Connection panel
shows its own origin. A claude.ai artifact cannot call the service: the artifact sandbox only lets a page
fetch from a few CDNs, so its requests are blocked before any key is checked. Keep the page as a file,
serve it from localhost, or put it on a static host.
The Hall Hire Example
docs/examples/apps/hall in the engine repository is the app above, ready to push:
| File | Holds |
|---|---|
app.yml |
Entities room, booking and invoice, and the flow invoice: from a booking, run hall_invoice with its room’s rate and save an invoice |
hall_invoice.yml, hall_invoice_cases.yml |
The blueprint: the hours from start to finish, and the total at the hourly rate |
describe.json |
What reckoning app describe hall --json answers, for building pages before the app is pushed |
pages/invoices.html |
A page made from the skill’s template: the bookings, Run and Try on each, and the invoices saved |
reckoning push hall_invoice docs/examples/apps/hall/hall_invoice.yml docs/examples/apps/hall/hall_invoice_cases.yml
reckoning publish hall_invoice
reckoning app push docs/examples/apps/hall/app.yml
reckoning app key hall --origin null --run invoice --write booking --read room --read invoice
Open pages/invoices.html from disk, paste the key into its Connection panel, add a booking and run it.
Next Steps
- The Hosted Service - Definitions, versions and the other service commands.
- CLI Commands and Exit Codes - Every command, local and remote.
- Blueprint Format - The input types and options a field takes.