A2 · Side A · Listening
haystack
Finds the needle.
Music discovery for one Spotify account, on an always-on Linux box. It learns your taste from the audio itself, scouts new tracks by how they sound, and puts the best in a weekly Discoveries playlist.
What it does
haystack learns your taste from how your music sounds, not from its tags. It runs every track in your library, and every song you've liked on Spotify, through Essentia's Discogs-EffNet model, in about nine 30-second windows each.
Each morning it gathers candidates from Deezer and ListenBrainz and does the same with their 30-second previews. A candidate scores by its closest match among the music you like, less a penalty for sounding like what you've turned down.
On Monday mornings the best go into a private Discoveries playlist: 15 by default, though the batch size is yours to set in its config. It takes one per artist, with about a fifth of them spent exploring. What you do next teaches it: your likes on Spotify and your Verdicts in needle. A discovery still unliked when the next batch comes counts as a no, and a liked one that isn't in your library goes on a To Rip playlist.
Its week
- Daily, 03:15
- library Scans your music and embeds what's new or changed.
- Daily, 05:00
- harvest Gathers and embeds candidates, then scores them again.
- Hourly
- sync Reads your plays and likes, settles outcomes and updates the playlists.
- Mondays, 08:00
- batch Clears Discoveries, then adds the new batch.
- Always on
- api needle's API, and the Spotify writes after each Verdict.
How it works
Python, with Essentia for the audio and SQLite for the rest. It runs in a Docker container, where one process serves needle's API and starts each job on the schedule in its config. Or, without Docker, as systemd user units under linger. Either way it carries on with nobody logged in, and the timed jobs run at the lowest CPU priority.
Your library is read-only to it: files are opened read-only and tags are only ever read. Previews stay in memory, piped into ffmpeg and never written to disk, and Deezer gets at most one request every 1.1 seconds.
It has no screen of its own. needle is where you hear each batch and judge it, and haystack makes every Spotify write.
Credits
- Runs on
- An always-on Linux server or VPS, for one Spotify account. needle is its screen.
- Install
- The Docker image on GitHub (linux/amd64), with Docker Compose. Or from source with pip, under systemd user units.
- Built with
- Python, Essentia, ffmpeg and SQLite
- Latest
- 0.9.0, 23 October 2026
- Licence
- AGPL-3.0-or-later
- Models
- Essentia's Discogs-EffNet and MusiCNN models, by the Music Technology Group at Universitat Pompeu Fabra, under CC BY-NC. haystack downloads them at setup and never ships them, and using them commercially needs a licence from the MTG.
- Libraries
- Essentia (AGPL-3.0, with TensorFlow under Apache-2.0), numpy (BSD-3-Clause), requests (Apache-2.0) and mutagen (GPL-2.0-or-later), installed by pip. ffmpeg (LGPL or GPL, by build) decodes the audio.
- Services
- Deezer's public API for candidates and previews, for private, non-commercial use under its terms. ListenBrainz, by the MetaBrainz Foundation, for similar recordings. The Spotify Web API, through your own Spotify app. haystack is not affiliated with, or endorsed by, any of them.
- Source
- kurtlieber/haystack on GitHub. Its NOTICE lists every licence.