v0.5.1 — an app stops being a guest and starts owning a screen
An app stops being a guest in someone's conversation and starts owning a screen. 0.5.0 made an app's declaration a first-class object; 0.5.1 asks the next question — where is this app standing? — and gives it three answers: a card in a chat, a page it owns, or a region inside a host's panel. One contract covers all three.
Highlights
- The stage contract. Every app used to hand-roll its own outer card, hero header, root width and overflow policy — 7 different frame styles and 10 different width values across the store, double-rounded corners on phones. Now the kit owns the wrapper: in a chat the app gets one standard conditional card (and on narrow frames, none — the host's widget frame is the card); on a page or panel it renders bare, edge to edge. Apps declare their width posture in one manifest word (
stage.width: column | wide | fluid), and all 22 store apps have been rebuilt to the contract — decorative identities (gradients, rings, accent bars) moved into content, where stripping the frame can't take them. @live— a brick, not a route. A display that follows whatever the AI opened last is now a primitive: any app can placeoma.embed("@live"), and the engine keeps a single overwritten pointer (schema v7, deliberately not a ledger event — opening an app is a glance, not a data change) and pushes it over the existing SSE channel. The store ships a ready-made Live Display app: install it, open/view/liveon a spare tablet, and the screen switches by itself as the AI works. Apps that contain@livedeclarestage.displayand are excluded from the pointer — a wall never points at itself.- Panel hosts are first-class. Two opt-in URL words for anyone embedding
/viewin their own chrome:?chrome=0(no viewer bar or stage — the panel draws its own) and?nav=intent(app→app links become anopenmcp:open-apppostMessage instead of navigating the frame — "open X" is a request to the host, not this page's navigation). Embedded child documents now inherit their parent's context, andstage.displayapps render chrome-less on/viewby default.
Fixed, found on real devices
- No sandboxed child document had ever reported its height — a minified-bundle name mismatch landed in the broadcast's own
catch, silently, since the runner shipped. Every embedded frame sat at 140px forever. One line; frames now size to content. - Forms inside embedded apps couldn't submit at all: the sandbox lacked
allow-forms, and Chrome refuses thesubmitevent before dispatch — so everyonsubmithandler (17 of 23 store apps hang their add/edit on one) never ran. Granted, with the actual submission still triple-walled off. - Apps taller than their frame couldn't scroll in fixed-height contexts: seven store apps pinned
overflow: hiddenon the root, which is correct in a host that grants height and a dead scroll wheel in one that doesn't. The viewer now unlocks the root; the apps handed in their declarations.
Upgrading
- A 0.5.0 store upgrades in place on first open (v6 → v7: one added table, one transaction). A store opened by 0.5.1 cannot be opened by 0.5.0 — upgrade every host registration together.
- Tool surface,
oma.contract, and the runtime API are byte-for-byte unchanged from 0.5.0.manifest.stageis optional and additive.
Full detail, including the measurement behind every line: CHANGELOG.md.