Aller au contenu

Maia client (@maiaos/client)

The shared Expo application for Maia OS: one React Native codebase that renders Maia Node state for the Tauri desktop app today and native iOS and Android builds later, so people can follow and steer their AI coding agents by text or voice.

Status: source candidate, not release-qualified. Desktop comes first; mobile follows from the same features. The Expo web export is local Tauri content and a headless test artifact, not a standalone web application.

The client is a projection: React components render, and Effect services in @maiaos/client-core reach Maia Node through @maiaos/sdk and explicit platform transports. It never owns Node authority, runtime supervision, provider APIs, credentials or durable state.

Run it

From the repository root:

pnpm --filter @maiaos/client dev    # Expo web development server
pnpm dev:desktop                    # the same client inside the Desktop shell
pnpm test:e2e:client                # rebuild the export and run Playwright

A running Node is needed for live data; see the quick start.

Key concepts

  • Truthful states. Unavailable platforms, offline Nodes, missing Gateway configuration and denied microphones show explicit, distinct states; nothing falls back to sample data or a fake send.
  • Preview, then confirm. A managed text request targets an exact idle Session, shows the Node's preview and runs only after explicit confirmation. Uncertain outcomes stay visible until reconciled through receipt.get.
  • Scope from the Node. The active Workspace scope, voice prompt and voice tool come from Maia Node; replacing the scope clears the visible voice projection.
  • Voice is optional. Text is the default. Voice uses GPT Realtime through Vercel AI Gateway with a short-lived token minted by the Desktop process; the microphone starts off.
  • Platform edges. SDK and Tauri imports live only in src/platform/desktop; native mobile adapters fail closed until their capabilities are qualified. Long-lived credentials never enter the renderer.

Status and direction

Mounted today (decision): a boot gate that waits for the Desktop host to report a ready Node (starting it once, or offering "Start Maia"), then file-based routes in one app shell:

RoutePage
/Home: Sessions grouped by attention with statistics; Get started when empty
/w/[workspaceId]A Workspace's Projects with their Session counts
/p/[projectId]A Project's Sessions grouped by attention; ?state= pages one group
/s/[sessionId]One Session: its detail, composer and recorded questions
/attentionSessions that need a person, most urgent first
/sessionsEvery Session, with search, a state filter and pages
/nodesThe Nodes this client reaches and their health
/startGet started: Node, accounts, existing sessions, first Session
/settings, /voiceThis Node, keyboard and voice (?section=); the voice conversation

Search, filter and page live in the URL (?q=&state=&page=), so back, forward (mod+[, mod+]), the header back arrow and deep links replay a place. One Work cockpit above the routes (decision) serves every page: a page holds the rows that fit the window, mod+K opens the launcher, j/k/Enter/Escape triage, [/] turn pages, the command dock opens New Session with a typed task, and ? lists every shortcut. Any key hides a tooltip under the pointer or on the focused icon (src/platform/hover-escape); an Escape that hides one does nothing else, so the next Escape reaches the shortcuts. Every registered remote Node that is ready gets its own cockpit; pages show all Nodes combined or the one chosen in /nodes, and each Project or Session action goes to the one Node that holds it. In the combined view an ID that no Node holds, or that two Nodes' indexes hold, gets no action and says so; choosing one Node in /nodes acts on that Node, whatever its bounded list shows. The Session page streams the conversation, answers approval requests through the native sheet and puts its composer in the shell's dock. Both docks offer on-device dictation on Desktop (macOS): a microphone, mod+shift+D and Escape. The live-terminal client is retained in src/features/terminal but not mounted. A retry after an output fence re-delivers from cursor 0 onto the same screen, because the renderer has no reset. The first product caller must add one: a reset path on TerminalRendererProps that calls xterm reset() and clears the output queue.

Desktop also lists Sessions from this computer and the remote Nodes registered with maia node install, with a Node label and filter. New Session selects its Node before its Project and Connection. Remote Nodes refresh every 15 seconds over the SSH bridge; a connection failure remains visible with its reason. A creation preview stays bound to its original Node and is disabled if that Node disappears or its registration changes. A prepared lifecycle confirmation closes when its Node changes. Local Sessions keep the live item stream; remote Sessions read final turn text because the SSH bridge has no attach stream yet (D-088).

The visual language follows the owner's Pencil design: src/ui/theme holds its light and dark tokens (neutral canvas, white content surfaces, ink, positive, attention and negative signals, 16/24/28 px radii, 44/48/64 px controls and three depth shadows), src/features/shell the app shell, its three page templates and density breakpoints, and src/ui/molecules the shared header, grouped list section, row, statistic and command dock. Icons are Lucide geometry copied under third-party/lucide. Inter and IBM Plex Mono are named first in the font stacks but not bundled, so a system font renders where they are not installed.

The longer-term target in the UI specification adds one coordinator chat per Maia, Workspace or Project scope. A "Create or Pair Node" journey and a switcher across personal and organization Nodes are planned, not implemented; each SDK connection will address one explicit existing Node.

Development

pnpm --filter @maiaos/client lint
pnpm --filter @maiaos/client typecheck
pnpm --filter @maiaos/client test
pnpm --filter @maiaos/client build      # exports to apps/client/dist
pnpm test:e2e:client

apps/client/dist is generated output: never commit or deploy it, and never treat it as evidence of a connected workflow. Native mobile work uses an Expo development build; Expo Go cannot qualify audio, deep links, secure storage or packaging.

Documentation

License

No license has been published yet. All rights reserved.

In this section

  • Platform

    The pages of the Maia OS documentation under Platform.

Imported from Maia OS docs at a2175bb