Desktop and mobile clients
Status: implemented as an unqualified source candidate: Tauri Desktop hosts the shared Expo renderer as routed pages in one app shell behind a Node boot gate (Home, Workspace, Project and Session pages, attention and all-Session lists, Nodes, Get started, settings and a voice page; decision); iOS, Android and plain browsers report these capabilities unavailable. Planned: R7 (text and voice everywhere), R9/R9a (connected client, json-render migration, Desktop and mobile qualification) and the master VPS Desktop delivery; the Swarm Canvas topology is Later.
This document owns the client platform, authority boundaries, live data path, Desktop and mobile contracts, platform ports, budgets and failure states. UI owns layout and navigation. The presentation runtime owns json-render rendering and view data contracts. The client README and Desktop README own current source details.
Closed platform decision
- One Expo/React Native application,
apps/client, is the only product renderer. - Desktop: Tauri v2 (
apps/desktop) hosts the locally built Expo web export; macOS first, Linux second. Desktop ships before mobile. - iOS and Android: native Expo development and production builds from
apps/client. Expo Go is never product, integration or release evidence. - No standalone browser client, React Native macOS or Tauri mobile.
apps/siteis documentation and marketing only. - Design system:
@tamagui/core(decision). Product-view composition: json-render (decision).
Reasons and rejected alternatives: decision.
Current implementation
Verified in source; not release-qualified:
- A boot gate reads
node_lifecycle_status, starts the Node once withnode_lifecycle_startwhen none runs, and reads the status again with a growing pause until the host reports it ready; only then do the routes mount. A Node that will not start shows one "Start Maia" action (decision). - File-based routes (
apps/client/src/app) render pages in one app shell: Home/(Sessions grouped into Needs attention, Active & queued and Idle & stopped, with statistics; Get started on an empty Node), a Workspace/w/[id](its Projects), a Project/p/[id](its Sessions grouped, or one group paged with?state=), a Session/s/[id],/attention,/sessions(search, state filter, pages),/nodes,/start,/settingsand/voice(the scope-keyed single-session voice and managed-request surface). Search, filter and page live in the URL; back, forward,mod+[/mod+]and the header back arrow move through it. - One Work cockpit per Node above the routes
(decision): the local Node and each registered
remote Node that is ready, shown combined or narrowed to one Node from
/nodes, with each Project or Session action going to the one Node that holds it and, in the combined view, refused when none or two Nodes' indexes do. Each loads one bounded index of Workspaces, Projects and Sessions (Workspaces with their Projects fromcontainer.index.listpages of 500 rows, then whole-Nodesession.listpages), follows oneobserve.eventsfeed (a remote Node polls) with targetedsession.showreads and reads runtime health with onesession.observeper interval. When a read limit (1,000 Workspaces, 2,000 Projects or 4,000 Sessions) cuts the index short or the Node caps its runtime list, every page says in one line that it shows part of the Node and names the limit it reached. Every Project belongs to one Workspace on the Node (decision; migration 35 makes it a required reference), so the client shows no "Unassigned" group: a Session outside the index means a cut read (or a Project registered during it), never a Project without a Workspace. A Session's status reads the same in lists, the launcher, the Session page and Workspace counts: the Node's attention reason first, and a running Session whose turn finished reads Idle. A page holds the rows that fit the window; keyboard triage (j/k, Enter, Escape back,[/]pages,xstop andaarchive with confirmation), themod+Klauncher, the command dock (its task opens New Session; on-device dictation on macOS), single and bulk creation through the SDK and the Session page work on every page. The Session page shows the live item stream with approvals answered through the native sheet, a summary, changed files, interrupt, wait, stop, resume and archive, and puts its composer in the shell's dock. Measured in headless Chromium with a synthetic 24/96/1,056 fixture and its 2x case; this is renderer evidence only. - Desktop reaches Node only through eleven Tauri commands:
node_request(the 73 operations whose feature descriptor has reviewed Desktop exposure),node_cancel,node_status,node_lifecycle_status,node_lifecycle_start,observation_subscribe,observation_cancel,session_attach,session_detach,voice_realtime_tokenandmicrophone_permission. Credentials stay in Rust. Consequential and destructive operations need the user's answer in a native macOS sheet that the renderer cannot answer, exceptturn.sendandterminal.input.write, which go straight to the Node as from the CLI (D-076). Three more commands,dictation_start,dictation_finishanddictation_cancel, never reach the Node: they run macOS on-device speech recognition into the composer draft, keep no audio and add no operation (D-083). - Desktop uses the profile's running Node or starts and supervises
maia-node --desktopas its child; it never installs a service. - Voice: Rust mints a 60-second Vercel AI Gateway client token; the renderer
lazy-loads GPT Realtime and receives only the protocol-generated
maiatool. Audio and transcripts stay in memory. Pi relay dispatch stays release-disabled. - The terminal feature is retained but not mounted.
- iOS, Android and plain browsers use unavailable adapters, never fixtures.
Product intent
The client is one persistent workspace, not a set of pages. It continuously answers:
- What is the Swarm doing now?
- Which Workspace, Project, Session, activation, Routine, worker or Node needs attention?
- What evidence supports the displayed state?
- What exact target receives the next typed, spoken or explicit operation?
Desktop is the complete administrator client. Mobile is the same control plane optimized for voice, alerts, focused inspection and safe intervention.
Conversation rules (R3, R7):
- Show the exact owner before a message is submitted. Use admitted Session SDK
operations, never the execution
workspace.selector a client-side chat store. - History lists and reopening are bounded and authorized. Reopening is not activation or archive restoration.
- Drafts, pending actions and voice stay bound to the exact Session. Navigation, Project creation or delegation never moves a Session's history or owner, or reuses a sibling Session's private context.
- Creation and continuation stay visibly unavailable until the owner contracts qualify. Acceptance: WP-20/21, DF-22.
Coordinator learning (R4): Node maintains scoped knowledge, memory and Skills from submitted communication and evidenced work. The client shows what was learned, why, its scope and revision, actual use, correction and pinning, pause/forget, and explicit Project-to-Workspace promotion. The renderer never mines chat history or publishes instructions. See the coordinator learning contract and PF-06/DF-06.
Product topology and authority
Control Node
durable state, policy, receipts,
observation snapshots and streams
^
|
@maiaos/sdk only
|
@maiaos/client-core
Effect resources + pure projections
|
apps/client (Expo)
shared features and design system
/ \
apps/desktop (Tauri) iOS / Android binary
macOS first Expo build
In the planned master VPS deployment
(PF-21)
the Control Node runs on the user's VPS. Desktop pairs to it as a user/device
client; a separately enrolled execution-only process on the Desktop computer
runs local workers. Closing Desktop never stops server-owned work. Laptop sleep
and Control Node outage are distinct stale/recovery cases. There is no automatic
local authority fallback. Until pairing exists, Desktop reaches a Node
registered with maia node install over the SSH stdio bridge, exactly as
maia --node does (D-088); it refuses one
recorded with maia node register for now (D-176).
The Control Node is the only authority for identity, health, lifecycle, policy, Sessions, scheduling, operation results, confirmations, events and receipts. Team Workspaces and several Control Nodes are specified in Team Workspaces and Control Nodes; Maia as the coordination hub is a decision. Clients own only rebuildable presentation state:
- selected and focused resources;
- camera, zoom, local layout, open overlays and inspector size;
- bounded drafts and pending local interaction state;
- non-authoritative preferences such as theme, reduced motion and graph mode;
- a bounded, policy-permitted cache that is discarded or rebuilt after a gap.
A color, animation, cached object, transcript, canvas edge or notification never establishes success, health, ownership or permission. Every consequential action is a registered Maia operation with the same preview, explicit confirmation, compare-and-set/idempotency and receipt path as the CLI.
Component boundaries
| Owner | Owns | Must not own |
|---|---|---|
packages/protocol | wire schemas, operations, events, receipts, risk and exposure policy | React, Tauri, Expo, layout, platform APIs |
packages/sdk | authenticated requests, snapshots, streams, cursors, typed failures | UI state, native APIs, durable truth |
packages/client-core | Effect connection/subscription services, bounded projections, reconnect policy, typed client use cases | React rendering, Tauri, Expo modules, Node storage |
apps/client | universal Expo composition, coordinator shell, voice, inspectors, design tokens, platform-neutral rules | direct transport, credentials, provider SDKs, process or filesystem access |
apps/client/src/platform | narrow native/web implementations of declared client ports | business decisions or ambient authority |
apps/desktop | Tauri window, local assets, trusted-origin checks, reviewed native bridge and packaging | Node state, business operations, broad filesystem/shell access |
apps/site | public documentation and marketing | authenticated product control, live Node access, client reuse as a web app |
No shared UI package exists in v1. Extract one only when a second application consumes the same boundary.
Adaptive focus and presentation
R1/R9a/R10b target. The presentation runtime owns json-render composition, Jev selection and the focus snapshot contract. Client rules for focus:
- Node builds an authorized graph snapshot from recorded entities and edges. The same SDK snapshot feeds list, graph, chat and worker views with exact identities, revisions, per-owner watermarks, coverage and bounded expansion. No graph database or client-derived truth.
- An explicit "show this Project" changes focus only after exact authorized resolution; ambiguous names ask. A focus proposal binds the client/Session, selection generation, source revisions and policy; a newer user action, pin, draft or target change rejects it. Background suggestions never steal focus, clear drafts or move confirmations. Focus is presentation, never command retargeting or authority.
- The human's portfolio is not the coordinator's context. Browsing a Project does not retarget the conversation; switching attaches that Project's own coordinator. Neither injects other names, counts or cached content into a Session, voice context or evaluation request (ownership; PF/DF-22, PF/DF-24).
- Model failure keeps deterministic manual views and marks the AI mode unavailable. Side effects belong to client-core Effect programs, not React event handlers. The feedback policy decides visual, text and voice delivery.
Live data path
Clients never subscribe to workers, provider sockets, Pi streams or Agent processes. Target (R1, R9): one aggregate authorized subscription per client and Node:
Node snapshot + signed cursor
-> @maiaos/sdk observation subscription
-> Effect bounded queue
-> pure client-core projection
-> per-frame coalesced React view state
-> renderer
Today Desktop relays the Node observe.events stream through the native
observation_subscribe command to refresh the mounted Session list, and one
focused Session's session.attach item stream through session_attach. The
renderer builds the subscribe message without a credential; Rust admits only
session.attach for one Session ID and optional { epoch, sequence } cursor,
adds the bearer and forwards bounded frames. client-core folds them with the
SDK reducer, reattaches after its cursor on resync at once and on a lost
relay with backoff (250 ms doubling to 5 s, starting over once a reattachment
has stayed live for 5 s), and stops on an error frame until Refresh attaches it again. Rust
checks the relay bound before it opens the Node socket and again before it
subscribes. A frame re-renders only the conversation turn it changed, and the
busy flag while an approval is answered re-renders approval items alone.
Agent text renders as text nodes through a small Markdown subset (fenced
code, headings, list items, inline code and strong), never as HTML.
The initial request uses snapshot-then-events, includeContent: false, and
only the authorized domains and Project IDs the view needs. Detail content is a
separate explicit inspector request. Selecting a resource opens no worker stream.
The client projection must:
- apply records only after schema validation;
- preserve per-partition and per-owner order without inventing global order;
- coalesce visual updates before the next frame; never render once per record;
- keep the focused resource while it stays authorized and present;
- show
complete,degraded,stale,offlineandreset-requiredcoverage; - stop applying deltas after a cursor gap, epoch change, policy change or projection invariant failure, then request a fresh bounded snapshot;
- keep SDK ingestion outside React render;
- cancel subscriptions and native resources through Scope when the Node or profile changes.
Diagnostic loss may reduce animation detail but must show a gap. Authoritative loss freezes affected lifecycle presentation until resnapshot. The last green frame never stays "live".
Voice
The portfolio voice contract (R7, PF-18, DF-18) owns text/voice parity, idempotency and retention. Client rules:
- Text is the default composer. Voice is a peer input to the exact selected conversation; in the UI target that is the selected scope's coordinator. Missing audio permission or provider never disables text.
- Opening a chat starts no microphone. One capture target per client; switching conversation stops or explicitly rebinds capture, and late callbacks to the old target are rejected.
- Visible states:
idle,listening,thinking, thenspeakingorconfirmation-required. - Each turn carries focus as a typed exact hint with the visible revision and coverage. Neither the model nor the client broadens or changes the target.
- v1 uses push-to-talk or an explicit foreground conversation. Raw audio is not retained, transcript persistence is opt-in and background recording is off.
- The authenticated client completes confirmation. A spoken "yes" may open the confirmation screen but cannot consume its device-bound proof. The screen shows operation, normalized input, exact targets, revision, risk, expiry and expected effect before the trusted gesture.
- Unsent drafts stay in target-bound client memory. A renderer crash may lose them and must say so; submitted history and receipts recover from Node.
Desktop contract
- Desktop is the first graphical delivery target: macOS first, Linux second, Windows third (RL7), after a remote-only bootstrap and a reviewed Windows confirmation dialog.
- One local Tauri window loads only repository-built Expo assets.
- Tauri owns windowing and reviewed native adapters only.
- The renderer never receives Node bearer credentials, descriptors, filesystem scope, shell authority or ambient Tauri commands.
- Each native command is listed in the default-deny capability manifest. A new view inherits no native authority from an existing command.
- Remote Node access goes through the native bridge: the renderer names a registered Node, and Rust resolves it through the local Node, runs the SDK's SSH bridge command and adds no credential of its own. The renderer never names a host.
- Closing Desktop detaches client resources; it never stops Node, Sessions or workers.
- A planned Create or Pair Node journey uses a separate bootstrap port; it never turns the renderer into a supervisor or Node.
Mobile contract
Mobile is the same apps/client compiled for iOS and Android. Its first
qualified surface is smaller than Desktop:
- connect or pair to one exact Node profile (pairing proposal);
- type in every supported conversation and optionally start, resume and stop a voice attachment for that exact Session;
- view health, attention, active Projects and a clustered overview;
- focus one Project, Workspace, Session, Routine, activation, worker or Node;
- inspect a bounded live causal timeline and receipt;
- answer an interaction or complete a trusted confirmation;
- receive a redacted notification that opens the exact focus.
Native work uses an Expo development build from the first native slice. Local builds stay supported; EAS is optional, never a runtime dependency. Native credentials and signing material never enter the repository. iOS on a physical device comes first, then Android parity from the same source.
Background behavior is conservative:
- OS suspension means disconnected, not "healthy in background";
- push is a wake-up hint, not delivery or operation evidence;
- a notification never confirms or performs a consequential operation;
- reconnect uses a signed cursor and resnapshots on expiry or gap;
- no continuous microphone or background recording in v1;
- no client timer is a durable Routine or scheduler.
Platform ports
Framework and native APIs end at narrow ports. Planned ports:
| Port | Desktop implementation | Mobile implementation |
|---|---|---|
NodeClientTransport | reviewed Tauri commands to the loopback Node API, or SDK WSS | SDK WSS/HTTP |
VoiceTransport | realtime audio adapter in trusted Desktop composition | Expo-native audio/WebRTC adapter |
ClientSecretStore | macOS Keychain adapter outside the renderer | Keychain/Keystore-backed native adapter |
NotificationPort | optional native desktop notification adapter | APNs/FCM-compatible Expo notification adapter |
DeepLinkPort | Tauri single-instance URL handler | Expo linking adapter |
SwarmSceneRenderer | 2D desktop renderer; optional qualified 3D | clustered 2D native renderer |
HapticsPort | unavailable | optional native feedback only |
Today only Desktop node transport (Tauri commands) and voice (Vercel AI Gateway Realtime over WSS) exist; no named port type is implemented yet. No feature imports Tauri or Expo native modules directly; platform composition supplies the implementation and client-core decides what the capability means.
Effect and React ownership
Effect owns resourceful client boundaries: Node connection lifecycle, snapshot and observation subscriptions, bounded queues, cancellation, reconnect, timeout and retry, voice transport lifecycle, secure-store, notification and deep-link calls, typed failures and redacted diagnostics.
Pure reducers own projection, focus, camera constraints, clustering, layout hints, inspector state and operation-preview presentation. React only composes and renders. The render loop never consumes an Effect stream per record, and Effect stays out of geometry hot paths.
Swarm Canvas
Later (ROADMAP: lists, search, inbox and the connected Project journey come first; decision). The Swarm Canvas is an infinite topology projection, not a workflow builder, scheduler or second orchestration graph.
| Level | Visible by default | Purpose |
|---|---|---|
| overview | Control/Execution Nodes, Projects, global queues, health and attention clusters | understand the whole Swarm |
| Project | Execution Environments, Project Agents, Routines, capacity, blocked work, active Session clusters | understand one team |
| Session | exact Sessions, parent/child relations, activations, workers, Connections and pending interactions | inspect coordination |
| evidence | selected turn, tool/effect/provider attempt, receipt and causal timeline | debug one exact outcome |
Zoom changes detail, never authority. Aggregates show counts and the watermark used. Expanding a cluster requests bounded detail for that exact scope.
The scene is derived from authorized Node snapshots and observation records:
| Type | Values or fields |
|---|---|
| node kinds | control-node, execution-node, project, workspace, agent, agent-session, routine, activation, worker, connection, attention-cluster |
| node fields | sceneNodeId, kind, resourceId, projectId, parentSceneNodeId, label, lifecycle, health (healthy, degraded, blocked, unknown), attention (none, info, action, critical), resourceRevision, clusterCount, stale |
| edge kinds | contains, parent-session, scheduled-by, activated-as, assigned-to, uses-connection, waiting-on, message |
| edge fields | sceneEdgeId, kind, fromSceneNodeId, toSceneNodeId, state (active, historical, blocked, unknown), sourceRevision |
- These are client projection types, not durable aggregates. Geometry, camera, animation and labels are never written back to Node.
- Scene IDs derive from typed resource IDs, never labels or array positions.
- A cluster is never a mutation target; the user expands or resolves it to an explicit authorized target set.
- Focus is a hint. Before any request the client resolves it to exact operation input, checks the displayed revision and shows the exact targets. "Stop this Agent" is never sent as an ambiguous target; stale, clustered, hidden or changed focus fails closed and asks the user to select again.
The first renderer is 2D: pan, zoom, fit-to-focus, semantic clustering, minimap,
keyboard traversal, search and deterministic focus. A 3D renderer behind
SwarmSceneRenderer needs identical scene and focus semantics, an accessible
non-3D representation, budgets no worse than 2D, reduced-motion behavior,
deterministic hit testing and instant fallback to 2D without reconnecting. 3D
is never the only way to inspect, select, confirm or recover work.
Performance and scale budgets
The client is a bounded view of unbounded durable history. Node and SDK pagination and cursors remain the scale boundary.
| Budget | Desktop target | Mobile target |
|---|---|---|
| logical scene nodes retained | 10,000 | 2,500 |
| logical scene edges retained | 25,000 | 5,000 |
| primitives rendered after level-of-detail | 2,000 nodes / 4,000 edges | 500 nodes / 1,000 edges |
| steady interaction frame rate | 60 fps at 1,000 rendered nodes; never below 30 fps at cap | 30 fps at cap |
| pointer/touch/keyboard focus response p95 | under 100 ms | under 150 ms |
| committed observation to visible state p95 | under 250 ms on a healthy local/tailnet link | under 500 ms on a healthy link |
| client scene queue | 1,024 records or 4 MiB, whichever arrives first | 512 records or 2 MiB |
| retained detailed timeline | 1,000 items for the focused scope | 250 items |
These are qualification targets, not measured capacity.
- Exceeding a logical limit clusters or pages data; it never drops an authoritative focused resource. Queue saturation marks coverage degraded and resnapshots. Subscriber count never changes worker emissions.
- Measure with synthetic 1x, 2x and failure-scale fixtures plus a real Node feed. DF-20 adds 24 Workspaces, 96 Projects, 1,000 retained Sessions and 24 concurrent activations, plus a 2x case. Idle Projects add no model loop or worker stream.
- DF-28 runs 1, 2 and 8 clients plus overload, keeps these absolute bounds and allows at most 10% p95 degradation against a matched baseline. A stalled, flooding or crashing client never backpressures workers or other clients.
- A 3D renderer cannot raise ingestion limits. Battery, thermal, memory and GPU evidence on physical mobile hardware is required before 3D is enabled there.
Accessibility and alternative representations
Every visual view has a synchronized non-spatial representation:
- searchable hierarchical resource list;
- keyboard and switch-control traversal;
- screen-reader labels with type, lifecycle, health, attention and relation;
- reduced-motion mode with no required animation;
- high-contrast, color-independent health states;
- visible focus and minimum touch-target sizes;
- content shown on hover or focus, such as an icon's tooltip, hides on the next key press without moving the pointer or focus, and an Escape that hides it runs no shortcut;
- a text timeline and receipt view for every visual transition.
Position or color is never the only evidence. Voice responses name the exact resource label and type; duplicate labels add the Project and a short stable ID.
Security and privacy
- Long-lived Node and provider credentials never enter Expo props, React state, browser storage, URLs, deep links, logs, canvas labels or notification text.
- Client telemetry holds bounded UI state, durations, counts, saturation and renderer measurements only; never prompts, transcripts, terminal output, resource content, credentials, endpoints or stable resource IDs.
includeContentdefaults to false and needs an authorized inspector request.- Deep links carry a bounded opaque focus reference, never credentials or content.
- Notifications carry a generic redacted summary by default.
- Screenshots, screen recording, clipboard and OS accessibility are explicit data-exposure surfaces; sensitive inspectors may add platform protection after a threat review, without promising absolute prevention.
- Cached projections are rebuildable. v1 persists layout and preferences only; persistent offline domain data needs encryption, retention, delete and device-revocation contracts first.
Failure and recovery states
The client shows these states explicitly and never replaces one with stale success:
| State | Required behavior |
|---|---|
| connecting | show target Node identity; no inferred health |
| live-complete | display current watermark and last heartbeat |
| live-degraded | preserve visible data, mark affected scope, disable unsafe shortcuts |
| stale | show elapsed staleness and reconnect action |
| offline | retain only policy-permitted projection; mutations unavailable |
| reset-required | freeze affected projection, fetch a new snapshot, preserve local focus only if still valid |
| policy-revoked | remove hidden data and close affected inspectors/subscriptions immediately |
| outcome-unknown | fence the exact operation until receipt reconciliation |
| Node epoch changed | end the old subscription, read the Node instance again, drop old cursors, resnapshot |
A renderer crash or restart never changes Node lifecycle. A voice transport failure does not mean the attached Session stopped. An app update never loads a JavaScript bundle whose declared native runtime is incompatible.
Delivery and verification
Delivery order (R7, R9, R9a, master VPS; Swarm Canvas Later). Source layout follows source organization.
- Contracts and fixtures: closed observation fixtures for overview, Project, Session, gap, policy revocation, Node epoch reset and outcome unknown; pure projection and focus reducers; the same snapshot and records give the same projection on web and native JavaScript runtimes.
- Desktop read path: authenticated aggregate snapshot and subscription, coverage, search and a bounded causal timeline; mutations stay disabled.
- Desktop text, voice and safe control (R7): text plus same-target voice, interruption, playback, target pinning, cross-mode send deduplication and reconnect; read/status, preview, trusted confirmation, receipt and outcome-unknown reconciliation through registered operations.
- Desktop qualification (R9): accessibility, budgets, long reconnect, cursor reset, policy revocation, renderer crash, Node restart, voice failure and slow-client isolation; packaging, signing, notarization, updates (RL5), rollback, dependency audit, SBOM and clean install. Desktop is complete before mobile is called parity.
- iOS: Expo development build composing secure storage, Node transport, deep link, audio, voice and notification ports; physical-device journeys.
- Android parity: the same ports with Android permission, foreground-service, notification, audio-route, back-button and lifecycle behavior; the shared fixtures and an interruption/reconnect suite.
- Optional 3D (Later): benchmark against the scene port and budgets; admit at most one renderer after dependency, accessibility, power, fallback, security and release review. 2D stays the default.
| Evidence | shared Expo | Tauri/macOS | iOS | Android |
|---|---|---|---|---|
| pure scene/focus fixtures | required | inherited | inherited | inherited |
| SDK snapshot/stream/gap fixtures | required | required | required | required |
| voice state and confirmation fixtures | required | required | required | required |
| headless accessibility and exported-renderer journey | required | supporting only | not applicable | not applicable |
| real native composition | not sufficient | required | required | required |
| physical microphone/audio route/interruption | not sufficient | required | required | required |
| notifications/deep links | not sufficient | if enabled | required | required |
| scale/frame/memory/power evidence | required | required | required | required |
| signing/install/update/rollback | not sufficient | required | required | required |
Browser tests prove the shared renderer only. Expo Go proves only compatible JavaScript presentation. Neither proves Tauri lifecycle, native permissions, mobile audio, secure storage, notification delivery, packaging or release.
Desktop is ready when an operator can, from one client:
- connect to an exact Node and see honest coverage;
- view and navigate the complete authorized Swarm through bounded views;
- focus an exact Project, Workspace, Session, Routine, activation, worker or Node;
- type, or speak, to the exact selected conversation and continue in text when voice is unavailable;
- inspect evidence and complete a trusted confirmation in place;
- survive gaps, reconnect, policy changes, renderer restart, Node restart and outcome-unknown operations without inventing state;
- meet accessibility, scale, security, packaging and recovery gates.
Mobile is ready when the same contracts pass on physical iOS and Android devices and the user completes the text/voice, attention, focus, evidence, confirmation, receipt, notification and reconnect journeys without a Desktop or browser.
Imported from Maia OS docs at 3dc3e07