Skip to content

research(setbuilder): LexiconDJ as an optional measured-energy source of truth for WrzDJSet (+ library sync) #526

Description

@thewrz

Why

WrzDJSet's per-track energy (set_pool.energy / track_vibe.energy, 0–10) is currently
LLM-inferred (vibe_enrichment.py, #391) — a guess, not a measurement. LexiconDJ runs a
real audio energy analyzer. For DJs who subscribe to Lexicon and keep a local library, we
can offer Lexicon's measured energy as an optional source of truth for WrzDJSet, plus
bidirectional library/playlist sync.

Hard boundary: this is WrzDJSet-only. Normal WrzDJ (the guest request pipeline) is
cloud SaaS and must stay on cloud sources — it cannot depend on a DJ's locally-running app.

This is a research/decision issue (no ADR system here; closest prior records are the #401
spec/plan under docs/superpowers/).

Verified current state

LexiconDJ surfaces

Surface Locality / auth Capability
Local REST API http://localhost:48624 localhost-only, off by default, no auth (vendor: "coming"), app must be running read GET /v1/tracks (tracks/playlists/cues/beatgrids/tags)
Plugin (JS, sandboxed) runs inside Lexicon, DJ-installed from Documents/Lexicon/Plugins full CRUD tracks+playlists; reads all fields; outbound HTTP POST to whitelisted domains, ignores CORS (_network)

Plugin globals: _library (CRUD), _vars (selected/all tracks), _network, _storage,
_ui, _musicplayer, _helpers, _files. Sandbox: no require/import/window/document.

Analyzer + the constraint

Lexicon measures energy (absolute scale), BPM/beatgrid (~3ms), key (built-in or free
OpenKeyScan), cue points (ML). Analysis runs on local audio files ("tracks imported from a
DJ app are not auto-analyzed"). WrzDJ tracks are Tidal-backed (no file), so Lexicon data is
available only when the DJ owns + analyzed that track locally — a match-and-enrich keyed
on ISRC (which WrzDJ already carries end-to-end).

Use-case mapping

Use case Verdict
Measured energy → WrzDJSet 🎯 primary goal — ISRC-match a pool track to the DJ's local Lexicon track, pull measured energy, normalize to 0–10, prefer over the LLM guess. Subscriber/opt-in.
Library/playlist sync (import Lexicon → WrzDJ pool) 🆕 plugin reads tracks → POST to WrzDJ ingest; slots into epic #442 Family 4 as import_from_lexicon (cf. #524).
key/BPM already cloud-covered (Beatport/Tidal). Lexicon only as a WrzDJSet fallback-primary if cloud misses — not a normal-WrzDJ path.
cue points ⏭️ deprioritized (no pool/set consumer today).
export WrzDJ → Lexicon ✅ exists (#401 Rekordbox XML); optional CSV-merge-on-ISRC polish later.

Architecture + distribution

Primary — WrzDJ-authored Lexicon plugin. Whitelists the WrzDJ API domain, reads tracks
(+ measured energy), POSTs to a new DJ-scoped WrzDJ ingest endpoint. Outbound HTTPS, so
topology-agnostic — works wherever Lexicon runs, including a Windows DJ VM today (no
co-located bridge needed). Can also _library.playlist.create from a WrzDJ set (improves on
the #401 relink flow).

Distribution: the bridge-app installer optionally bundles the plugin installer (drops
the plugin ZIP into Documents/Lexicon/Plugins). Plugin source lives in the WrzDJ monorepo
(lexicon-plugin/), packaged by the bridge-app build — versioned in lockstep with the ingest
contract.

Alt — bridge polls the Local API (read-only). Lighter (no Lexicon-side install) but can't
write playlists, no auth today, and the bridge-app must run on the same host as Lexicon.

Phase 2 (optional) — ISRC match-rate aid via SonoVault. SonoVault
(api.sonovault.now, x-api-key) is an identity/ISRC↔platform-ID resolver — verified to
return id/title/artists/releases/isrc/duration/genre/subgenre + cross-platform links
(Spotify/Beatport/Apple/Tidal/Discogs/MusicBrainz), no BPM/key/energy. Useful to resolve a
Tidal ISRC → Beatport ID (feeding cloud key/BPM) and to raise local-match hit-rates. Pure
matching infra, not an analysis source.

Licensing posture

Lexicon = Rekordcloud B.V., commercial (free + Basic/Pro + Lifetime); conversions/imports are
free-tier. Published Terms are silent on API/plugins (neither grant nor forbid) and the
surfaces are officially documented. Posture: DJ owns + runs + opts into their own licensed
Lexicon
; WrzDJ never bundles/redistributes Lexicon or its data; documented surfaces only
(no reverse engineering, no DB writes); treat capability as best-effort/revocable and
degrade gracefully.

Risks & caveats

  • Local-file analysis ⇒ energy available only for tracks the DJ has locally (ISRC-gated, opt-in).
  • Local API has no auth today (vendor intends to add it) ⇒ the read-only bridge path is
    fragile; the plugin path is more durable.
  • Subscriber/paid-software dependency + must-be-running + opt-in friction.
  • Thin public plugin ecosystem (early-adopter).

Open questions to resolve before building

  1. Lexicon energy scale → exact normalization to WrzDJ's 0–10.
  2. Does GET /v1/tracks expose ISRC + energy fields directly (needed to match + enrich)?
  3. Do the API/plugins require a paid Lexicon tier (imports are free; API/plugin tier unconfirmed)?
  4. DJ-scoped WrzDJ token delivery into the plugin (config field vs bridge-style pairing).
  5. Bridge-app installer mechanics for optionally writing the plugin ZIP into Documents/Lexicon/Plugins.

Proposed follow-up implementation issue

Child under #442: feat(setbuilder): import_from_lexicon + measured-energy enrichment
(owner-scoped, rationale on mutation, never writes requests, additive/undoable; mirrors #524).

References

#442 (epic), #401 + PR #453, #396, #524 (Family-4 import pattern); enrichment-pipeline
audit #527; docs/superpowers/specs/2026-06-17-issue-401-design.md,
docs/superpowers/plans/2026-06-17-issue-401-engine-lexicon-export.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-engineAI Engine Back-end Redesign (provider-agnostic LLM gateway + OAuth)enhancementNew feature or request

    Type

    No type

    Projects

    • Status
      Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions