@maiaos/client-core
Platform-neutral client use cases for Maia OS: Effect services that sit between
a client's renderer and
@maiaos/sdk,
so every client reads Maia Node state and sends requests the same way.
Pre-release. Maia publishes
canarybuilds to npm only, andlatestfollows the newest one (earlier nightly builds are historical). They are not release-qualified, and Maia has no stable release (D-202). Nothing in this package is a stability promise: entry points, names and shapes can change in any build.
Two Maia clients share it. The Expo client,
@maiaos/client
(Desktop and mobile), uses it today. The maia CLI will use it for its
terminal dashboard
(D-161,
planned; the CLI does not use it yet).
Requirements
Node.js 24.22.1, and a Maia Node to talk to through @maiaos/sdk, which
installs with this package.
Install
pnpm add @maiaos/client-core@canary # or an exact version
Usage
import { makeNodeStatusClientService } from "@maiaos/client-core/node-status";
import { validateVoiceProposal } from "@maiaos/client-core/single-session";
import { makeTerminalClientService } from "@maiaos/client-core/terminal";
import { makeWorkspaceScopeService } from "@maiaos/client-core/workspace-scope";
Each factory returns an Effect service that the renderer composes with a platform transport; React components only render its state.
The package owns client-side validation, deadlines, cancellation, recovery of uncertain requests and projections of Node state. It owns no transport, credentials, native API, Node lifecycle or durable state: the SDK is the protocol client and Maia Node is the authority.
| Entry point | Responsibility |
|---|---|
boot | The Desktop boot sequence: lifecycle status, one start, then status reads until the host reports a ready Node |
navigation | Route names, the ?q=&state=&page= list query, parent routes and the one pagination model |
node-status | One truthful, point-in-time Node status projection |
workspace-scope | The one active Workspace scope, loaded from and replaced only by Node |
single-session | Voice setup, Node-provided orchestrator context and local proposals |
terminal, terminal-unavailable | Live terminal client and its explicit unavailable state |
interaction, interaction-view | Record-only questions and answers, with recovery of unknown outcomes |
presentation | Bounded Workspace, Project and Session list reads |
cockpit | Work cockpit per Node and a combined view: one bounded index, one change feed, attention, lists, launcher search, single or bulk Session creation over the SDK batch and first-run onboarding |
session-view | Focused Session detail: live items over session.attach, recent turns, summary, diff and a send, interrupt and wait composer |
commands | The keyboard command registry: stable IDs, Desktop and terminal keymaps, rebinding, conflicts and reserved chords |
node-registry | The local and registered remote Nodes a client addresses: connecting, ready, stale or unreachable (with ssh's reason, or auth when the Node rejects the credential) |
session-attach | The SDK's Session attach reducer, re-exported unchanged |
dictation | Composer dictation state: listening, partial text at the caret, cancel, language |
- Deadlines and uncertainty. Every request gets a unique message ID from
the package
IdGenerator(EffectRandomby default) and a 5.5-second client deadline. A timed-out query is retryable; a timed-out mutation isoutcome_unknownand is reconciled with its original command ID, never retried as a new one. Each request carriesdeadlineAt, that deadline as an instant onClock.monotonicTimeNanos(never wall-clock time), for a requester that retries to stop before it. A client that must bound its reads in flight providesReadAdmission; a read waits for its permit before its deadline starts, and a mutation never waits. - Freshness. Each Node's cockpit keeps the time of its last successful
read and one whole-Node load in flight. A failed load retries, after 2 s and
doubling to 30 s, until the Node answers; a reload a person asks for runs
once; the change feed resubscribes on the same backoff. A copy is
stalewhen its latest whole-Node read failed andpartialuntil the Node first answers or while it caps a read. The combined view stays ready once any Node answers. - Routing. The combined view labels each Project and Session with its
Node, and
nodeIdOfis the one lookup an action asks. It returns that Node, or aNodeRouteErrorwhen the combined view holds no such target (unknown) or two Nodes' indexes hold the same ID (ambiguous). A repeated Workspace, Project or Session ID keeps the first Node's record and marks the view truncated, and no action targets a repeated Project or Session. One Node's own view routes every target to that Node, since its bounded index can lack a Session the Node holds. - Fail closed. Token, Workspace, orchestrator and relay services are unavailable by default. A proposal or preview is never evidence of delivery; only an exact Node preview enables explicit confirmation.
- No hidden authority. Browsing owns no execution focus or mutation authority, and errors carry only bounded reason codes, never credentials or request envelopes.
Status
Source candidate. Its terminal, voice, interaction and cockpit services are
not release-qualified. The cockpit follows today's observe.events feed; the
planned R1 aggregate subscription, view store and reconnect policy will replace
its index load here; see the
client architecture.
- Bulk creation. A preview fixes every target, task and command ID and
carries a digest; one confirmation runs it once, within its expiry. Each
item reports its receipts or the Node's refusal (for example
saturatedwhen an account has no free slot). A retry replays the same commands and request bodies, so the Node answers the original results. The Run ledger (S19) joins as a secondCreationDispatch. - Onboarding.
makeOnboardingreads vendor accounts from Connection records, scans native sessions as metadata (titles only when a person turns them on), registers repositories, and runs adoption as a preview, then one confirmation request per item, each opening the Desktop native sheet. A declined or uncertain confirmation stops the batch; confirming again resends the same preview IDs. One-click use of signed-in CLIs waits forconnection.detect(CliDetectionplaceholder). - Timeline seam.
session-viewreads final turn text through aTimelineSource; the S12breduceSessionAttachsource plugs in there.
Links
- Desktop and mobile client architecture
@maiaos/sdk- Security policy
- Repository
Imported from Maia OS docs at a2175bb