BEROUNOS for AI-native devices

System API

Dialogs, sound, vibration, screens.

The calls an app, a service or Caroline uses to talk to the owner and to the hardware, the same for all of them.

Beroun gives every app the same small set of ways to reach the owner and the hardware: a modal dialog, a sound, a vibration, a notification and a second screen. They are called the same way by an app's page, by a service, and by Caroline, so a person and the assistant always see the same thing.

Who may call

An app's page (known by its address) or a service of a manifest (header X-IntelliCat-Service-Id). Nobody else. In system dialogs only the cursor, A and B have a job.

MessageBox

A modal message drawn over the frontend in the shared window. One shows at a time and the next waits in a queue. A box with no page to show it waits for the next page that connects, so closing an app never loses it.

Saved Your note is on the card. OK ok Delete note? This cannot be undone. Yes No yesno Leave? Unsaved changes. Yes No Cancel yesnocancel Update ready Caroline 1.2 Install now Later buttons: 1 to 4 of your own ← → choose · A confirms · B cancels · icon: none, info, question, warning, error
The standard layouts, and your own button texts.
POST/api/msgbox{title, text, kind | buttons, icon, default, timeout, wait}
GET/api/msgbox/result?id=&wait=the answer, or {id, pending: true}
POST/api/msgbox/cancel{id}
  • kind: ok, okcancel, yesno, yesnocancel, or buttons (1–4 texts, each up to 24 characters).
  • timeout in seconds: 0 waits until answered, default 120, maximum 3600. Title up to 60 characters, text up to 400.
  • The answer is {id, index, button, reason} with reason one of button, cancel, timeout, cancelled.
From a page
const r = await Platform.messageBox({ title: 'Delete note?', text: 'This cannot be undone.', kind: 'yesno', icon: 'question' }); if (r.reason === 'button' && r.index === 0) deleteNote();
From a service, without waiting
curl -XPOST localhost:8765/api/msgbox -H 'X-IntelliCat-Service-Id: backupd' \ -d '{"title":"Backup done","text":"1.2 GB saved.","kind":"ok","icon":"info"}' # → {"id":"7f3a…"} later: curl 'localhost:8765/api/msgbox/result?id=7f3a…&wait=30'

System sounds

Eight tunes, generated once and played by the system: notify, message, ok, warning, error, click, alarm, ring. Do not disturb silences all of them except the priority sounds alarm and ring; force: true overrides it.

GET/api/sound/list
POST/api/sound/play{name, force}
Platform.sound.play('ok'); Platform.sound.play('alarm', { force: true });

Vibration

A pattern is a name or a list of whole milliseconds, on/off/on…

NamePattern
tap30 ms
short80 ms
long400 ms
double, alarm, ringPredefined rhythms
A listUp to 20 steps, 2 s each, 10 s in total: [100, 50, 100]
GET/api/vibraenabled, patterns, max_ms
POST/api/vibra/pulse{pattern, strength 0–100, force}
POST/api/vibra/stop
Platform.vibra.pulse('double'); Platform.vibra.pulse([100, 50, 100], 60); // pattern, strength 0–100 Platform.vibra.stop();

The system setting vibration turns the motor off for everyone. Do not disturb silences it except for alarm and ring.

Notifications

One call raises a notification in the status bar and the panel (see Notifications).

Platform.notify('Timer finished', { level: 'info', sound: 'notify', vibrate: 'short' }); curl -XPOST localhost:8765/api/notify -d '{"app":"clock","text":"Timer finished"}'

The external display

An app with an external section has a big page for a second screen: an extended desktop with one fullscreen window. The app's own page becomes the remote control. Apps that opened a big page form a stack. The top one is shown; an empty stack shows the cat splash. When the top one closes, the one below returns at its saved place.

the app's page the remote · 640×480 Console screen the big page fullscreen on the monitor External monitor messages top of stack covered app covered app cat splash SELECT switches input focus between the screens · MODE closes the newest big page
Two pages per app, one stack of big pages.

With a monitor attached the left stick is the mouse, the right stick is the wheel, and X/Y are the mouse buttons, while the focus is on the external screen. A game ("external": {"input": "game"}) keeps every button as the gamepad's while it is on top. Audio stays on the device's speaker.

manifest.json
"external": { "entry": "big.html", "state": true }
The console page
const s = await Platform.display.status(); // {connected, width, height, focus, top, stack} const stop = Platform.display.on(e => { // {event: connected | disconnected | resize | focus | stack, ...status} if (e.event === 'connected') Platform.display.open(); }); Platform.display.send({ slide: 4 }); // JSON up to 64 KB, delivered while the big page is on screen
The big page
const { arg, resume } = await Platform.display.launch(); // once Platform.display.onMessage(m => showSlide(m.slide)); Platform.onSuspend(async reason => { // covered | closed | unplugged | reopen await Platform.state.set({ slide }); // 2 seconds; the big page's state is its own });
HTTPMeaning
GET /api/displayStatus
POST /api/display/open|close|sendopen answers 409 without a screen and 404 for an app without external
GET /api/display/launchFor the big page: {arg, resume}
POST /api/display/focus {to}Move input focus between screens

A big page is the app's page with ?ext=1, and its /appws channel is ?screen=big. Plugging and unplugging the monitor and its resolution come from the platform (Targets).

Caroline and the system API

She has a tool for every route (beroun_*), reached as the owner: files, settings, the clock, network, power, sleep, services, notifications, MessageBox (beroun_message_box, which waits for the button), sounds, vibration, her own updates, the external display and the store. Caroline in the system →