Skip to content

Architecture

Localix runs a React workspace against a local Bun API, with a Tauri shell packaging both for desktop use. Use this map to find the owner of a UI surface, runtime behavior, transport, or stored record before changing it.

Terminology

TermMeaningBoundary
Agentic Development EnvironmentThe product category covering connected development surfaces, context, model routes, agents, and extensible workbenches.Do not use it to exclude non-code workbenches.
SessionThe durable unit of direct or orchestrated agent work.A session can contain multiple runs.
WorkerA session created for delegated work.It is not automatically isolated.
Task boardA mini app from the Localix marketplace: a per-chat task board with dependencies and a card lifecycle.A mini app, not core; not a general project-management system.
WorkbenchA product surface a mini app contributes.It exists only while its mini app is enabled.
Work itemA typed editor-grid pane.Each registered kind owns its component and state contract.
Composition rootBootstrap code selecting concrete infrastructure.Feature modules receive those dependencies.

Ownership contract

PathOwnsBoundary
apps/apiHono routes, domain services, agent execution, persistence, and mini app hosts.Feature code reaches the agent loop through the runtime port.
apps/uiReact workspaces, typed panes, settings, and API/event clients.It requests state from the API; it does not own durable domain state.
apps/desktop-tauriNative window, release sidecar lifecycle, and desktop capabilities.Development scripts start the API instead of the Rust shell.
apps/landingDocumentation site and generated navigation.It is not part of the desktop runtime.
packages/agentProvider-neutral agent types, tools, messages, and runtime interfaces.It cannot import Localix API features or the engine.
packages/engine*The engine behind the runtime port: loop, model access, script sandbox.Production API imports are limited to the bootstrap composition root.
packages/mini-app-sdkThe mini app manifest (/app-manifest) and host contribution contracts.A contribution exists only when its extension is installed and enabled.
packages/cliThe localix launcher: it hands a path to the running desktop app.It opens a deep link; it never starts a runtime or renders a session.

How it works

Release startup

Plain text
Tauri shell
  -> reserve a loopback port
  -> spawn the bundled Bun sidecar
  -> wait for LOCALIX_RUNTIME_READY
  -> release the UI runtime-ready barrier
  -> connect API clients

The desktop release waits for the sidecar readiness signal before the UI opens its core event connection. In development, the Tauri code does not spawn that sidecar; workspace scripts own the API process, and a development build of the UI holds its first reads on the same barrier by polling the API's own /health (apps/ui/src/shared/lib/runtimeReady.ts) instead of failing into the startup retry ladder.

The first capability snapshot names every enabled mini app's tools. Answering that means running each mini app's register(), so the answer is kept on disk under ~/.localix/cache and a launch whose mini app code, config and host build are unchanged serves it without importing any backend (apps/api/src/features/mini-apps/inspection-store.ts). The UI publishes the enabled set and tools the moment that snapshot lands and registers each mini app's UI as its own artifact loads.

API composition

apps/api/src/bootstrap.ts is the composition root. Its phases create infrastructure, registries, mini app hosts, domain services, the chat service, the trigger engine, the application facade, routes, and background timers. Features receive those dependencies rather than constructing storage or the agent adapter themselves.

SQLite stores projects, sessions, messages, task state, provider connections, and other local records through Kysely repositories. Production stores media bytes in a filesystem directory next to the configured database file.

Client transport

ChannelMechanismBoundary
HTTP/RPCRequest-response operations use shared API types, checked at build time.Route availability depends on the running API and enabled hosts.
Core event socketOne retained /rpc/ws connection multiplexes subscriptions and WebSocket RPC.It is the shared application channel, not the transport for terminal bytes.
Terminal streamEach terminal pane opens a dedicated WebSocket for its PTY session.The pane closes that socket when its stream lifecycle ends.

The editor grid maps typed WorkItem records to pane components. Core panes are registered in the UI registry; enabled mini apps can contribute additional pane types through the extension host.

A value crossing into the browser needs its own leaf

@localixai/api/client is a TYPE-ONLY barrel. Types erase, so importing one costs the web bundle nothing; a VALUE import loads the module it lives in and everything that module imports. Because the barrel re-exports from the API's own contracts, one value export there can reach the chat contracts, the mini-app-sdk backend, and through them node:path / node:dns. Vite does not fail on that — it externalizes the builtin and hands the browser a stub that throws on first use (Module "node:dns" has been externalized for browser compatibility).

So a constant, schema, or helper the UI needs at RUNTIME gets a narrow subpath in apps/api/package.json (./tool-names, ./slash-catalog, ./tip-contracts, ./session-ref, …), pointing at a module with few or no imports — never a re-export from client.ts.

scripts/browser-graph-guard.test.ts enforces it by walking the module graph of everything the web build pulls in — the HTML entry plus each import.meta.glob (feature contributions, UI surfaces) — and failing on any node: import, with the chain that reached it.

Agent execution

The chat service assembles session context, effective configuration, tools, permissions, and persistence around the AgentRuntime port. The production composition root supplies the engine. The agent runtime boundary owns that interface and its event contract.

A task board, a mini app of the Localix marketplace, is a passive board per chat, stored in that chat's mini app folder. Core names no board. The app reaches the host only through generic seams — per-chat storage, the agent directory, the tool's bound agent, a resource and a search provider, and a live-frame stream. It creates no session and starts no run; agents create child sessions only with the Agent tool.

Configuration

Architecture checks are repository commands, not runtime settings.

CommandChecks
bun run check:architecturePackage import boundaries, engine layers, and the composition-root rule.
bun run check:docsInternal subsystem references documented by the architecture checker.
bun run --cwd apps/landing docs:genDocumentation metadata, links, repository paths, and generated navigation.

Plugin and mini app enablement changes which tools, providers, hooks, and workbench panes the hosts register. Build a mini app owns the mini app manifest fields and contribution lifecycles; Install Claude Code plugins owns what a plugin runs. Plugins and mini apps is the contract between the two.

Limits

  • The release desktop starts a local sidecar. Sessions execute on that machine; there is no remote execution adapter.
  • The core event socket is multiplexed, while terminal panes use separate stream sockets. Treating all live traffic as one connection is incorrect.
  • SQLite and filesystem stores are local process dependencies. This layout is not a distributed control plane or multi-node persistence design.
  • The architecture checker validates import text and known package rules. It does not prove runtime behavior or dependency injection correctness.
  • Extension surfaces are conditional. An installed mini app can be disabled, and an installed plugin or mini app can omit a contribution type.
  • Tauri release startup and development startup deliberately differ. A failure reproduced in one path may not exercise the other.

Source of truth