Loams Desktop and the loams CLI
The Electron desktop app that runs the console, a local engine and the agent daemon on your machine, and the one loams binary that runs, upgrades and administers a Loams stack.
What they are
Loams Desktop is one window with the whole Loams console in it. It runs a local engine for you (loams dev, supervised), manages local Postgres and TiKV stacks through Docker or Podman Compose, hosts Loams Studio on the local agent daemon loams-agentd, embeds the software factory apps, and connects to any other Loams server you add by URL, including a stack on your tailnet. It is Electron, and the console inside it is the same cordis console that runs at console.loams.dev.
The loams CLI is one binary. Today it is mostly the server: loams dev, standalone and cluster run the engine, and loams upgrade and loams migrate move a self-hosted stack from one release to the next while keeping its data. The client half that the design describes (profiles, stack create, product command groups, an MCP server, a one-line installer) is planned, not built.
Use the desktop if you want to try Loams on a laptop without assembling the compose stack, or if you want Studio with your local repositories and agent CLIs. Use the CLI to run an engine on a server, to mint API keys, and to upgrade a compose stack. Do not use either as your production control plane yet: the desktop's local stacks are development stacks, and the CLI has no remote management commands.
Status
Both are available in Loams 0.1.0, released 2026-10-18. As with all of 0.x, flags, layouts and formats may change between minor versions, and loams upgrade moves a stack between them. Studio, inside the desktop, is experimental.
| Release | Loams Desktop | loams CLI |
|---|---|---|
| 0.1.0-preview.1 (2026-10-12) | The Electron app on Linux: the cloud console against any server, a supervised loams dev with Data Studio, local Postgres and TiKV stacks, the factory apps, an agent panel | Linux .deb, .rpm and .pkg.tar.zst, and an unsigned Windows .zip |
| 0.1.0-preview.2 (2026-10-15) | macOS (arm64, x64) and Windows (x64) beside Linux; Studio as the default mode | macOS tarballs and the Windows zip beside the Linux packages |
| 0.1.0 (2026-10-18, current) | Studio's full surface through loams-agentd (experimental); the app reaches Loams Live on the engine's main port | loams upgrade and loams migrate; git-remote-loams ships next to loams in every package |
0.1.0 is the first release that keeps data across an upgrade: a preview.2 stack moves to 0.1.0 with loams upgrade. preview.1 to preview.2 kept no data.
Architecture
The desktop
| Part | Where | What it does |
|---|---|---|
| Renderer | web/apps/console with the catalog/desktop.yml patch | The cordis console, sandboxed, no Node. Plugins that need the desktop require the desktop service, which only @loams/platform-electron provides (D658) |
loams-app:// protocol | apps/desktop-electron/src/main/protocol | Serves the console from loams-app://console/ui/ and proxies /api/, /v1/, /loams., /.well-known/, /health and /ready to the active server's origin, so the console keeps its cookies and router (D655) |
| Engine supervisor | src/main/engine | Runs loams dev on free loopback ports, waits for GetInstance, restarts with backoff (1 to 30 seconds, at most 5 restarts in 10 minutes), rotates engine.log, and scrubs secrets from the child's environment (D656) |
| Stack manager | src/main/stacks | Starts the repository's Postgres and TiKV dev stacks with podman compose or docker compose, whichever it finds first |
| Studio and the daemon | src/main/agentd, src/main/studio | Discovers or starts loams-agentd, forwards /loams.agentd.v1.* to its loopback Connect listener with the owner token after an allowlist check (D908), and drives the tray block and OS notifications |
| Factory host and vault | src/main/factory | Forgejo, Zulip, Plane, GlitchTip, OpenPanel, Matomo, Langfuse and OpenObserve as read-only panels and embedded views; credentials encrypted with safeStorage, never sent to the renderer (D659) |
| Updater | src/main/update | Off unless a feed is configured; a latest*.yml manifest must carry an Ed25519 signature against a key compiled into the app (D661) |
When the active server is the local engine, the desktop answers /api/v1/instance and /api/v1/session itself (edition oss, features.local) and refuses the rest of /api/v1/* (D657), because the engine serves no control-plane REST. Cloud-only pages hide themselves.
The packaged app carries an engine built with --features live,durable,live-tikv,graph. If the Windows engine build or its --version check fails, the Windows build ships without a local engine and shows a "not available on Windows yet" state.
The CLI
crates/loams/src/main.rs is one clap tree:
| Command | What it does |
|---|---|
loams dev | Everything in one process, data in a local directory (--data-dir, default .loams); the HTTP API on loopback port 8080 by default |
loams standalone --bucket <url> | Everything in one process, data in an object-store bucket (s3://, gs://, file:///) |
loams cluster | One node of a cluster, with --node-id, --roles (a subset of meta,log,query,worker,gateway), --peers and --bucket |
loams warm <ns>/<collection> | Warms a collection on the node that owns it |
loams durable migrate | Creates or updates Loams Durable's store schema |
loams auth new-key | Prints a new API key once, and the hashed line for LOAMS_API_KEYS_FILE (--append <file> writes it, mode 0600) |
loams upgrade | Upgrades a self-hosted compose stack one release at a time: check, --to, rollback, status, snapshots |
loams migrate | The server side of an upgrade: run, plan, status, verify, snapshot, restore, snapshots. In compose it is the one-shot migrate service |
loams pg-control, pg-api-key, pg-runner | Loams Postgres's control plane, its keys and its compute runner. Built with the postgres feature, so they are in the loams-pg-control image, not in the packaged binary |
The packages are built from the default feature set (es, flight, hnsw, live, qdrant). Durable, TiKV, the Postgres and MySQL wires and streaming gRPC are opt-in features, so a packaged loams refuses their flags; the compose images are built with them.
How it works
One console, in a window
The desktop does not fork the console. The renderer loads the same build the browser does, under a custom protocol, and Electron main makes it look same-origin by proxying API prefixes to whichever server is active. No redirect to another origin is followed, and cookie Domain attributes are stripped. That is why switching between the local engine, a stack on your tailnet and Loams Cloud is a server switcher, not three apps.
The local engine and stacks
The local engine is a child process, not a library (D656). The same loams binary runs here as on a server, a crash does not take the window down, and the supervisor restarts it. Live flags are passed only if the binary supports them: an engine that serves Loams Live on its main port gets no deprecated --live-listen, and if another engine already holds Live's default port, the desktop moves Live's own listener so this engine still starts.
The Postgres and TiKV stacks are the repository's own compose files (deploy/loams-postgres-dev, deploy/tikv), bundled with the app. They need Docker or Podman; without one, those pages say so and the rest of the app works.
The agent daemon
loams-agentd is the per-user Rust daemon that owns agent work (D780): Studio's threads, worktrees, terminals and approvals, and the harness CLIs. It came from a hard fork of an MIT-licensed desktop agent app, reduced to a headless daemon (D782, D783). It is a per-user service, never a system service (D784): systemd --user, a LaunchAgent on macOS, an HKCU Run entry on Windows. Until you agree to keep agents running in the background, it runs as the app's child and a quit drains it (D785). Linux linger is opt-in (D786).
Its RPC is loopback-only on an ephemeral port, with a per-user token checked before the WebSocket upgrade, any Origin refused and Host checked (D788). Electron main is the only general client, and the page reaches the daemon only through main's proxy. The same daemon is also published as the image ghcr.io/ostrium-labs/loams-agentd, for a remote Studio host (see Loams Studio).
Upgrades
loams upgrade drives a compose stack from its directory (D934). It never opens a store itself: every data step is loams migrate … in a container of the target image, so the code that writes the new format is the code that ships with it.
- Preflight, bundle, pull.
check's blockers must be empty and every service healthy. The target's compose bundle is downloaded and checked against the release'sSHA256SUMS, and the images are pulled while the stack still serves. A failure here changes nothing. - Close the door and quiesce. The Tailscale sidecars stop, so no client reaches the stack; then the writers stop (the daemon, the console, the Postgres computes,
pg-control,pg-runner, the House, the engine, TiDB). - Snapshot every store with the writers stopped (D930): TiKV with BR or as a cold copy, the bucket's few mutable pointer objects plus a GC root (the data objects are immutable, so this is cheap), Postgres drained and every timeline branched at its last record LSN, the House's directory,
pg-control's records, Durable's SQLite, and the stack directory. Snapshots stay on the host, mode 0700, never uploaded. - Install, restart, migrate, start, verify. The bundle replaces the stack files (
.env,secrets/andcompose.override.yamlare kept), PD then TiKV restart,loams migrate runapplies the release's migrations and records each in a ledger in the metastore's_systemnamespace (D928), the services start in order, andloams migrate verifyreads every product's data. - Open the door.
A failure in steps 8 to 11 restores the snapshot automatically and exits 10 (upgrade_failed_rolled_back). loams upgrade rollback does the same by hand and prints the window of writes it will lose first. rollback --keep-writes swaps the images back and keeps the data, but only when every migration of the step is Reversible and no third-party pin changed. If the CLI is killed, the same command resumes from .loams-upgrade/history.jsonl.
The engine, the House and pg-control refuse data they cannot read and exit 78 rather than start. Upgrades go one step at a time (D925): each release from the one before it, and from 0.1.0 on, any earlier patch of the same minor line. Third-party components stay pinned, and a target with an older PD, TiKV or TiDB is refused (D933). The hosted console supports the newest engine and the one before it; an older engine gets an "upgrade your engine" page (D938).
Key decisions and why
From the decision log; the designs are §37 (§19 is the Electron desktop), §50 (the daemon), §30 (the CLI) and §54 (upgrades).
| Decision | What | Why, and what was rejected |
|---|---|---|
| D652 | The desktop ships on Electron | The owner's ruling; the earlier native shell (a fork of a Rust GPUI app) had never launched from this repository and spoke its own contracts, while the console already existed. Tauri and the native track were set aside |
| D655 | Serve the console from loams-app://console and proxy API prefixes to the active server | The console keeps its router, its base path, cookies and CSRF unchanged; no console fork |
| D656 | The local engine is a supervised loams dev sidecar | Process isolation, crash containment and the same binary as the CLI; embedding would tie Electron's lifecycle to the engine's |
| D659 | Factory credentials stay in main under safeStorage; IPC is a read-only op allowlist | Tokens never reach web content, and an app's UI can never drive the desktop |
| D661 | No updates without a signed manifest under a compiled-in key | A build can never install another project's binary |
| D663 | No telemetry; crash dumps stay local | Carries D284's rule for the CLI |
| D676, D677 | Linux packages GPG- or SignPath-signed; Windows through SignPath; macOS unsigned and not notarized, with "Download" instead of self-update | The owner has no Apple account. Windows builds without the SignPath secrets are unsigned too (below) |
| D780 | One agent system in a per-user Rust daemon, loams-agentd | Agent turns must survive the window closing; Electron becomes a client |
| D788 | The daemon's RPC is loopback-only with a per-user token and refuses any Origin | The fork's IPC served any local process; the browser path is a separate listener (D909) |
| D281, D283 | One loams binary for server and client; an output and exit-code contract | Approved, and partly visible today: loams upgrade already has stable error codes and exit codes |
| D923, D930, D932 | Data-keeping upgrades from preview.2 onward; snapshot first with writers stopped; rollback restores the snapshot | The owner's direction of 2026-10-13: a preview must be safe to keep using |
| D927 | migrate is a one-shot service of the loams image, and the engine starts only after it exits 0 | No separate migration image; an ordinary restart finds nothing to do |
| D935 | The fixed sequence, with the door closed during the dangerous part | No client sees a half-migrated stack |
What is compatible
| Supported | |
|---|---|
| Desktop platforms | Linux x64 and arm64 (.deb, .rpm, .pacman, .AppImage); macOS arm64 and x64 (.dmg, .zip); Windows x64 (NSIS installer, .zip) |
| CLI platforms | Linux x64 and arm64 (.deb, .rpm, .pkg.tar.zst); macOS arm64 and x64 (.tar.gz); Windows x64 (.zip) |
| Linux distributions for the CLI packages | Debian and Ubuntu (.deb); Fedora, RHEL and openSUSE (.rpm); Arch and CachyOS (.pkg.tar.zst) |
| Container runtimes | Docker or Podman with Compose, for the desktop's local stacks and for loams upgrade (docker compose or podman compose) |
| Electron | Pinned exactly (44.4.5 in apps/desktop-electron/package.json) |
| systemd | loams.service (loams dev, data in /var/lib/loams) and the loams@.service template, configured in /etc/default/loams |
The server stack itself stays Linux containers. On macOS and Windows, run deploy/release with Docker Desktop; the patched TiDB image is amd64-only and runs emulated on Apple silicon.
How it compares
These are analogies, to place the pieces, not feature claims.
Loams Desktop and loams | The closest familiar tool | |
|---|---|---|
| Run the whole platform locally | The desktop supervises loams dev and the compose stacks; docker compose up runs the full stack | Like the Supabase CLI's supabase start, which runs Supabase's services locally in Docker. The Supabase CLI also manages migrations and deploys for a hosted project, which loams cannot do yet |
| Manage a hosted service from the terminal | Not yet: login, keys, product commands and stacks are CL1, planned | Like Neon's CLI, neonctl, which manages projects and branches in Neon's cloud. loams has nothing comparable today |
| A desktop app around local containers | The desktop runs compose stacks, but its focus is the console, Studio and the engine, not container management | Docker Desktop manages containers and images in general; the Loams desktop uses Docker or Podman, it does not replace them |
| Upgrades | loams upgrade snapshots, migrates, verifies and rolls back a self-hosted stack | Most self-hosted database stacks leave this to the operator's own runbook |
Where the others are better today: the Supabase and Neon CLIs are complete clients for a hosted product, with login, project management and scripting; loams is a server binary with an upgrade tool. Docker Desktop is signed and notarized; Loams' macOS builds are only ad-hoc signed and its Windows builds are unsigned.
What is missing and what is planned
- Signing. Builds that are not signed by a trusted certificate say so in the release notes. macOS is ad-hoc signed and not notarized; Windows is unsigned and SmartScreen warns. The release pipeline can sign Windows and the Linux packages through SignPath and GPG once the owner adds the secrets (
docs/release/desktop.md). - The client CLI (CL1, planned):
configureand profiles, an API client, local stacks with product companions,loams live,pg,sql,graphandhousecommand groups,login,keys, agent tokens,mcp serveandmcp install, embedded docs,loams doctor. - The installer and self-update (CLI2, planned):
https://loams.dev/install.sh, prebuiltstandard,fullandclivariants,loams self-updatewith a signed manifest (D292 to D294). Today you install a package or unpack an archive. - The desktop runs
migrateafter an update (UP1 Task 18, D940): not built yet. Upgrades withloams upgradeare for compose stacks. - The daemon takes over supervision (DD1 DD1c, D790): today Electron main supervises the engine and the stacks. Bundling
loams-agentdin every desktop package besideloamsis D798; today the desktop release workflow bundles the engine only. - The console redesign (§59, plan CF1) makes the desktop feel less like a web page, with an agent-first home.
- Local stacks use development settings: the Postgres dev stack uses default credentials and
fsync = off(seedeploy/loams-postgres-dev).
How to try it
Loams Desktop
Download from the GitHub release and check the files against DESKTOP-SHA256SUMS. On macOS, after installing:
xattr -dr com.apple.quarantine /Applications/Loams.appOn Windows, SmartScreen shows "Windows protected your PC": choose More info, then Run anyway. The app opens in Studio; switch to Console with Mod+Shift+M. The local engine is the default server; add a stack on your tailnet by its URL, such as https://loams.<tailnet>.ts.net.
The loams CLI
From the GitHub release, check the release checksums, then install the package for your system (0.1.0 shown; file names carry the release version):
sudo apt install ./loams_0.1.0_amd64.deb # Debian, Ubuntu
sudo dnf install ./loams-0.1.0-1.x86_64.rpm # Fedora, RHEL, openSUSE
sudo pacman -U ./loams-0.1.0-1-x86_64.pkg.tar.zst # Arch, CachyOSExpand-Archive .\loams-0.1.0-windows-x86_64.zip -DestinationPath loams
Get-Item .\loams\loams.exe, .\loams\git-remote-loams.exe | Unblock-File
.\loams\loams.exe devRun an engine and create an API key for the CLI or an SDK (with LOAMS_AUTH_MODE=apikey on the stack):
loams dev
loams auth new-key --label laptop --append keys.txtAs a service on Linux:
sudo systemctl enable --now loamsUpgrading a compose stack
From the stack's directory (the bundle's release/, with compose.yaml and .env):
loams upgrade check --to 0.1.0 # what it will do, and what would stop it
loams upgrade --to 0.1.0 # asks first; --yes to skip the question
loams upgrade status # the stack's release, the ledger, the last attempt
loams upgrade rollback # restores the snapshot; prints the writes it loses firstDo not upgrade by editing LOAMS_VERSION and running docker compose up: 0.1.0 recreates the Postgres safekeeper, which must be drained first. For a VM set up with byoc/install.sh, deploy/release/byoc/upgrade.sh user@host --to V runs the same upgrade over SSH.
Source
- Design: §37 Desktop and mobile apps, §50 The desktop daemon, §30 The Loams CLI, §54 Upgrades
- Plans: AP1e Electron desktop, DD1 Desktop daemon, CL1 The CLI in production, CLI1, CLI2, UP1 Upgrades
- Release docs: packaging, desktop releases, upgrades, running Loams 0.1.0
- Code:
apps/desktop-electron,crates/loams,crates/loams-upgrade,crates/loams-migrate,crates/loams-agentd
Loams Software Factory
The self-hosted development toolchain that Loams Desktop and Studio bring into one window: Forgejo, Zulip, Plane, GlitchTip, OpenPanel, Matomo, Langfuse and OpenObserve, and the planned loop in which agents take an issue to a reviewed pull request.
SDKs
Seven Loams client libraries, generated from one set of protos, held to one runtime contract and checked against one recorded fixture corpus.