Skip to content

File map

Where things physically live: packages, proto trees, CLI entry points, and the webui's unwired inventory. This is the descriptive companion to docs/architecture.md — that document is normative (boundaries, ownership, invariants); this one just tells you where the files are.

Runtime layout

The voice runtime ships as one logical package, packages/aleph/, with the two languages it needs:

  • packages/aleph/server/ — Go orchestrator (audio routing, satellite plane, settings store, webui, sidecar supervision). Module aleph/server. Entry point cmd/aleph/.
  • packages/aleph/sidecar/ — Python ML pipeline (stateless calc server): STT via ParakeetSTT / onnx-asr by default, with opt-in WhisperCppSTT / pywhispercpp; Silero VAD; livekit_turn + smart_turn ONNX (raw scores, no statemachine); local LLM inference via llama.cpp/xllamacpp; TTS; the one shared text embedder (memory + tool arming) and the speaker embedder. The sidecar is llama.cpp-only for LLM — remote providers (Anthropic and OpenAI-compatible: OpenAI, DeepSeek, Gemini, Ollama, LM Studio, vLLM) never reach the sidecar. They're served by internal/core/provider/apillm in the Go server, which talks to the API directly over HTTP; API keys live only in the Go settings store. The end-of-speech statemachine lives in the Go server (internal/core/endpoint/); the sidecar's ClassifyTurn RPC is a stateless calc verb that returns raw turn-detector probabilities. See docs/concepts/models.md for the full model topology and CPU/GPU residency table. Importable module aleph_sidecar, packaged with pyproject.toml + uv.lock.

Both are released and developed together. The server supervises the sidecar subprocess; envprep (packages/aleph/server/internal/sidecar/envprep/) provisions the sidecar venv before launch.

Sibling packages outside the merged runtime:

  • packages/protocol/alabama-go/ — Alabama 3.0 wire-protocol Go library (framing, Noise transport, generated stubs, conformance exerciser) shared with the satellite side.
  • packages/satellites/reference/ — Go reference satellite; doubles as the shared satellite client library (desktop and discord build on it).
  • packages/satellites/desktop/ — Wails desktop client (Go + Vue frontend).
  • packages/satellites/android-kiosk/ — Android satellite app (Echo Show kiosk launcher; always-on wakeword + AEC3).
  • packages/satellites/android-companion/ — Phone-side Aleph companion (Digital Assistant role, on-demand mic, phone-control tools).
  • packages/satellites/android-rokid/ — Phone-side companion for the Rokid RV101 glasses: streams the glasses mic in and TTS out, renders live captions on the heads-up display, exposes the glasses camera as a WEBCAM image-capture source, and carries an in-app drag-and-drop glasses-UI editor. The real glasses link (CXR-L SDK) is gated behind -PenableCxr; the default build compiles a stub link and stays green.
  • packages/protocol/alabama-android/ — Shared Kotlin Alabama 3.0 library (Wire-generated v3 stubs, Noise XX transport, AlabamaSession) consumed by the Android apps via Gradle composite build.
  • packages/satellites/esp32-s3-audio-board/ — ESP32-S3 firmware satellite (Waveshare audio board, ES7210/ES8311, esp-sr AFE for AEC + microWakeWord).
  • packages/satellites/respeaker/ — ESP32-S3 firmware satellite for the Seeed reSpeaker XVF3800 4-mic array (hardware AEC/beamforming, microWakeWord, LED ring via XVF3800 I2C).
  • packages/protocol/esp32-components/ — shared ESP-IDF components (alabama wire client, ggwave decoder) consumed by both firmware satellites.
  • packages/aleph/webui/ — Svelte 5 management UI embedded into the aleph binary via go:embed (built by task webui-build).

Server internal layout

packages/aleph/server/internal/ is being grouped into concern sub-directories instead of one flat pile of packages, along the role axis of docs/architecture.md. internal/core/ (the pipeline brain — deciders, stores, identity, memory, turn loop) already nests this way; the rest of the tree is migrating cluster by cluster. Within a group with a natural hub the hub package sits at the group root and its extensions nest beside it (e.g. sink is the registry hub, sinkfactory and upnpsink live under it). Most moves are import-path-only — the package identifier is unchanged — but a package that reads better under a cleaner name is renamed outright (transport's alabama/listener).

  • internal/playback/ — the assistant→device output plane (architecture §2 SPEAK side):

    • audio/ — PCM utilities/resampler (hub), with audioenc/ (container encoding) and audiorouter/ (fan one PCM source out to N sinks) beside it.
    • sink/ — audio-sink identity + live registry (hub), with sinkdiscovery/, sinkfactory/, sinkhttp/, upnpsink/, and satellitesink/.
    • speak/ — spoken-output behaviours: announce/, voicegate/, greeting/.
    • routing/ — Output Routing (sinks): resolves a source satellite's configured output assignment into concrete audiorouter.PlayTargets. It is a §9 decider (system=core), but lives here with the sinks it routes, exactly as the Provider/Model Router lives in core/provider/ with the backends it routes — physical home follows the domain, not the system tag.
  • internal/transport/ — the satellite↔core wire ingress (architecture §6):

    • alabama/ — Alabama wire-session adapter (was satellitealabama).
    • listener/ — the satellite-connection server + turn driver (was server).
    • lannet/ — what of the server is reachable from the LAN.
  • internal/satellite/ — the satellite domain (architecture §3): the session/state-machine satellite package is the hub, with devices/ (device registry), satellitetools/, softsat/ (software-satellite catalog), and pairingidentity/ (Noise identity + admission) nested under it.

  • internal/sidecar/ — the sidecar runtime: bring it up, supervise it, self-heal it (architecture §5/§11). The gRPC-client sidecar package is the hub, with envprep/ (venv/torch/wheel provisioning), binprep/ (per-tool binary/wheel fetch: uv/, whispercpp/, opencode/, librespot/), hwdetect/ (accelerator probe), proctree/ (kill-group subprocess spawning), supervisor/ (env-healing orchestration), status/ (provisioning-status broadcast), healthlog/ (resilience-event log), src/ (the embedded Python source tree, was sidecarsrc), and embedtree/ (embedded-tree materializer, was embedsrc — not embed, which collides with the stdlib package) nested under it.

  • internal/tools/ — the tool plane (architecture §8): everything federates into the tools registry, which is the hub at the group root. providers/ (the tool-provider registry + every provider: the multi-instance homeassistant/, calendar/, spotify/, mcp/, iobroker/, memory_recall/, plus the singleton-provider impls coding/, lists/, websearch/) nests under it — tools/providers cleanly disambiguates from core/provider (the LLM backends). The shared, non-provider tool infra stays as peers beside providers/: servertools/ (image-capture orchestrator tools), imagecache/ (tool-produced image store), entityindex/ (shared entity index the satellite/transport planes also read), and tooldispatch/ (dispatch context flags).

  • internal/obs/ — the observability/telemetry plane: tracing (the OTel tracer + recording processor), livespans (in-process span pub/sub), spanschema (generated span binding), metrics (Prometheus), and prettylog (the coloured slog handler). No hub — five peer packages.

  • internal/scheduling/ — background and scheduled work: jobs (scheduled background jobs), scheduler (timers, reminders, recurring), and background (long-lived maintenance workers).

  • internal/webui/ — the server-side management plane. The webui package is the hub: it serves the browser over Connect. Its one read-model nests under it — threads/, the span-backed conversation index that subscribes to obs/livespans and feeds the WebUI's conversation view (a consumer of the telemetry plane, not part of it). static/ holds the embedded webui dist.

A handful of genuinely cross-cutting utilities stay flat at the internal/ root on purpose — grouping unrelated packages into a platform/ bucket would just push the flatness down a level: config (bootstrap env), i18n, slug, topology (the wiring extractor), testutil, and settings (the settings store, read by server, sidecar, and webui alike). pb/ (generated stubs) likewise stays put. recorder (the per-turn input+output recording) is a turn concern that folds into core/ when that boundary is next revisited.

Tool providers

The Go server hosts a tools/providers.Registry at packages/aleph/server/internal/tools/providers/. It owns all server-side tool providers: each one implements TypeID() / Cardinality() / Reconcile(...) and produces one or more Profiles with their own Tools() for the LLM. The registry subscribes to the settings store, re-reconciles every provider on each change, and republishes the aggregated tool set into tools.Registry. Singleton providers (websearch, conversation_control, display, image, coding, …) live as single files in the providers root. Multi-instance providers — mcp/, homeassistant/, calendar/, spotify/ — get their own sub-package because their implementation grows beyond one file; the MCP provider supervises one client per configured server from Settings.Tools.Providers.McpServers (the per-transport client is still the disconnected stub until the stdio/HTTP transports land).

Satellite tools are deliberately not providers: they are device-owned and session-scoped, advertised over Alabama when the device connects and registered directly with tools.Registry under the device's own owner key (internal/tools/registry.go). The trust model — why every satellite-advertised tool is stamped peer-trusted at registration — is an architecture invariant; see the tools section of docs/architecture.md.

The Home Assistant provider at packages/aleph/server/internal/tools/providers/homeassistant/ reads exposure from HA's own assist-pipeline registry over WebSocket (no Aleph-side whitelist) and exposes four tools to the LLM: homeassistant_get_state (state + sensor value/unit + cover position), homeassistant_set_state (lights/switches: on/off, color, brightness), homeassistant_set_cover (covers: open/close/stop/set_position via an action enum — a tight schema keeps small local models reliable), and homeassistant_list_entities. The optional location parameter selects between multiple configured HA instances.

Proto layout

Proto sources live in two trees, one per logical package:

packages/aleph/proto/aleph/ — server/sidecar/webui surface:

  • settings/v1/ — settings tree consumed by server, sidecar, and webui. Go in packages/aleph/server/internal/pb/aleph/settings/v1/, Python in packages/aleph/sidecar/aleph/settings/v1/, TS in packages/aleph/webui/src/lib/pb/aleph/settings/v1/.
  • sidecar/v1/ — server↔sidecar gRPC surface. Go in packages/aleph/server/internal/pb/aleph/sidecar/v1/; Python in packages/aleph/sidecar/aleph/sidecar/v1/.
  • user/v1/User entity shared by the settings tree and the webui surface.
  • webui/v1/WebUIService Connect service consumed by the browser (GetSettings, UpdateSettings, SubscribeSettings).

packages/protocol/alabama-go/proto/aleph/alabama/v3/ — Alabama wire protocol, generated into packages/protocol/alabama-go/v3/pb/ (Go) and the nanopb ESP component (C).

docs/protocol/proto/ — the canonical .proto source for the Alabama 3.0 wire protocol, source of truth for the specification. task spec-alabama injects these into the Bikeshed spec (docs/protocol/alabama-3.0.bs) and renders it to docs/public/spec/, which the docs site serves at /spec/. The schema in the spec is never hand-copied, so it cannot drift from the .proto.

aleph CLI

The Go binary built from packages/aleph/server/cmd/aleph/ dispatches on the first positional argument; a leading flag falls through to server for ergonomic invocations like aleph -debug.

  • aleph server (default) — runs the orchestrator. Loads bootstrap + settings, spawns and supervises the Python sidecar, serves the satellite plane, the webui, and the settings gRPC service.
  • aleph sidecar — runs envprep then execs the Python sidecar in the foreground (stdio attached, no supervision). Useful for profiling, standalone runs, or a future remote-sidecar deployment. Flags: -no-envprep, -gpu-extra, -settings-addr, -debug.
  • aleph device-code <device-id> — prints the captive-portal access code for a paired satellite. Read-only.

WebUI: unwired inventory

The Svelte webui (packages/aleph/webui/) renders every page from the real design dump, but some interactive elements have no backend to call — either the proto has no field/RPC for the concept at all, or the field exists but nothing server-side acts on it yet. Those elements are wrapped in <Unwired topic="..."> (packages/aleph/webui/src/lib/components/ Unwired.svelte): the control renders, looks real, but clicks are swallowed (stopPropagation/preventDefault in capture phase) and a small dot marks it as inert. This is a deliberate data-honesty rule — the UI never fabricates state or fakes a working control. Regenerate this table with rg -o 'topic="[a-z-]+"' packages/aleph/webui/src -r '$1' | sort -u (excluding the "x" topic, which only exists in a component test harness).

TopicFeatureFehlendes Backend
attributionNutzer → Zuordnung tab: reassign a turn's speaker, merge two usersNo turn-reassignment RPC and no user-merge RPC exist; only listing users (to pick a merge target) is real
identity-inboxNutzer page: inbox of unlinked identities awaiting attributionNo unlinked-identity/inbox data source exists anywhere in the proto; the section is a static example row
identity-linksNutzer → Identität tab: pairing PIN, linked external accounts (email/phone)No account-linking concept or RPC exists in the proto at all
identity-selfNutzer: "DU" badge marking the operator's own profileNo operator/"this is me" signal exists anywhere
mcp-crudWerkzeuge → MCP section: add/enable-toggle/remove an MCP serverProviders.mcp_servers is a real settings map, but the Go MCP provider's per-transport (stdio/HTTP) client is still a disconnected stub — writing entries wouldn't connect anything
pairing-wordsSatelliten pairing modal: play spoken verification words for an already-connected guestNo RPC derives/speaks a word triple for a connected-but-unapproved device (GeneratePairingToken is a different, not-yet-built "add a brand-new device" flow)
providersEinstellungen → LLM "weitere Maschine verbinden" row; Anbieter page's "Maschinen" / "Verbundene Dienste" cardsNo settings model exists for registering additional inference machines or generic connected services
sat-blocklistSatelliten pending list: deny a request, remove a blocked deviceNo deny/block/reject RPC exists; ApproveSatellite has no counterpart, so the blocked list is always empty
sat-fqnSatelliten detail: fingerprint button meant to reveal a second identifierSatellite carries only one identifier (device_id); there is no second value to reveal
sat-output-routingSatelliten detail: picking an audio-output sinkSatellite has no output-sink-binding field and no RPC persists one; the sink list itself is real (ListSinks/ScanOutputDevices)
sat-removeSatelliten detail: "Entfernen" (forget device)No remove/forget-satellite RPC exists
sat-roomSatelliten detail: Raum/Zone fieldSatellite has no room/zone field at all
tool-aclWerkzeuge tab: per-tool access-scope select (Nur ich/Alle/Bestimmte)No per-tool ACL/access-scope path exists anywhere in settings.proto
tool-acl-peopleWerkzeuge tab: specific-people picker for a tool's access scopeSame gap as tool-acl — no people-scoping field or RPC exists

These are backend gaps, not webui bugs — closing one means adding the proto field/RPC and its server-side implementation first, then removing the Unwired wrapper.