Local Weights · docs/MANAGER_ARCHITECTURE.md

System architecture — the manager boundary

Four layers, two hard boundaries. Below the UI boundary no Tauri type exists and progress flows as serializable data on per-operation channels. At the trust gate, profile operations receive an Arc<TrustedRegistry> as an argument — a type whose sole constructor is signature verification. The manager holds no registry state, no job registry, and no event bus: callers own tracking, the manager owns the work.

Layer 1 · consumers & adapters — presentation, consent, wording. No business logic.

Desktop app apps/desktop

Catalog, library, peers, consent dialogs, notifications.

Svelte UI

Renders plans, progress, APPROVED/MANUAL, SIGNED badge. Owns all human-facing wording.

Tauri adapter profile_cmds.rs · thin

Owns LoadedRegistry + registry sync, the OperationId → CancellationToken map, and task handles. Forwards each operation's events → app.emit. Manual peer/ticket cmds stay unchanged.

CLI apps/cli

Second consumer — keeps the boundary honest.

weights profile list · show · plan · acquire · install · start · stop · restart · status · run · logs · uninstall

Plus weights join (invites) and weights scan-dir add/remove/list (custom scan folders). Loads the signed cache, constructs the same manager, owns one foreground OperationContext; Ctrl-C cancels it. May need the desktop app stopped to open the iroh store.

↓ ↓ plan(registry, name) · acquire(registry, name, OperationContext) — Arc<TrustedRegistry> snapshot per call
↑ ↑ per-operation mpsc<ManagerEvent> — Planned · Acquiring · Verifying · Acquired · InstallingRuntime · StartingService · RuntimeInstalled · Cancelled · Failed
UI boundary no Tauri types below · events Serialize + operation_id + profile · caller owns tasks, tokens, and terminal state

Layer 2 · orchestration — the one implementation of "install a profile".

weights-manager crates/manager

Owns policy and sequencing, nothing else. Fields: data_dir · db · p2p — constructor-injected; no registry state, no job registry, no event bus, never reads UI state.

trust gate · plan/acquire take Arc<TrustedRegistry> as an argument — UnsignedDev(Registry) cannot enter; browsing/badges only. An operation keeps the exact snapshot it was called with, even if the app syncs a newer release mid-flight.

lib.rs

ProfileManager { data_dir, db, p2p } · plan(), acquire(), and the service lifecycle (install · start · stop · restart · status · uninstall) · DTOs (ProfilePlan, AcquisitionSource, AcquiredProfile, InstalledProfile) all Serialize.

acquire.rs

Hardware facts → tier → source choice; local reuse short-circuit; LAN transfer with HF fallback; conservative disk math; verify (BLAKE3 + SHA-256) before exposure; .acquire.lock cross-process guard; record into db; cancellation checked between stages.

OperationContext supplied per call

id + CancellationToken + mpsc::UnboundedSender. Caller creates and tracks it; manager honors it. Cooperative cancel leaves resumable .part/iroh state and returns Cancelled.

events.rs types only

ManagerEvent: Clone + Serialize, operation id + profile on every event. Sent through the caller's channel — no bus, no replay, no subscribers.

runtime/

mod.rs + launchd.rs + systemd.rs — both service backends shipped for the macOS and Strix Halo targets. Verified artifacts (archive + binary hashes, symlink-safe extraction), clone/hardlink materialization, exact argv + constructed env, install/uninstall, health as identity (/props must report the managed model), repair data.

ManagerError one enum

Serializable thiserror enum, tag = "code": ProfileNotFound · UnsupportedHardware{detected_gib, minimum_gib} · InsufficientDisk{req, avail} · MissingCredentials · AlreadyAcquiring · ProfileNotInstalled · Service · RuntimeArtifact{Missing, HashMismatch} · RuntimeUnhealthy · Cancelled · Internal · … — data, not UX copy.

verify releases · schema validation · hashing · HF primitives · db · hardware facts · linking
providers_for(blake3) · download_with_progress(hash, providers) · export · local_bytes for disk planning
trust gate origin TrustedRegistry has private fields — verify_release / signed-cache load are its only constructors

Layer 3 · primitives — mechanism, no policy. Neither crate knows the manager exists.

weights-core crates/core

Identity, verification, storage, file mechanics.

registry_signing → TrustedRegistry ★ registry · match by sha256/blake3 profile schema + reserved-flag validation acquire: HF resume · disk · hw facts hash (sha256+blake3 single pass) integrity (gguf/safetensors) link: clone/hardlink/symlink/copy · dedup: clone/hardlink state: SQLite · scan gens · journal scan: hf · ollama · lmstudio · llama.cpp · acquired/

weights-p2p crates/p2p

Verified transfer. BLAKE3 is the only identity on the wire.

iroh endpoint · relay off = LAN-only mDNS address lookup have/1 — frozen wire format FsStore · TryReference imports multi-provider download · resume tickets
↓ ↓ ↓ ↓ https (signed registry · HF · pinned artifacts) · iroh/QUIC (peers) · filesystem · exec

Layer 4 · the world — everything the system talks to but does not contain.

Signed registry host

release.json + registry.json. Any https host or local path; trust is the Ed25519 key, never the host. Rollback-protected by version.

Hugging Face · llama.cpp releases

Fallback weight source at pinned revisions (Range resume, HF_TOKEN); runtime artifacts pinned by build ID, source revision, archive SHA-256, and binary SHA-256.

LAN peers

Other machines running Weights. Preferred byte source. Approval is receiver-side against each machine's own trusted registry.

Host system

~/.weights (state.db, trust.json, acquired/, blobs/, runtimes/, logs/) · app caches (HF, LM Studio, Ollama, llama.cpp) · launchd / systemd user services running llama-server.

Boundaries

  • — — green: UI boundary. Below it, no Tauri; progress and errors are serializable data with operation identity.
  • — — amber: trust origin. The only path to TrustedRegistry is signature verification in core; the manager's profile API makes unsigned state unrepresentable, not just rejected.
  • dashed boxes: outside the codebase (layer 4).

Rules the picture encodes

  • Dependencies point down only: adapters → manager → core/p2p. Nothing below knows what's above.
  • Policy lives in exactly one layer (manager); core and p2p are mechanism; adapters are wording.
  • Registry state lives in the adapters; the manager only ever sees immutable trusted snapshots, passed per call.
  • Two consumers (Tauri + CLI) exercise the same manager — the boundary stays honest because it has two clients.
  • Cross-process safety is filesystem-level (.acquire.lock); in-process lifecycle is caller-owned tokens and task handles. Terminal results return from acquire() itself — nothing depends on catching every event.