Every parser in `backend/metadata` is header-only -- a few hundred bytes and return -- so on a spinning disk a scan is not waiting on CPU or on bytes, it is waiting on the head to arrive. Two things follow, and the drive says which. **How many reads should be in flight.** This was a flat 2 for anything rotational, which is a pre-NCQ assumption: a modern SATA disk reports a queue depth of 32 and reorders outstanding reads into the order its head passes over them, and was being handed a quarter of what it can use. It gets 4 now. A drive that reports 1 -- a USB bridge, a pre-2004 disk -- services one command at a time in the order given, where every extra worker is one more seek competing for one head and the scan gets *slower* the harder it is pushed; that keeps 2. **And that the next seek should already be queued.** A prefetch stage between the walk and the workers issues `POSIX_FADV_WILLNEED` over the first 512 KB of each file -- enough for an ID3v2 tag carrying cover art, or FLAC's STREAMINFO and PICTURE blocks. The buffered channel *is* the lookahead: the goroutine runs 16 files ahead of the workers, hinting as it goes, so the read a worker needs has been in flight for sixteen files' worth of parsing by the time it asks. Rotational only; an SSD gets the channel back unwrapped and pays nothing, since it has no seek to hide and already has one worker per core. `workersForProfile` is the policy on its own so it can be tested against drives this machine does not have, and the scan logs the device, its rotational flag and its queue depth, so the decision is inspectable rather than inferred. Also: `ScanConcurrency` has been a validated three-value config field with exactly one caller, passing the constant `auto` -- so choosing `ssd` or `hdd` by hand did nothing at all. It reads the config now. The two modes overrule detection about the *disk* and not about its queue, since a user who picks `hdd` on a queueing drive still wants that drive's queue used. What is not here is inode-ordered dispatch. It needs the streaming walk restructured to buffer per directory, and with queueing the drive is already reordering what the hints put in front of it; that wants a measurement on real hardware before the complexity. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MeQt5hgXg5YGoNZQ9ozG7L
YellowJacket
Music how it was meant to bee.
YellowJacket is a fast, cross-platform desktop music player for your local collection. It plays your files, keeps your library tidy, and helps you discover and organize your music — all in a clean, responsive interface. No accounts, no streaming, no telemetry: just your music on your machine.
Runs on Linux, macOS, and Windows.
Features
Play your music
- Plays MP3, FLAC, OGG Vorbis, and WAV
- Play, pause, seek, and volume control with a mute toggle
- Gapless, glitch-free seeking backed by a read-ahead buffer
- A queue you can add to, reorder, and shuffle, with play-next support
- Shuffle and repeat (off / all / one)
- Picks up right where you left off — remembers your track, position, and volume between sessions
- Media-key and MPRIS support on Linux, so your desktop's playback controls just work
Keep your library organized
- Point it at your music folders and it scans them automatically
- Reads tags and embedded cover art, and de-duplicates artwork so it isn't stored twice
- Incremental sync — only new or changed files get reprocessed, and deleted files are cleaned up
- Browse by album, artist, or genre, or search across everything
- Mark favorites and see what you've been listening to with play history
- Edit track tags directly when something's off
Playlists
- Create playlists, drag tracks in, and reorder them
- Smart playlists that build themselves from rules (by genre, rating, play count, and more)
- Pin a default playlist and spot duplicate tracks at a glance
Discover and clean up (powered by MusicBrainz)
- Explore — browse artists, releases, and genres from the MusicBrainz catalog, not just what's already in your library
- Auto-tag — match your files against MusicBrainz to fill in correct artist, album, and track metadata, with a review step before anything is written
- Lyrics search — find a track by a line you remember
Install
Download the latest build for your platform from the releases page.
| Platform | Download |
|---|---|
| Linux | yellowjacket-linux-amd64 |
| macOS | yellowjacket-darwin-universal.app.zip (Apple Silicon + Intel) |
| Windows | yellowjacket-windows-amd64.exe |
Prefer to build it yourself? See Building from source.
Getting started
- Launch YellowJacket.
- Open Settings and add the folder(s) where your music lives.
- Let the initial scan finish — you'll see progress as it works.
- Browse by album, artist, or genre, queue something up, and press play.
Your library and settings are stored locally:
| Linux / macOS | Windows | |
|---|---|---|
| Config | ~/.config/yellowjacket/ |
%LOCALAPPDATA%\yellowjacket\config |
| Library data | ~/.local/share/yellowjacket/ |
%LOCALAPPDATA%\yellowjacket\data |
Building from source
YellowJacket is built with Go and a Lit/TypeScript frontend, bridged by the Wails framework.
Prerequisites
| Tool | Version |
|---|---|
| Go | 1.25+ |
| Node.js | 22+ |
| pnpm | 10+ |
| Wails CLI | v3 — vendored, no install needed (go tool wails3) |
The Wails v3 CLI resolves from the tool block in go.mod, so there is nothing
to install globally; make setup fetches it with the rest of the tooling.
On Linux, install the system libraries Wails needs. v3 builds against GTK4 + WebKitGTK 6.0 by default:
sudo apt-get install libasound2-dev libgtk-4-dev libwebkitgtk-6.0-dev # Debian/Ubuntu
sudo pacman -S alsa-lib gtk4 webkitgtk-6.0 # Arch
A machine without webkitgtk-6.0 can still build with -tags gtk3 against the
older WebKit2GTK 4.1 stack, but that is an escape hatch, not what CI or a
release builds.
macOS and Windows need no extra system packages. Run go tool wails3 doctor to
check your environment.
Build
make setup # install tooling and git hooks
make dev # run with hot-reload
make build-prod # produce a release binary
More detail for contributors lives in
docs/dev/overview.md and CLAUDE.md.