Cockpit
Overview
The Cockpit combines the account's live modules in one workspace. The user guide covers arranging tiles, presets and docks. The server stores a working state for each (account, user) pair. It has one base slot (preset_id: null, shown as Without preset) and one draft per visible saved Cockpit preset. A named preset is a setting preset of kind cockpit; the base slot is outside the preset quota.
The Cockpit requires feature:cockpit; named presets also require feature:setting_presets. Each tile still checks its own feature and permission. The workspace and its drafts are personal state: a session, the user's own API key or a popout token bound to that user can read and write them in that account. A popout token may create, rename, set default and delete only its bound user's cockpit presets; sharing with members requires a first-party sign-in and presets:share. Other credential classes, including MCP and System keys, cannot use the workspace. The same identity and feature checks apply to GraphQL and REST.
Versioned document
A saved cockpit preset has a JSON payload with format: "lumio.cockpit" and version: 1. It contains layout (including root and the module gap) and optional chat, events, music and chatters display sections. The document uses test_events for the Test Events module id. Display sections contain a display object; chat filters, keyword tabs, highlighted users and alerts are stored separately and do not travel with the preset. Keys inside each section are preserved across clients, and a module id this client cannot render remains in the layout as an unavailable tile. The server accepts only the named top-level keys and limits the compact payload to 64 KiB.
{
"format": "lumio.cockpit",
"version": 1,
"layout": {
"root": { "kind": "stack", "modules": ["chat", "test_events"], "active": 0 },
"gap": "none"
},
"chat": { "display": { "showHeader": true } }
}
The preset's name is stored on its setting-preset row; an export code or file also carries that name for the import preview.
The JSON Schema for version 1 is published at /schemas/cockpit/v1.json. Every client that reads or writes the document, including a desktop client, follows it together with the version rules below.
Version rules
- Adding an optional key, a new
displaykey or a new module id keepsversionunchanged. - Renaming or removing a key, or changing what a key means, raises
version. - Readers ignore unknown keys and show an unknown module id as an unavailable tile. They never drop either.
- Writers keep unknown keys inside a section: they change the raw section object and write it back whole. A section write replaces the complete section, so a client that strips unknown keys deletes settings another client added.
- A client that sees a
versionhigher than the highest version it knows opens that document read-only and asks the user to update. - The server stores
format_versionon each working-state row and accepts a write only whenformat_versionis a version it knows. A preset payload with an unknownversionis rejected on create.
The working state carries format_version: 1, a row revision and a rev plus data for each of the five sections. A section's data: null means defaults in the base slot, or the saved preset's value in a draft. A section write sends its complete JSON object and its current base_rev; the server limits it to 32 KiB. A stale revision returns COCKPIT_CONFLICT with the current state for recovery. Saving a draft merges its non-null sections into the named preset and clears the draft. A stack's active is the tab a new window shows first. The web client keeps the tab currently in front for each window in sessionStorage (lumio:cockpit-tabs:<surface>:<user>:<account>, per slot and stack). Switching tabs therefore writes no section and creates no draft. A layout write keeps the stored active of every stack whose module list it does not change; a stack whose modules it adds, removes or reorders takes the window's front tab. Save changes writes the window's current front tabs, so they become the preset's start tabs. While the base slot's layout is still at rev 0, each window shows the start layout for its own width; the first open writes layout only to carry over a layout from the browser's earlier local Cockpit storage, while the display sections are imported as before. A draft whose layout differs from the saved preset only in active values, with no other draft section, does not count as a draft. The client discards it when it loads. Resetting Without preset writes the base slot back to defaults.
Windows and live updates
The preset selected by each browser tab is window-local; the server stores no window or device assignment. A ?preset= link selects a slot when that window opens. The same slot's edits appear in other windows through workspace:\{account_id\}:\{user_id\}. The channel accepts only that user in that account, including a token bound to that user. Its messages carry a versioned envelope, the changed section or preset, a revision and an origin id. Clients reload cockpitWorkspace or GET /v1/cockpit/workspace when they subscribe or reconnect, because pub/sub messages are not a durable history.
The web client shows a change at once and writes the section on release (display changes after 300 ms). One write per slot and section is in flight; a change made meanwhile follows on the new revision. On COCKPIT_CONFLICT it drops the local change, reads the server state and says so once. A network error, 429 or 5xx keeps the change on screen and retries it up to four times, then waits for Try again; any other refusal drops the change and reads the server state. Both failure kinds show Not saved with the reason in the Cockpit bar until a write succeeds. A server answer keeps its message; a request that got no answer at all (offline, aborted) shows a translated sentence that the server was not reachable instead of the browser's own error text. The card repeats Try again only where the bar shows it as an icon.
Preset export is an LS1… code, a link whose #s= fragment holds that code, or a JSON file. Import checks the lumio.cockpit format, previews the document, then creates a new cockpit preset through the regular preset API. The fragment itself is never sent to the server. See Cockpit presets for the user flow.