AP

approach-note-release-validator

Validate the integrity of database releases in ApproachNote.

Install

mkdir -p .claude/skills/approach-note-release-validator && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16300" && unzip -o skill.zip -d .claude/skills/approach-note-release-validator && rm skill.zip

Installs to .claude/skills/approach-note-release-validator

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Validate that a release in the ApproachNote production database is well-formed — check referential integrity, presence of MusicBrainz match, cover imagery, streaming links, track listings, and artist links. Use whenever the user asks to validate, audit, sanity-check, or "look at" a specific ApproachNote release. Triggers on inputs that include an ApproachNote release UUID, a MusicBrainz release ID (MBID), or a song name (in which case run an interactive disambiguation to land on a specific release first). Use this skill even when the user just asks "is this release OK?" / "does this look right?" / "audit release X" with a release-like identifier — don't wait for the word "validate.
690 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Beginner

Key capabilities

  • Validate referential integrity of a release
  • Check for MusicBrainz match presence
  • Verify cover imagery and streaming links
  • Audit track listings and artist links
  • Generate a human-readable report of findings

How it works

The skill connects to the ApproachNote Postgres database in read-only mode. It resolves the input identifier to a single release ID and then performs various validation checks against the release's data.

Inputs & outputs

You give it
ApproachNote release UUID, MusicBrainz release ID (MBID), or a song name
You get back
A human-readable report indicating passes, warnings, and failures for the release

When to use approach-note-release-validator

  • Validate release data
  • Audit database records
  • Sanity check release metadata

About this skill

ApproachNote Release Validator

Confirm that a single release row in the ApproachNote Postgres database has all expected relationships, references, and metadata populated.

This is a read-only audit. No writes, no calls to MusicBrainz or any other external service. The output is a human-readable report of what passed, what warned, and what failed.


When this skill applies

Trigger when the user wants to inspect a specific release. Inputs come in three flavors:

  1. ApproachNote release UUID — a 36-char UUID that exists in releases.id.
  2. MusicBrainz release ID (MBID) — looks like a 36-char UUID; the user usually labels it as MB or pastes a musicbrainz.org/release/... URL.
  3. Song name (with optional artist / album hints) — requires an interactive disambiguation to pick one release.

If the user gives no identifier at all, ask for one before doing anything.


Setup

Run from ApproachNote/backend/ so .env and db_utils.py are on the path. The skill uses simple (non-pooled) connection mode — make sure DB_USE_POOLING is unset or false.

Sanity check before the first query:

import os
os.environ.setdefault("DB_USE_POOLING", "false")
from db_utils import test_connection, execute_query, find_song_by_name
test_connection()

If test_connection() fails, stop and surface the error to the user — don't try to soldier on with broken credentials.


Resolving the input to a single release

The goal of this stage is one releases.id UUID. Confirm with the user before validating, especially in case C.

Case A — ApproachNote release UUID

Fetch the row directly. Echo back title, artist_credit, year so the user can sanity-check we're looking at the right thing.

SELECT id, title, artist_credit, release_year, musicbrainz_release_id
FROM releases
WHERE id = %s;

If not found, tell the user — likely a typo or a deleted row.

Case B — MusicBrainz release ID (MBID)

SELECT id, title, artist_credit, release_year, musicbrainz_release_id
FROM releases
WHERE musicbrainz_release_id = %s;

If not found: the release just isn't in ApproachNote yet. Don't try to fetch from MusicBrainz — that's out of scope.

Case C — Song name (turn-by-turn disambiguation)

Walk the user one step at a time. Don't dump all candidates at once. Each step is one question, then wait.

Step 1: Find the song.

song = find_song_by_name(user_input)  # handles case + accent normalization

If None, tell the user. If multiple songs share the title (rare — usually only happens with alt_titles), list them with composer + year and ask which.

Step 2: List candidate artists.

Show the top 20 distinct artist_credit values across all releases that contain a recording of this song, ranked by release count so popular candidates float up:

SELECT rel.artist_credit, COUNT(DISTINCT rel.id) AS release_count
FROM songs s
JOIN recordings r          ON r.song_id = s.id
JOIN recording_releases rr ON rr.recording_id = r.id
JOIN releases rel          ON rel.id = rr.release_id
WHERE s.id = %s
GROUP BY rel.artist_credit
ORDER BY release_count DESC, rel.artist_credit
LIMIT 20;

Present the list and ask which artist. Phrase the question so the user knows they can name an artist that isn't in the top 20 (e.g., "Which artist? Or name one not listed."). Match the user's answer with ILIKE '%...%' against releases.artist_credit — the match doesn't need to come from the displayed list.

Step 3: List candidate releases for that song + artist.

SELECT rel.id, rel.title, rel.release_year, rel.label
FROM songs s
JOIN recordings r          ON r.song_id = s.id
JOIN recording_releases rr ON rr.recording_id = r.id
JOIN releases rel          ON rel.id = rr.release_id
WHERE s.id = %s AND rel.artist_credit ILIKE %s
ORDER BY rel.release_year NULLS LAST, rel.title;

If exactly one — confirm and proceed. If multiple — show title + year + label, ask which. If zero — back up and let the user re-pick the artist.

Step 4: Resolve to one releases.id and validate.

If the candidate set is ever empty, stop and tell the user where it broke down.


Validation checks

Run all of these against the resolved release and collect findings as (severity, category, message). Severities: FAIL (✗), WARN (⚠), PASS (✓ — usually omitted from output unless the user asked for the full breakdown).

Core release row

  • title is non-empty (not just whitespace).
  • artist_credit is set.
  • musicbrainz_release_id is set and matches the 36-char UUID shape.
  • musicbrainz_release_group_id is set.
  • release_year is set (or release_date).
  • format_id and status_id are set.

Track listing

  • total_tracks is declared (non-null, > 0).
  • Count of recording_releases rows for this release equals total_tracks (WARN if mismatched, with both numbers).
  • No null track_number in any junction row.
  • No duplicate (disc_number, track_number) within the release.
  • Track numbers are contiguous from 1 per disc (WARN on gaps, e.g. 1,2,4).
  • total_discs matches the count of distinct disc_number values in the junction.

Recordings linked to this release

For every recording reachable via recording_releases:

  • Recording has a musicbrainz_id (WARN if missing).
  • song_id row exists in songs (referential integrity).
  • Recording has at least one recording_performers row (WARN if zero).
  • Recording has recording_year or recording_date (WARN if both null).

Aggregate WARNs across tracks rather than emitting one per track ("3 of 7 tracks have no MB recording ID").

Imagery

  • At least one release_imagery row with type = 'Front' (FAIL if missing).
  • At least one with type = 'Back' (WARN if missing — optional but nice).
  • If no imagery at all, cover_art_checked_at should be set (so we know we tried). FAIL if both: no imagery AND cover_art_checked_at IS NULL.

Streaming

  • At least one release_streaming_links row, album-level (WARN if none).
  • For each recording_releases, at least one recording_release_streaming_links row (track-level). Aggregate: "N of M tracks missing track-level streaming link."

Metadata

  • At least one release_events row (release date with country) — WARN if missing.
  • At least one release_labels row — WARN if missing (the releases.label field can serve as fallback).

This is a starter set. Well-formedness criteria are still being defined and will be tuned as the skill is used. When the user wants to add or change a check, edit this section directly.


Output format

Lead with a one-line identification so the user can confirm we hit the right release:

Release: "{title}" — {artist_credit} ({release_year})
  AN ID: {releases.id}
  MB ID: {musicbrainz_release_id or "—"}

Then either the all-clear:

The release appears well-formed.

…optionally followed by a one-line-per-category summary of what was checked, so "well-formed" is concrete.

…or a grouped list of issues, sorted FAILs before WARNs:

✗ No Front cover imagery (and cover_art_checked_at is null)
✗ release_labels has zero entries
⚠ 3 of 7 tracks missing track-level Spotify link
⚠ musicbrainz_release_group_id not set

Keep the tone factual and scan-friendly — the user will likely either fix issues by hand or queue them for a backfill, so the report should read fast. Don't editorialize ("this is bad!"); just report.


Schema cheat-sheet (release-relevant tables)

Full schema: ApproachNote/sql/jazz-db-schema.sql. Most-used columns for this skill:

TableKey columns
releasesid, musicbrainz_release_id, musicbrainz_release_group_id, title, artist_credit, release_date, release_year, country, label, catalog_number, barcode, format_id, packaging_id, status_id, total_tracks, total_discs, cover_art_checked_at
recording_releasesid, recording_id, release_id, disc_number, track_number, track_position, track_title, track_length_ms — UNIQUE on (recording_id, release_id)
recordingsid, song_id, title, recording_date, recording_year, musicbrainz_id, default_release_id, duration_ms
release_imageryrelease_id, source (enum: MusicBrainz/Spotify/Wikipedia/Apple/Amazon), type (enum: Front/Back), image_url_small/medium/large
release_streaming_linksrelease_id, service (spotify/apple_music/youtube/…), service_id, service_url
recording_release_streaming_linksrecording_release_id, service, service_id, isrc, match_confidence, match_method
release_eventsrelease_id, country, release_date
release_labelsrelease_id, label_name, catalog_number, musicbrainz_label_id
release_performersrelease_id, performer_id, instrument_id, role
songsid, title, composer, musicbrainz_id, alt_titles
performersid, name, sort_name, musicbrainz_id
recording_performersrecording_id, performer_id, instrument_id, role

For anything else, read the relevant section of ApproachNote/sql/jazz-db-schema.sql directly.


Helpers worth knowing about in db_utils.py

  • execute_query(query, params=None, fetch_one=False, fetch_all=True) — main read path; returns dict_row results.
  • execute_update(...) — exists, but don't use it in this skill. This skill is read-only.
  • find_song_by_name(title) — case + accent + apostrophe normalized lookup. Use this for Case C step 1, don't roll your own LOWER(title) =.
  • find_performer_by_name(name) — similar, useful if the user gives a performer name.
  • test_connection() — quick sanity check; returns bool.

When not to use it

  • When the user wants to fetch data from MusicBrainz
  • When the user wants to modify database records
  • When no specific release identifier is provided

Limitations

  • This is a read-only audit; no writes are performed.
  • It does not call MusicBrainz or any other external service.
  • It cannot fetch releases not already in ApproachNote.

How it compares

This skill performs a read-only audit of a single database release, providing a structured report of its integrity and metadata, unlike manually querying the database for individual fields.

Compared to similar skills

approach-note-release-validator side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
approach-note-release-validator (this skill)03moReviewBeginner
sql-queries185moNo flagsIntermediate
snowflake-semanticview57moReviewAdvanced
fuzzy-matching86moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

sql-queries

anthropics

Write correct, performant SQL across all major data warehouse dialects (Snowflake, BigQuery, Databricks, PostgreSQL, etc.). Use when writing queries, optimizing slow SQL, translating between dialects, or building complex analytical queries with CTEs, window functions, or aggregations.

1888

snowflake-semanticview

github

Create, alter, and validate Snowflake semantic views using Snowflake CLI (snow). Use when asked to build or troubleshoot semantic views/semantic layer definitions with CREATE/ALTER SEMANTIC VIEW, to validate semantic-view DDL against Snowflake via CLI, or to guide Snowflake CLI installation and connection setup.

542

fuzzy-matching

dadbodgeoff

Multi-stage fuzzy matching pipeline for entity reconciliation. PostgreSQL trigram pre-filter, salient overlap check, and multi-factor similarity scoring.

825

sql-pro

sickn33

Master modern SQL with cloud-native databases, OLTP/OLAP optimization, and advanced query techniques. Expert in performance tuning, data modeling, and hybrid analytical systems. Use PROACTIVELY for database optimization or complex analysis.

323

postgres-hybrid-text-search

timescale

Use this skill to implement hybrid search combining BM25 keyword search with semantic vector search using Reciprocal Rank Fusion (RRF). **Trigger when user asks to:** - Combine keyword and semantic search - Implement hybrid search or multi-modal retrieval - Use BM25/pg_textsearch with pgvector together - Implement RRF (Reciprocal Rank Fusion) for search - Build search that handles both exact terms and meaning **Keywords:** hybrid search, BM25, pg_textsearch, RRF, reciprocal rank fusion, keyword search, full-text search, reranking, cross-encoder Covers: pg_textsearch BM25 index setup, parallel query patterns, client-side RRF fusion (Python/TypeScript), weighting strategies, and optional ML reranking.

112

whodb

clidey

Database operations including querying, schema exploration, and data analysis. Activates for tasks involving PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, Redis, Elasticsearch, or ClickHouse databases.

18

Search skills

Search the agent skills registry