Skip to content

Enrichment & Analysis

Scroll horizontally to explore the full data flow.

Input SourcesProcessingOutputsDownstreamStratum analysis to genre classificationStratum analysis to set and pool scoringEssentia analysis to genre classificationEssentia analysis to set and pool scoringDiscogs metadata to genre classificationDiscogs metadata to metadata backfillBeatport metadata to genre classificationBeatport metadata to metadata backfillAudio Filestrack audio on diskTrack Metadataartist, title, albumstratum-dspcompiled in, always availableEssentiaoptional Python subprocessDiscogsvia broker APIBeatportHTML/JSON extractionBPMKeyRhythm RegularityDanceabilitySpectral CentroidLoudnessOnset RateDynamic ComplexityGenreStyleLabelYearCatalog #GenreSub-genreBPMKeyLabelGenre Classificationclassify_tracksaudio + provider evidenceSet & Pool Scoringbuild_set · expand_poolRekordbox + audio cachesMetadata Backfillbackfill_* toolsprovider metadata
Audio analysis from Stratum and Essentia supports classification and scoring. Discogs and Beatport metadata support classification and backfill, but set and pool scoring reads Rekordbox metadata and audio caches instead.

Single-track lookups cover Discogs, Beatport, MusicBrainz, and Bandcamp. Results are cached — subsequent calls return instantly unless force_refresh is set.

The batch surfaces are deliberately narrower:

  • CLI hydrate runs Discogs, Beatport, and audio analysis.
  • MCP enrich_tracks runs Discogs, Beatport, and Bandcamp.
  • MusicBrainz is an individual lookup and targeted backfill source; it is not an enrich_tracks batch provider.

Match one specific track or release on Discogs. This is not a general catalog, credits, collaborator, or release-discovery browser.

Parameter Type Required Description
track_id string Track ID — auto-fills artist/title/album from library
artist string Artist name (required if no track_id)
title string Track title (required if no track_id)
album string Album/release title for more accurate matching
force_refresh boolean Bypass cache (default: false)
Returned field Meaning
title, year, label Matched release identity and basic metadata
genres, styles Discogs genre and style arrays
url, cover_image Matched release and artwork URLs
fuzzy_match Whether the selected result was a fuzzy rather than exact title match

Match one specific track on Beatport. The result contains one genre value, not a separate sub-genre.

Parameter Type Required Description
track_id string Track ID — auto-fills artist/title from library
artist string Artist name (required if no track_id)
title string Track title (required if no track_id)
force_refresh boolean Bypass cache (default: false)
Returned field Meaning
genre, bpm, key Beatport’s genre, tempo, and key for the matched track
track_name, artists Matched title and artist list
release_date, label Optional release date and label
fuzzy_match Whether the selected result was a fuzzy rather than exact title match

Look up a track on MusicBrainz for year/label data. Returns year from first-release-date and label from the best matching release. Results are cached.

Parameter Type Required Description
track_id string Track ID — auto-fills artist/title from library
artist string Artist name (required if no track_id)
title string Track title (required if no track_id)
force_refresh boolean Bypass cache (default: false)

Look up a track on Bandcamp for year/label/tags/cover data. Pass a direct Bandcamp /track/ or /album/ url when you already found the release page; this bypasses Bandcamp search and refreshes the artist/title cache entry. Album pages use the provided title to select the track from Bandcamp JSON-LD. Particularly effective for underground/independent electronic music.

Parameter Type Required Description
track_id string Track ID — auto-fills artist/title from library
artist string Artist name (required if no track_id)
title string Track title (required if no track_id)
url string Direct Bandcamp /track/ or /album/ URL; bypasses search
force_refresh boolean Bypass cache (default: false)

Batch enrich tracks via Discogs/Beatport/Bandcamp. Accepts shared search filters to scope which tracks to enrich.

Parameter Type Required Item values Description
track_ids string[] Specific track IDs (highest priority selector)
playlist_id string Enrich tracks in this playlist
max_tracks integer Max pending tracks to admit after cache checks (default: 50, max: 200)
offset integer Index into the stable underlying selector order (default: 0)
providers string[] ["discogs", "beatport", "bandcamp"] Providers (default: ["discogs"])
skip_cached boolean Skip already-cached tracks (default: true)
force_refresh boolean Bypass cache entirely (default: false)
concurrency integer Max concurrent enrichments (default: 4, max: 8)

With skip_cached=true, cached candidates do not consume max_tracks slots. Starting at offset, the server checks ordered candidates until it admits the requested pending work or reaches the end of the scope. A cached no-match is a completed search; cache errors remain pending.

Field Type Required Description
summary object yes Counts for the inspected continuation page, including fully cached candidates
failures array yes Retryable failures with track, provider, and stage context
page object yes Underlying-selector continuation metadata
Field Type Required Description
matched_tracks integer yes Total tracks in the logical selector at call time
start_offset integer yes Underlying selector index supplied by the caller
examined_tracks integer yes Candidates inspected from start_offset
selected_tracks integer yes Pending tracks admitted under max_tracks
fully_cached_skipped integer yes Complete candidates skipped without spending a work slot
next_offset integer | null yes Underlying index after the last examined candidate when more remain; null at the end
has_more boolean yes Whether an unexamined underlying candidate remains

summary.tracks_total is page.examined_tracks; provider totals and cached counts include fully cached candidates skipped before work admission. The response remains bounded because only selected pending work can produce failures or other per-track task output.

Continue from page.next_offset while page.has_more is true. Record failures while traversing, then retry those explicit track_ids separately. Offsets are stable only while the selector scope and library ordering are unchanged; after an import, deletion, or reorder, restart at zero. Keep providers, skip_cached, and force_refresh unchanged for the whole traversal; changing any of them changes which earlier candidates count as complete and also requires a restart at zero. max_tracks=0 reports the matched scope but intentionally returns a terminal no-op page, so use a positive cap for traversal.

The response summary reports cache persistence under summary.cache_writes:

Field Description
attempted Cache writes received by the single persistence writer
succeeded Writes acknowledged after the enrichment row was stored durably
failed Writes rejected because the cache store could not be opened or updated

summary.enriched and summary.skipped advance only after the matching positive or negative cache row is acknowledged as durable. A cache-write failure increments summary.failed, appears in failures with track and provider context, and is never also reported as enriched or skipped.


The two backends return separate evidence and are cached independently. Stratum is compiled in; Essentia is optional. Neither backend returns a field named energy: scoring derives energy from three Essentia fields when all are present, otherwise it uses a BPM proxy.

The tables below group every public field family. In a fresh analyzer result, optional detector values serialize as null when a detector cannot run or a beat grid is unavailable. Cache freshness rejects results from older schemas; the live analyze_track_audio response remains the field-level schema authority.

Stratum family Returned fields Notes
Tempo and key bpm, bpm_confidence, key, key_camelot, key_confidence, key_clarity Confidence and clarity are evidence, not guarantees that every downstream consumer uses them.
Grid provenance grid_stability, grid_source grid_source distinguishes a supplied Rekordbox grid from the HMM fallback. The cache also records a versioned grid/no-grid input fingerprint.
Analysis metadata duration_seconds, processing_time_ms, analyzer_version, flags, warnings Cache freshness additionally requires the current Stratum schema version and current audio-file identity.
Modulation and decay mod_centroid, harmonic_proportion, decay_mid_tau, decay_mid_r2, decay_high_tau, decay_high_r2 Optional modulation-centroid, harmonic-proportion, and fitted decay evidence.
Dub-stab timing dub_stab_onset_count, dub_stab_onset_rate, dub_stab_rate_basis, dub_stab_histogram, dub_stab_template, dub_stab_template_score Optional onset, 32-bin histogram, rate-basis, and template evidence.
Kick pattern kick_pattern, kick_pattern_confidence, kick_kicks_per_bar, kick_onset_count, kick_rate_basis, kick_histogram Optional pattern label, confidence, counts, basis, and flattened 4×16 histogram.
Structure sections Optional ordered Intro/MainGroove/Breakdown/Outro sections with start/end time, kick-band RMS, and broadband RMS.
Essentia family Returned fields Notes
Analysis metadata analyzer_version Cache freshness also requires the current Essentia schema version and audio-file identity; grid changes do not invalidate Essentia.
Dynamics and loudness danceability, loudness_integrated, loudness_range, dynamic_complexity, average_loudness Optional descriptors. There is no returned energy field.
Tempo and rhythm bpm_essentia, onset_rate, rhythm_regularity Optional independent tempo and onset evidence.
Brightness, dissonance, and intensity spectral_centroid_mean, dissonance_mean, intensity_mean, intensity_var Optional scalar spectral/timbral evidence.
Detailed timbre and spectrum mfcc_mean, mfcc_std, spectral_centroid_cv, spectral_flux_mean, spectral_flux_iqr, spectral_contrast_mean Optional vectors and summary statistics used selectively by calibration and pool scoring.

Returned evidence is broader than the current scoring inputs. In particular, dub-stab, modulation/harmonic, structure, and most kick-pattern fields are available for inspection but do not directly alter transition or pool scores.

Consumer Current audio inputs
Genre classification/audit rule-based summary (classify.rs::AudioProfile) Rekordbox/Stratum BPM agreement; detector-consensus fallback is considered only when finite Essentia danceability is at least 1.5 (the Dancefloor or HighEnergy buckets). In that case, when the Stratum and Essentia BPM detectors agree with each other but disagree with Rekordbox (and are not a near double-time match), their mean replaces the Rekordbox BPM. Lower or missing danceability retains the Rekordbox BPM. Other inputs are Stratum duration, key_confidence, and decay_mid_tau; plus Essentia danceability, dynamic complexity, rhythm regularity, spectral centroid mean, and loudness_range. Extracted kick evidence is returned for review but is not a direct current decision input.
Calibrated genre-affinity profiles (audio_profile.rs), calibration, and affinity scoring Rekordbox BPM; Stratum decay_mid_tau, decay_high_tau, and key clarity; Essentia danceability, onset rate, rhythm regularity, centroid mean/CV, dynamic complexity, integrated loudness, spectral flux mean, dissonance mean, MFCC mean/std, and spectral contrast mean. Missing optional families reduce coverage rather than becoming zeroes.
Transition scoring and build_set Stratum key (preferred) and BPM (fallback); derived energy; Essentia brightness, rhythm regularity, and loudness range. Only build_set adds sequence-context modifiers.
Pool scoring and discovery Key, BPM, derived energy, canonical genre/family, Essentia brightness, and rhythm regularity. When every required timbral family is available, an optional distance axis uses MFCC mean/std, spectral contrast mean, spectral centroid variability, and dissonance. Pool scoring does not consume loudness_range.
Cache/audit coverage Analyzer freshness and presence counts; coverage does not imply that every returned field is consumed.

Derived energy is calculated only when Essentia has danceability, loudness_integrated, and onset_rate: the normalized inputs are weighted 0.4/0.3/0.3 and clamped to 0–1. If any one is missing—or Essentia is unavailable—the entire value falls back to the BPM proxy; it is not a partial Essentia score.


Analyze one track. Returns the Stratum evidence families above. The response always includes an essentia key plus essentia_available, essentia_cache_hit, and essentia_error context. essentia contains the separate result when analysis succeeds and is null when Essentia is unavailable or its analysis fails; optional fields inside a fresh result also serialize as null when unavailable.

Parameter Type Required Description
track_id string yes Track ID
skip_cached boolean Skip if already cached (default: true)

Cached analysis is validated against the analysis schema plus the canonical audio file identity (path, size, and modification time). Stratum additionally fingerprints the Rekordbox beat grid used for analysis, or a versioned no-grid fallback. A grid change invalidates and recomputes the Stratum result while leaving the Essentia result fresh.


Batch audio analysis. Accepts shared search filters to scope which tracks to analyze.

Parameter Type Required Description
track_ids string[] Specific track IDs (highest priority selector)
playlist_id string Analyze tracks in this playlist
max_tracks integer Max pending tracks to admit after freshness checks (default: 20, max: 200)
offset integer Index into the stable underlying selector order (default: 0)
skip_cached boolean Skip already-cached tracks (default: true)
concurrency integer Max concurrent analyses (default: cpus - 2, min: 1, max: 4)

Current Stratum results are skipped before work slots are assigned. When Essentia is available, a track is complete only when both current analyzer results exist; when it is unavailable, missing Essentia does not keep the track pending.

Field Type Required Description
summary object yes Counts for the inspected continuation page, including fully current candidates
results object[] yes Per-track analysis results
failures array yes Retryable failures with track, analyzer, and stage context
page object yes Underlying-selector continuation metadata
essentia_setup_hint string Setup guidance when Essentia is unavailable
Field Type Required Description
matched_tracks integer yes Total tracks in the logical selector at call time
start_offset integer yes Underlying selector index supplied by the caller
examined_tracks integer yes Candidates inspected from start_offset
selected_tracks integer yes Pending tracks admitted under max_tracks
fully_cached_skipped integer yes Current candidates skipped without spending a work slot
next_offset integer | null yes Underlying index after the last examined candidate when more remain; null at the end
has_more boolean yes Whether an unexamined underlying candidate remains

summary.total is page.examined_tracks. Its Stratum cache count, and its Essentia cache count when Essentia is available, include fully current candidates skipped before work admission. results remains bounded to selected pending tracks.

Traverse next_offset while has_more, retain failures, and retry failed track_ids after the scope traversal. Restart at zero if the selector or library order changes. Keep Essentia availability unchanged during traversal; also keep skip_cached unchanged. If either changes, including Essentia being installed, removed, or newly detectable, restart at zero because earlier tracks may have changed completion state. A zero cap is an inspection-free terminal no-op.


setup_essentia no params

Section titled “setup_essentia ”

Install or validate Essentia in a local Python venv. Creates a venv at ~/.local/share/reklawdbox/essentia-venv/ if needed. Activation takes effect immediately — no server restart needed.