Pumas separates durable model-library behavior from desktop presentation and optional inference runtimes.
The Rust crate is independently embeddable and the RPC binary independently
executable. Neither requires the GUI or its JavaScript dependencies. The
launcher selects the optional GUI with PUMAS_GUI; inference-plugin selection
is independent. The GUI adapts backend operations and owns native dialogs and
window controls, rather than defining the backend's available functionality.
React renderer
-> sandboxed Electron preload/main boundary
-> local HTTP/JSON-RPC
-> pumas-rpc
-> pumas-core
-> optional runtime providers and pumas-app-manager
| Component | Owns | Does not own |
|---|---|---|
frontend |
UI drafts, presentation, renderer subscriptions | Durable model/runtime truth |
electron |
Desktop privileges, sidecar lifecycle, IPC validation, windows and dialogs | Model-library domain rules |
pumas-rpc |
HTTP transport, JSON-RPC dispatch, SSE, /v1 gateway |
Durable model storage |
pumas-core |
Library state, SQLite index, downloads, imports, reconciliation, runtime profiles, serving state | Desktop presentation |
pumas-app-manager |
External runtime versions, installers, processes, service clients | Model catalog authority |
torch-server |
Torch model slots and Torch HTTP inference | General Pumas library state |
A launcher root has one owning PumasApi/PumasLibraryInstance. Construction
claims the root and returns an error when another live process owns it.
PumasLocalClient explicitly connects to an existing ready owner.
PumasReadOnlyLibrary reads indexed state without taking lifecycle ownership.
An embedding application or standalone RPC process constructs the owner; in desktop use, Electron supervises that RPC process. Renderer state is a projection of backend responses and update events; local optimistic state must not redefine whether a model, download, route, or runtime is authoritative.
The core intent service accepts transport-independent model requirements and
returns typed observations. Its resolver, immutable acquisition plan, durable
consumer declarations and reconciliation share the existing library owner.
PumasApi::intent() and PumasLocalClient::intent() provide the native and local
IPC views; seven intent_ JSON-RPC methods project the same service through the
existing loopback server. Transport handlers decode and project outcomes without
owning another download or declaration lifecycle.
Get may admit acquisition when explicitly allowed. Ensure commits retention before convergence; release removes one declaration generation without deleting files or cancelling downloads. Consumer disconnection does not revoke ownership of admitted work. The primary drains local effects and downloads during composed shutdown. See the core contract for availability evidence, restart, retry, deletion and downgrade limits.
Existing operational consumers remain supported. Desktop and UniFFI intent adoption is separate from this native/local transport increment. Node, fleet, remote discovery and additional network features are deferred until after the next Pumas release.
Important launcher-root paths are:
| Path | Purpose |
|---|---|
shared-resources/models/ |
Canonical model packages |
shared-resources/models/models.db |
SQLite model index and durable update feed |
shared-resources/cache/search.sqlite |
Hugging Face search cache |
launcher-data/cache/ |
Download and runtime cache state |
launcher-data/metadata/ |
Launcher metadata |
launcher-data/plugins/ |
Source/runtime plugin descriptors |
<app>-versions/ |
Managed external runtime installations |
Import, download, reconciliation, migration, and deletion must keep filesystem, metadata, index, and event history consistent. Recovery outcomes must remain distinguishable from normal success.
The renderer accesses only window.electronAPI; it has no direct Node access.
Electron uses contextIsolation, renderer sandboxing, and an RPC method
allowlist. The executable method/request registry is
electron/src/rpc-method-registry.ts; electron/src/ipc-validation.ts applies
it before main-process dispatch.
Rust method behavior is owned by rust/crates/pumas-rpc/src/handlers/ and core
services. TypeScript interfaces are consumer projections, not runtime proof.
New or changed operations must update the receiver decoder, producer, consumer,
and negative contract evidence together.
The RPC server accepts loopback binding only. There is no supported
--allow-lan mode; standalone deployment does not broaden exposure.
The backend exposes server-sent update streams for model-library, download, runtime-profile, serving, and status-telemetry changes. Events are invalidation or snapshot coordination signals; consumers must recover from missed events using the corresponding snapshot/feed contract.
The frontend may display a decoded startup snapshot while the backend loads, but freshness, provenance, and degraded refresh outcomes must be explicit.
Optional inference support distinguishes:
- app/plugin identity;
- runtime provider behavior;
- persisted runtime profiles;
- provider-scoped model routes;
- serving adapters and backend-owned served instances; and
- gateway endpoint capabilities.
Ollama and llama.cpp use external processes, ONNX Runtime is hosted in the Rust
process, and Torch uses the Python sidecar. The /v1 gateway is the public
facade: external clients target it, never provider-internal endpoints.
Provider processes expose private protocols (versioned handshakes,
capability advertisements, and internal request shapes) that the gateway
adapts into the public contracts; compatibility between the two sides is
established inside Pumas, not by clients. Every admitted generation uses the
one shared generation lifetime: connection-bounded but duration-unbounded
transport with no total, read, idle, or elapsed deadline, as defined in
generation lifetime.
The durable provider decision is recorded in ADR 0001; the Torch image boundary split is recorded in ADR 0002.
The default pumas-rpc build enables inference plugins. The library-only
desktop variant combines pumas-rpc --no-default-features with the frontend
library-only Vite mode. PUMAS_INFERENCE_PLUGINS=false selects that pair in
the shared launcher.
The pumas-core HF/process/GPU feature names do not currently remove their
underlying dependency or public module surfaces. Do not describe its
--no-default-features build as minimal until the feature contract is fixed and
verified.
The current standards audit tracks gaps in RPC authentication/decoding, persistence atomicity and migration, async shutdown, cached-state provenance, release evidence, accessibility, and binding support. Those findings supersede optimistic claims in removed plans or older documentation.