MusicSeed — Dependency & Workflow Architecture

React web surface + standalone REST API · August 2026 · SQLite only No Docker No ML runtime REST API Next.js web

This document explains every dependency MusicSeed relies on today — Python packages, data stores, network services — and how data flows through the four main workflows (import, enrich, sonic retrieval, recommend) and the two surfaces (CLI, and the Next.js web UI via the REST API). It exists to track how small the install surface has become, so publishing MusicSeed as open source means a new user needs as little as possible.

TL;DR install surface: Python 3.12+ and SQLite 3, plus Node for building the web UI during install; six core packages, two CLI packages, three API packages, and a Next.js + React web app — one SQLite file (created automatically), and read access to two Plex SQLite databases. Local-network Plex discovery (GDM + SSDP) is stdlib socket only; servers on other subnets are found through the optional plex.tv/api/resources account lookup (httpx, needs a Plex token). uv is development-only tooling — the end-user install is plain python3 -m venv + pip. That's the whole thing — no server, no containers, no native ML libraries.

1. The big picture

Browser → musicseed-web Next.js · React · TypeScript musicseed-cli Typer commands · Rich output musicseed-api handlers/ · orchestration · no UI FastAPI JSON routes at /api/ musicseed-core (import name: musicseed) services/ · importers/ · enrichers/ · recommender/ · sonic.py · plex_discovery.py deps: sqlalchemy · pyyaml · httpx · numpy · pydantic · rich all business logic lives here — no UI, no Typer, no HTTP musicseed.db (SQLite) ~/.local/share/musicseed/ · WAL read + write · MusicSeed's own state Plex metadata DB com.plexapp.plugins.library.db READ-ONLY (stdlib sqlite3) Plex blobs DB …library.blobs.db · sonic vectors READ-ONLY at query time Plex HTTP API playlists · sonic Butler trigger optional · token required External APIs ListenBrainz (preferred) MusicBrainz (MBIDs) Spotify (optional fallback) rate-limited · enrichment only JSON / HTTP services only services (direct) SQLAlchemy ORM import sonic vectors httpx · playlist writes httpx · async
Everything MusicSeed touches. Green borders are read-only SQLite files owned by Plex; the blue-bordered file is the only writable store. Amber is network I/O. Purple is the API orchestration layer — the browser UI reaches it over HTTP (Next.js proxy), while the CLI calls core services directly. Removed in the dependency reduction: PostgreSQL server, Docker, pgvector, psycopg, essentia-tensorflow, Jinja/HTMX server rendering, and all audio-file reads.

Python packages (core)

6

sqlalchemy, pyyaml, httpx, numpy, pydantic, rich — all pure-Python or widely pre-built wheels.

Python packages (surfaces)

2 + 3 + Node

cli: typer, rich · api: fastapi, uvicorn, python-multipart · web: next, react, react-dom (Node). Web talks to api over HTTP; api and cli depend on core via editable paths.

External processes

0

No database server, no container runtime, no daemon. Plex itself is the only assumed service.

2. Dependency ledger (before → after)

Python packages

PackageRoleStatus
sqlalchemyORM over the SQLite state filekept core
httpxHTTP to Plex API + ListenBrainz/MusicBrainz/Spotifykept core
numpySonic vector math (matmul, cosine) at query timekept core
pydanticConfig + service result modelskept core
pyyamlconfig.yaml loadingkept core
richProgress rendering inside import/enrich pipelineskept core
typerCLI frameworkkept cli
fastapiREST API request handlingkept api
uvicornASGI server for the APIkept api
python-multipartHTML form parsing (setup wizard, credential forms)kept api
next / react / react-domNext.js + React client-rendered web UI (Node)kept web
jinja2Server-rendered templatesremoved · React rewrite
htmx (vendored file)Fragment updates without a JS build stepremoved · React rewrite
essentia-tensorflowSelf-generated audio embeddings (MusiCNN)removed · Phase 1
psycopg[binary]PostgreSQL driverremoved · Phase 3
pgvectorVector column type + cosine-distance queryremoved · Phase 2

Infrastructure & system requirements

ComponentFormer roleStatus
PostgreSQL 16 serverMusicSeed state databaseremoved · Phase 3
Docker / docker-composeRan the Postgres containerremoved · Phase 3
pg_trgm extensionTrigram indexes (never queried)removed · Phase 3
TensorFlow runtimePulled in by essentia; amd64-onlyremoved · Phase 1
Audio-file accessReading music files to embed themremoved · Phase 1
Stored embeddingsVector(200) column, zero-padded from 50removed · Phase 2

What remains external (and can't be removed)

DependencyWhy it existsAccess
Plex metadata DBSource of truth for artists/albums/tracks/tags/play historyread-only, stdlib sqlite3
Plex blobs DBPlex's own 50-dim sonic analysis vectorsread-only, at query time
Plex HTTP APICreating/populating playlists; triggering sonic analysisoptional, token-gated
ListenBrainz / MusicBrainzPopularity enrichment via recording MBIDsoptional, rate-limited
Spotify Web APIFallback popularity/metadata when MBIDs are missingoptional, credentialed
Why sonic vectors are not a stored dependency: Plex already computes a 50-dimensional vector per track during its own sonic analysis. MusicSeed reads those vectors straight out of the Plex blobs database into an in-memory L2-normalized matrix (sonic.py → SonicVectors) when a recommendation runs. Nothing is copied, embedded, or indexed — so there is no vector column, no ANN index, and no embedding pipeline to maintain.

3. Workflows

3.1 Import — Plex metadata → musicseed.db

Plex metadata DB read-only sqlite3 importers/plex.py row mapping · year fallback services/library.import_library batch commits · resumable musicseed.db 13 tables
musicseed import — one-way copy of artists, albums, tracks, genres, moods, styles, play history. The Plex file is never written to.

3.2 Enrich — popularity signals (async, resumable)

tracks with MBID musicseed.db queue enrichers/pipeline.py async · bounded concurrency · retries ListenBrainz preferred (MBID-keyed) Spotify optional fallback · credentials popularity columns musicseed.db · batch commits
musicseed enrich --source listenbrainz|spotify — attempted tracks are flagged so interrupted runs resume. This is the only workflow that spends third-party API calls, which is why old Postgres data was migrated rather than re-fetched.

3.3 Sonic retrieval — vectors at query time (no storage)

Plex blobs DB read-only sonic.py decode 50-dim · L2-normalize · cache SonicVectors (in RAM) ~60K × 50 float32 ≈ 12 MB nearest() numpy matmul · ms-scale
At this scale brute-force cosine search is single-digit milliseconds — faster than any server round-trip. No ANN index, no vector column, no padding hacks.

3.4 Recommend — six signals, explainable

seed tracks IDs or text SeedProfile resolve_seed_tracks build_candidate_pool sonic (numpy) + 5 SQL sources calculate_score ScoreBreakdown · 6 weights playlist max 3 / artist signals: sonic · popularity · style · genre · era · novelty — every score is explainable via --explain
musicseed recommend previews; playlist / populate ask for confirmation, then write to Plex over the HTTP API — the only workflow that mutates anything outside musicseed.db.

4. What a brand-new user needs (open-source readiness)

Prerequisites

· Python 3.12+, SQLite 3, Node.js/npm (install only)

· Plex Media Server with a music library, sonically analyzed

· Optional: Spotify API credentials (fallback enrichment only)

Install (from a git clone)

./scripts/install.sh

musicseed then open http://127.0.0.1:8789

The first-run wizard discovers Plex, initializes the database, and walks through import/enrichment. Node is not needed after install.

Still on the road to pip install musicseed

GapNotes
PyPI packagingcore + cli + web are separate distributions joined by editable paths; decide on one combined package or publish them all.
Plex DB discoveryServer discovery is solved (GDM/SSDP; plex.tv/api/resources for other subnets). On-disk db_path probes macOS and Linux candidates; Windows is untested.
Sonic analysis coverageRecommendation quality depends on Plex having analyzed the library; sonic-probe reports coverage, sonic-refresh triggers the Butler task.

5. Verify the current state

cd core && uv run ruff check src
cd api  && uv run ruff check src && uv run pytest tests -q
cd cli  && uv run ruff check src && uv run pytest tests -q
cd web  && npx tsc --noEmit && npm run lint
python3 -m compileall -q core/src/musicseed api/src/musicseed_api cli/src/musicseed_cli
cd cli && uv run musicseed-cli init-db      # creates the SQLite file
uv run musicseed-cli status                  # shows DB path + file size
uv run musicseed-cli recommend --seed-id 123 --limit 20 --explain