Ships the fresh-start schema cleanup: rebuilt explore catalog index pipeline (dump import, artifact fetch/build, incremental listen-count refresh), a new download subsystem (Lidarr/Prowlarr/qBittorrent/SABnzbd/ slskd/yt-dlp providers, staging, reconciliation, wanted list), and the supporting schema/query/store changes across backend and frontend. Also includes two smaller follow-ups: bump the central index's rebuild-after cadence from 90 to 180 days, and remove the Explore "library only" online/offline toggle entirely (frontend-only, no backend counterpart) rather than carry unused UI/state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2Agd9af5hE7qzti2ackiS
6.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project
YellowJacket is a cross-platform desktop music player built with Go (backend) and TypeScript/Lit (frontend), using the Wails framework to bridge them. It supports MP3, FLAC, OGG Vorbis, and WAV playback.
Planning
Active and historical plans live in .planning/:
.planning/NOTES.md— gotchas, deferred items, open architecture questions, the "we already considered and rejected" list..planning/plans/active/— work currently in progress (read first)..planning/plans/pending/— sequenced future work..planning/plans/completed/— one concise recap per shipped milestone.
Numbering is sequential and stable across status moves (a plan keeps its NNN- prefix as it migrates between pending → active → completed). Abandoned plans are deleted; paused work stays in pending/.
Commands
make dev # Hot-reload development (installs deps, generates code, cleans frontend)
make dev-debug # Same as dev but with YJ_LOG_LEVEL=debug
make build-dev # Debug build with symbols
make build-prod # Production build (stripped, UPX-compressed)
make generate # Run code generators (sqlc + templ via go generate)
make lint # golangci-lint v2 (strict), both build configurations
make test # All tests with race detector, both build configurations
make vulncheck # govulncheck for CVEs
make setup # Install go tools, frontend deps, git hooks (lefthook)
Running tests
All Go test commands require the -tags webkit2_41 build tag:
go test -tags webkit2_41 ./... # All tests
go test -tags webkit2_41 ./backend/player/ # Single package
go test -tags webkit2_41 -run TestName ./backend/player/ # Single test
The central index builder is behind a second tag and is not covered
by the command above — make test runs both passes, but a manual run
needs it spelled out:
go test -tags "webkit2_41 indexbuild" ./backend/explore/... ./cmd/...
Audio playback integration tests require YELLOWJACKET_INTEGRATION=1.
Architecture
Wails app lifecycle (main.go → backend/app.go): YellowJacketApp is the root struct bound to Wails. Its methods are callable from the frontend. Lifecycle hooks: OnStartup (init audio), OnDomReady (start library scan), OnBeforeClose (save window state), OnShutdown (persist player/queue state).
Backend packages (under backend/):
player— Audio playback via beep.BufferedStreamerprovides a ring buffer for smooth seeking.queue— Track queue with shuffle (Fisher-Yates), repeat modes, auto-advance, and session persistence.library— Concurrent library scanning, metadata extraction, cover art deduplication, incremental rescan.database— SQLite via pure-Go driver. Schema indatabase/sql/schemas/, queries indatabase/sql/queries/. sqlc generates Go code intodatabase/sql/sqlcgen/— never edit that directory by hand. There is no migration chain:applySchemacreates everything from the schema files on every open (all DDL isIF NOT EXISTS), and a database written by an older build is not supported. Changing the schema means editing the file insql/schemas/, not adding a step.metadata— Tag extraction (ID3v2, Vorbis Comments, FLAC).config— TOML-based settings. Settings page uses HTMX + templ for server-rendered HTML fragments.playlist/smartplaylist— Playlist CRUD and rule-based smart playlists.mediacontrols— MPRIS integration on Linux via D-Bus.system— OS-specific paths (XDG on Linux,%LOCALAPPDATA%on Windows).explore— Catalog search and browse overexplore_index. See below.profiling— pprof server on:6060, compiled out in non-dev builds via build tags (internal/dev/).
Explore catalog (backend/explore/): the searchable MusicBrainz/
ListenBrainz catalog in explore_index. Deriving it from the MetaBrainz
dumps means streaming ~89 GB from a server that caps a client near
2 MB/s — half a day, for a catalog identical for every user. So that
work happens once, centrally, and users download the result:
cmd/indexbuildbuilds the catalog from the dumps;cmd/indexexportcuts it down to a shippable core and stamps its provenance..gitea/workflows/index-artifact.ymlruns both and publishes the compressed artifact under a fixedlatestversion.- The app fetches and merges that artifact (
artifactfetch.go,artifactimport.go) — about a minute, versus a day. - Everything the app does not need is behind the
indexbuildbuild tag (dumpimport.go,dumpcounts.go,dumpcatalog.go,dumpproject.go,dumpparallel.go,indexpatch.go) so it is not linked into the binary.dumpbuild_stub.gois the app-side entry point;dumpshared.goholds what both sides use. - The app keeps popularity current with the daily incremental dumps
(
dumpincremental.go), and resolves artists outside the artifact's coverage lazily on first view.
Frontend (frontend/): Lit 3.2 web components + Web Awesome UI library + HTMX. State management via singleton reactive stores in src/store/. Wails bindings auto-generated in frontend/wailsjs/ — don't edit by hand.
Event-driven communication: Backend emits events via Wails runtime; frontend stores subscribe to them. Event names are constants in backend/events/.
Code Generation
Two generators run via go generate ./... (or make generate):
- sqlc — SQL → Go. Config at
backend/database/sqlc.yaml. Add queries inbackend/database/sql/queries/, get generated Go indatabase/sql/sqlcgen/. - templ —
.templfiles →*_templ.gofiles (same directory).
Pre-commit hooks verify generated code is fresh — always run make generate after changing .sql or .templ files.
Code Style
- Go: golangci-lint v2 with strict linters including
err113(static errors),nlreturn,wsl_v5(whitespace),godot(comment periods),sloglint,perfsprint. Imports grouped: stdlib → third-party →yellowjacket/...(enforced by gci). - TypeScript: Strict mode, no implicit any, no unused locals/parameters.
- Commits: Conventional commits format (enforced by commitlint in CI). Semantic release uses these for versioning.
Testing
Tests use database.NewTestDB(t) for in-memory SQLite, built by the same
applySchema production uses so the two cannot diverge. Test audio fixtures live in test_data/music_library_test/. Table-driven tests are the norm.
Git Workflow
Feature branches and PRs are the norm, but direct pushes to main are allowed. Pre-commit runs vet, lint, codegen check, and frontend typecheck in parallel. Pre-push runs the full test suite.