Aller au contenu

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/site is 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 with node_lifecycle_start when 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, /settings and /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 from container.index.list pages of 500 rows, then whole-Node session.list pages), follows one observe.events feed (a remote Node polls) with targeted session.show reads and reads runtime health with one session.observe per 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, x stop and a archive with confirmation), the mod+K launcher, 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_token and microphone_permission. Credentials stay in Rust. Consequential and destructive operations need the user's answer in a native macOS sheet that the renderer cannot answer, except turn.send and terminal.input.write, which go straight to the Node as from the CLI (D-076). Three more commands, dictation_start, dictation_finish and dictation_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 --desktop as 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 maia tool. 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:

  1. What is the Swarm doing now?
  2. Which Workspace, Project, Session, activation, Routine, worker or Node needs attention?
  3. What evidence supports the displayed state?
  4. 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.select or 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

OwnerOwnsMust not own
packages/protocolwire schemas, operations, events, receipts, risk and exposure policyReact, Tauri, Expo, layout, platform APIs
packages/sdkauthenticated requests, snapshots, streams, cursors, typed failuresUI state, native APIs, durable truth
packages/client-coreEffect connection/subscription services, bounded projections, reconnect policy, typed client use casesReact rendering, Tauri, Expo modules, Node storage
apps/clientuniversal Expo composition, coordinator shell, voice, inspectors, design tokens, platform-neutral rulesdirect transport, credentials, provider SDKs, process or filesystem access
apps/client/src/platformnarrow native/web implementations of declared client portsbusiness decisions or ambient authority
apps/desktopTauri window, local assets, trusted-origin checks, reviewed native bridge and packagingNode state, business operations, broad filesystem/shell access
apps/sitepublic documentation and marketingauthenticated 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, offline and reset-required coverage;
  • 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, then speaking or confirmation-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:

PortDesktop implementationMobile implementation
NodeClientTransportreviewed Tauri commands to the loopback Node API, or SDK WSSSDK WSS/HTTP
VoiceTransportrealtime audio adapter in trusted Desktop compositionExpo-native audio/WebRTC adapter
ClientSecretStoremacOS Keychain adapter outside the rendererKeychain/Keystore-backed native adapter
NotificationPortoptional native desktop notification adapterAPNs/FCM-compatible Expo notification adapter
DeepLinkPortTauri single-instance URL handlerExpo linking adapter
SwarmSceneRenderer2D desktop renderer; optional qualified 3Dclustered 2D native renderer
HapticsPortunavailableoptional 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.

LevelVisible by defaultPurpose
overviewControl/Execution Nodes, Projects, global queues, health and attention clustersunderstand the whole Swarm
ProjectExecution Environments, Project Agents, Routines, capacity, blocked work, active Session clustersunderstand one team
Sessionexact Sessions, parent/child relations, activations, workers, Connections and pending interactionsinspect coordination
evidenceselected turn, tool/effect/provider attempt, receipt and causal timelinedebug 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:

TypeValues or fields
node kindscontrol-node, execution-node, project, workspace, agent, agent-session, routine, activation, worker, connection, attention-cluster
node fieldssceneNodeId, kind, resourceId, projectId, parentSceneNodeId, label, lifecycle, health (healthy, degraded, blocked, unknown), attention (none, info, action, critical), resourceRevision, clusterCount, stale
edge kindscontains, parent-session, scheduled-by, activated-as, assigned-to, uses-connection, waiting-on, message
edge fieldssceneEdgeId, 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.

BudgetDesktop targetMobile target
logical scene nodes retained10,0002,500
logical scene edges retained25,0005,000
primitives rendered after level-of-detail2,000 nodes / 4,000 edges500 nodes / 1,000 edges
steady interaction frame rate60 fps at 1,000 rendered nodes; never below 30 fps at cap30 fps at cap
pointer/touch/keyboard focus response p95under 100 msunder 150 ms
committed observation to visible state p95under 250 ms on a healthy local/tailnet linkunder 500 ms on a healthy link
client scene queue1,024 records or 4 MiB, whichever arrives first512 records or 2 MiB
retained detailed timeline1,000 items for the focused scope250 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.
  • includeContent defaults 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:

StateRequired behavior
connectingshow target Node identity; no inferred health
live-completedisplay current watermark and last heartbeat
live-degradedpreserve visible data, mark affected scope, disable unsafe shortcuts
staleshow elapsed staleness and reconnect action
offlineretain only policy-permitted projection; mutations unavailable
reset-requiredfreeze affected projection, fetch a new snapshot, preserve local focus only if still valid
policy-revokedremove hidden data and close affected inspectors/subscriptions immediately
outcome-unknownfence the exact operation until receipt reconciliation
Node epoch changedend 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.

  1. 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.
  2. Desktop read path: authenticated aggregate snapshot and subscription, coverage, search and a bounded causal timeline; mutations stay disabled.
  3. 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.
  4. 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.
  5. iOS: Expo development build composing secure storage, Node transport, deep link, audio, voice and notification ports; physical-device journeys.
  6. 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.
  7. 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.
Evidenceshared ExpoTauri/macOSiOSAndroid
pure scene/focus fixturesrequiredinheritedinheritedinherited
SDK snapshot/stream/gap fixturesrequiredrequiredrequiredrequired
voice state and confirmation fixturesrequiredrequiredrequiredrequired
headless accessibility and exported-renderer journeyrequiredsupporting onlynot applicablenot applicable
real native compositionnot sufficientrequiredrequiredrequired
physical microphone/audio route/interruptionnot sufficientrequiredrequiredrequired
notifications/deep linksnot sufficientif enabledrequiredrequired
scale/frame/memory/power evidencerequiredrequiredrequiredrequired
signing/install/update/rollbacknot sufficientrequiredrequiredrequired

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:

  1. connect to an exact Node and see honest coverage;
  2. view and navigate the complete authorized Swarm through bounded views;
  3. focus an exact Project, Workspace, Session, Routine, activation, worker or Node;
  4. type, or speak, to the exact selected conversation and continue in text when voice is unavailable;
  5. inspect evidence and complete a trusted confirmation in place;
  6. survive gaps, reconnect, policy changes, renderer restart, Node restart and outcome-unknown operations without inventing state;
  7. 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