Skip to content

Genre Classification

Classify genres across a Rekordbox collection using cached enrichment and audio evidence.

Paste into your agent to start:

Classify genres for my ungenred tracks.

Constraints

  • Taxonomy is compiled. The alias map in genre.rs cannot be changed at runtime. If the user disagrees with a mapping, the agent works around it by using the user’s preferred genre directly.
  • No auto-tagging. Every genre change requires explicit human approval.
  • Cache-first. Classification runs from cached data. If cache is empty for a track, it is flagged as insufficient evidence — do not trigger enrichment mid-classification.
  • XML export only. No direct DB writes. All changes flow through update_trackspreview_changeswrite_xml.
  • Per-track reasoning is mandatory for low/insufficient confidence. Do not skip or batch-approve these tracks. Delegate to subagents if the volume is large.

Prerequisites

cache_coverage(has_genre=false)

All providers must be at 100% before proceeding. If not, hydrate first:

analyze_audio_batch(has_genre=false, skip_cached=true, max_tracks=200)
enrich_tracks(has_genre=false, skip_cached=true, providers=["discogs"], max_tracks=50)
enrich_tracks(has_genre=false, skip_cached=true, providers=["beatport"], max_tracks=50)

Repeat until all providers reach 100%. Report progress between batches.

All classify_tracks calls support max_tracks (default 50, max 200) and offset for pagination. Continue until all tracks are covered.

Steps

1. Normalize aliases

suggest_normalizations(stage_aliases=true)

This auto-stages all non-debatable alias mappings (e.g. Hip-HopHip Hop, DnBDrum & Bass) and returns grouped results showing each mapping and its track count.

Review the staged aliases. If any are debatable, unstage them with clear_changes(track_ids=[...]) and ask the user. Store overrides for Step 2.

Unknown genres (non-canonical, no alias mapping) will be classified in Step 2 using the has_unknown_genre filter.

2. Classify and get approval policy

Get the confidence distribution first using format="summary":

classify_tracks(max_tracks=200, format="summary", genre_overrides=[...])
classify_tracks(has_unknown_genre=true, max_tracks=200, format="summary", genre_overrides=[...])

The summary format returns genre-grouped counts with top artists per genre — no per-track data. Report the aggregate distribution:

"N tracks classified: X high, Y medium, Z low, W insufficient."

Present the confidence distribution and ask the user which tiers to auto-approve:

“Approve all high-confidence? Approve high and medium? Or review everything?”

Default recommendation: approve high, present medium as summary, full review for low/insufficient.

3. Stage approved tiers

Re-run classification with auto_stage to stage the approved tiers in one shot:

classify_tracks(max_tracks=200, format="summary", auto_stage=["high", "medium"], genre_overrides=[...])
classify_tracks(has_unknown_genre=true, max_tracks=200, format="summary", auto_stage=["high", "medium"], genre_overrides=[...])

The response includes a staging field with the staged count. No separate update_tracks call is needed.

For medium-confidence tracks that are NOT auto-approved, use format="compact" to get the per-track list for review:

classify_tracks(max_tracks=200, format="compact", genre_overrides=[...])
classify_tracks(has_unknown_genre=true, max_tracks=200, format="compact", genre_overrides=[...])

Present as a numbered list grouped by genre. Highlight which evidence sources agree vs disagree:

→ Techno (8):
#1 Cristi Cons — Bird In Space (Discogs: Techno, label: Cocoon → Techno, 124bpm)
#2 Polar Inertia — Black Sun remix (Discogs: Techno, 131bpm)
...

Ask: “Approve all, or reject/change specific numbers. Say ‘investigate #N’ for any you want more context on.”

For investigated tracks, use resolve_tracks_data to get full evidence, then check artist context via search_tracks.

Stage approved changes with update_tracks.

4. Review low and insufficient confidence

These tracks need per-track reasoning — do not batch-approve them. Use subagents to parallelize the work.

4.1 Get dispatch roster

Use format="dispatch" to get low/insufficient tracks grouped by artist:

classify_tracks(max_tracks=200, format="dispatch", genre_overrides=[...])
classify_tracks(has_unknown_genre=true, max_tracks=200, format="dispatch", genre_overrides=[...])

The dispatch format returns artists sorted by track count descending, with per-track evidence and flags included. Partition into subagent batches:

  • Artists with 10+ tracks → dedicated subagent
  • Remaining artists → batch into subagents of ~40–50 tracks

4.2 Dispatch review subagents

Launch as many subagents in parallel as possible. Each subagent receives:

  • A list of tracks from the dispatch roster (including evidence and flags)
  • The review prompt below

Review subagent prompt:

You are classifying genres for tracks in a Rekordbox library. For each track, produce a genre recommendation and stage it.

Evidence and flags are included with each track in the dispatch data. You do NOT need to call resolve_tracks_data.

Tools available:

  • get_genre_taxonomy() — canonical genre list and BPM ranges
  • search_tracks(artist="...", has_genre=true) — artist’s other genred tracks in the library (use when you need more context beyond the dispatch data)
  • get_track(track_id="...") — single track detail
  • update_tracks(changes=[...]) — stage genre changes

What the decision tree already considered: BPM range plausibility, Beatport/Discogs genre tags, label-genre mapping, audio energy profile, same-family depth resolution.

What you add: Artist reputation beyond this library, label/scene context, remix conventions (e.g. remixer known for a specific genre), title interpretation.

Workflow:

  1. Call get_genre_taxonomy() to load the canonical genre list — only recommend genres from this list
  2. Review the evidence and flags included with each track
  3. Check if the artist has other genred tracks in the library via search_tracks where useful
  4. Consider artist reputation, label identity, and track title
  5. Recommend a canonical genre with one-sentence reasoning
  6. After classifying all tracks, stage your recommendations via update_tracks

Output format:

#N Artist — Title
Evidence: [key signals from the evidence array]
Library: [artist's other genres, or "no other tracks"]
Recommend: GENRE — [why]

Tracks to classify: [track list here]

4.3 Verify staged results

Once all subagents have completed, verify the aggregate results:

preview_changes(format="summary")

Compare the staged track count against dispatch_stats.total_tracks from Step 4.1 (plus any tracks staged in Step 3). If the staged count is lower than expected, identify which artist batches may have failed and report them to the user.

Present the summary to the user. Report: "Review complete: N tracks staged across M genres."

Ask: “Any genres or artists you want to review before export?“

5. Export

preview_changes(format="summary")

Ask user: “Export these changes to XML?”

write_xml()

Report output path, then walk the user through the Rekordbox import:

  1. Add XML to Rekordbox — Open Preferences → Advanced → rekordbox xml → Imported Library → Browse → select the exported XML file.
  2. Open the XML view — In the sidebar, click the “Display rekordbox xml” icon. The imported tracks appear under “All Tracks”.
  3. Import into collection — Select all tracks (Cmd+A), right-click → Import To Collection. When prompted “Do you want to load information in the tag of the library being imported?”, click Yes (tick “Don’t ask me again” for bulk imports).