Build a custom machine

Pages and cards

Python SDK version 1

Markdown

A page is a function the Ownbox calls each time a person opens it. It answers screen.json: blocks the Ownbox draws in its own look, phone first.

Python
@m.screen(m.home, title="Jobs")                    # /my/<slug>; owner_only=True for a page only the owner opens
def home(query, person):                           # it may take query, person and path, by name
    return {"v": 1, "title": "Jobs", "lede": "What is open today.", "blocks": [
        {"kind": "figures", "items": [{"value": 3, "label": "open"}]},
        {"kind": "list", "items": [{"text": "Fix the gutter", "href": m.home + "/jobs/41"}]},
        {"kind": "actions", "items": [{"run": "sync", "label": "Sync now"}]},      # a job it declared with m.every
        {"kind": "settings", "fields": [{"key": "min_quote", "label": "Smallest job", "type": "number", "min": 0}]}]}

The page function takes any of these, by name:

ArgumentIs
queryThe page's query string as {name: value}: at most 10 names, each value at most 200 characters.
personWho is viewing: {"id", "role"}. Pass person["id"] to m.notify.
pathThe address asked for, for a page declared above it (/my/<slug>/jobs/41 under m.home + "/jobs").

screen.json is {"v": 1, "title", "lede"?, "blocks": [...]}: a title of at most 120 characters, a lede of at most 300, and at most 40 blocks and 64 KB as JSON. Every block takes an optional title of at most 80 characters.

BlockFieldsLimits
texttext2,000 characters; a blank line starts a paragraph.
figuresitems: [{value, label, hint?}]1 to 6 items; value a number or 24 characters, label 40, hint 80.
listitems: [{text, detail?, when?, href?}], empty?50 items; text 200, detail 300; when an ISO time.
tablecolumns: [...], rows: [[...]]1 to 8 columns, 100 rows, 120 characters a cell.
actionsitems: [{run, label}]1 to 3 buttons; run names a job it declared; label 60.
settingsfields: [{key, label, type, help?, ...}]12 fields; label 80, help 200.

Settings fields are the only input a page takes. The Ownbox draws the form, checks each value, and saves it, for the owner only, into the machine's own settings under the field's key: read it with m.setting(key). A key its page did not declare is never written.

TypeTakesThe Ownbox checks
textmax (default 200, at most 500)One line, no control characters.
text with lines: truemax (default 2,000, at most 5,000)Newlines kept, no other control characters.
numbermin, maxA number in range.
toggle—true or false.
choicechoices: 2 to 12, each at most 60 charactersOne of them, exactly.
url—https:// with a host, at most 2,000 characters. Shown as text, never as a link.
itemsfields (1 to 4 sub-fields), max (1 to 50), title?, toggle?, unique?A list of small records, each checked against its sub-fields.

An items field saves [{"id": "<the Ownbox's own>", "<sub-field>": value, ...}], newest last. Its sub-fields are any type above except items and multi-line text, and none may be named id. A save made from an older copy of the list is refused with the list as it is now, never merged quietly.

The rules the Ownbox draws by:

  • Every string is plain text. The Ownbox escapes it, so markup shows as written.
  • A link (href) is kept only when it is one of the machine's own pages, under m.home. Any other is dropped and the line kept.
  • A button runs one of its jobs as if its time had come. The job does the work, never the page. At most one run of a job waits at a time. The Ownbox remembers the buttons a page drew for each role, not each person: a button drawn for one member is every member's.
  • An answer that fails a check is not drawn. The page says This page couldn't be shown, with the reason, which names the field.
  • A machine declares at most 20 pages and 10 cards.
  • The owner's AI reads its pages in words, through the Ownbox's own tool for it. A page only the owner opens is never read for an AI.

A card, m.panel(slot, title=, render=), draws on another screen's slot. render() answers screen.json of at most 6 blocks and no settings block, or an HTML body. It may take person by name. A card is drawn for anyone signed in: check person["role"] for what only the owner should see. Today the Inbox's screen offers the slot inbox.

sdk.page(path, title=, lede=, body=) answers with HTML instead, for a machine written before screen.json. The Ownbox keeps p h2 h3 h4 ul ol li table thead tbody tr th td strong em b i br hr blockquote code pre small span div and a (a link to its own pages only). It cuts script, style, iframe, form, img and the like with everything they hold, and drops every attribute but class (card, quiet, figure, row), colspan and rowspan.

Those are every block and every field type a page can hold: the Ownbox refuses any other kind. Their limits are listed again under Limits.