MUSIC ONTO DISK. FROM WHATEVER MODEL YOU HAPPEN TO BE RUNNING.
A command line that takes the songs and albums you name, or a playlist from TIDAL, Deezer, YouTube
Music or an export file, works out which tracks you already own, canonicalises the rest against MusicBrainz,
and fetches what is missing from Soulseek through the Nicotine+ client already running on your machine. Every
command prints one JSON object and returns in seconds; the slow part runs in the background and
flacli status says what to do next. Any agent that can run a command can drive it, a seven-billion
parameter model included. Nothing is queued until you have seen the count, the size and the users involved and
said yes. No telemetry, no hosted service, no account but the ones you already have.
Any agent with a shell tool. Small local models. Humans. The guide is one command away.
Fifteen coarse tools, one workflow step each. For MCP clients with a modest model.
Every fine-grained tool, fifty-five of them. For models that can plan a nine-step pipeline.
flacli get "Artist - Title" "Artist - Album (album)". Albums are expanded to their tracklist on MusicBrainz, what you own is skipped, the rest is matched and, at or above 0.85 confidence, queued. Naming the music is the yes.flacli sync playlist.csv, or a TIDAL, Deezer or YouTube Music link. Resolve, diff, match in a detached worker. Nothing downloaded.next field naming the command to run.approve and skip by track id.--yes only after the user has seen them. Then the transfers go to Nicotine+.Artist/Album/NN - Title on arrival. flacli tidy plans the rest of the library; --apply after your yes.WITHOUT YOUR YES
sudo pacman -S --needed nicotine+ uv # or your distro's packages git clone https://github.com/h-3303/flacli ~/src/flacli cd ~/src/flacli && ./install.sh flacli doctor # is Nicotine+ reachable? flacli config set music_dir ~/Music flacli guide # hand this to the agent
The script copies the bridge into Nicotine+'s plugin folder and installs flacli with
uv tool install. Then tick MCP Bridge in Nicotine+ → Preferences → Plugins. Settings live
in ~/.config/flacli/config.toml; environment variables override them, so an MCP client entry can
carry its own music folder. Any distro with Nicotine+ 3.3 or newer and uv works.
flacli get "A - T" ...named songs and albums; resolved, diffed, matched, queued; the request is the go-aheadflacli sync <file|url|id>import, MusicBrainz, library diff, then a background match;--yeswhen the user asked for everything confident up frontflacli status [id]every playlist, or one: job, counts, transfers; files finished tracks; says what is nextflacli review · approve · skipcandidates with confidence 0–1, quality, queue length and a why breakdownflacli queue <id> [--yes]totals without the flag; transfers only with itflacli m3u <id>the file, in order, and the list of what is still missingflacli tidy [--apply]the library put in order; a report and a plan first, writes only with the flagflacli mpd [update · playlist]the player's MPD: is it reachable and serving the same library; a scoped rescan; a playlist stored by name. Done for you after every tidy and M3Uflacli avatar missing · fill · seta picture for every artist in the player: one a tagger left behind, the Wikidata portrait with its licence, a MusicBrainz image, or Deezer's; saved beside the music asartist.jpg, where Flaclify finds itflacli cover missing · fill · seta cover for every album: one already in the folder or a track, the Cover Art Archive front, Deezer's, or iTunes'; saved ascover.jpg, embedded in every track that had none, written into the player's cache under the album's folderflacli wiki missing · fill · setthe empty bio and wiki panels in Flaclify / Euphonica: Wikipedia where an article exists, the agent's own prose from MusicBrainz facts for the rest, each attributed, kept as Markdown beside the music, which Flaclify reads before asking anyone onlineflacli search · download · downloadsthe bridge on its own: raw Soulseek search, a whole folder, the transfer listflacli service · config · doctorTIDAL and YouTube Music logins stored 0600 on your disk; settings; the health check that says what to fix
flacli guide prints about ninety lines: a quick reference, the two workflows, the rules, and how to
read the output. It is written for the smallest model that might plausibly follow it. Paste it into a system
prompt, an AGENTS.md, a CLAUDE.md, or hand the model a shell and tell it to run the
command first. The rules are few: never pass --yes without the user's yes in the same conversation,
never delete by hand, do not fight the Soulseek rate limit, prefer FLAC, do not echo tokens.
For MCP clients the repository has the configuration for Claude Code, Codex CLI, Gemini CLI, opencode, Goose, Claude Desktop, and local models through Ollama or llama.cpp. Keep small models on the simple server; the full one has too many near-identical tools for them to pick between.
$ flacli get "Boards of Canada - Geogaddi (album)"
{ "understood": [ { "album": "Geogaddi",
"release": "2002-02-18", "tracks": 23 } ],
"already_in_library": 0, "to_fetch": 23,
"job_id": 4, "note": "fetching 23 track(s)
in the background; run flacli status 1" }
$ flacli status 1
{ "job": { "status": "finished",
"queued": 23, "for_review": 0 },
"downloads": { "done": 23 },
"tidied": { "moved": 23, "moved_to":
[ "Boards of Canada/Geogaddi" ] },
"next": "all done: flacli m3u 1" }
The worker is a detached process with its pid in the job row. A later call can tell a live job from a dead one, and flacli cancel sends it a signal instead of hoping.
flacli files music; Flaclify, an MPD client, plays it. They meet
through MPD and through files beside the music, nothing else. A finished download is filed and MPD is asked
to rescan that one folder, so the album is in the library before the agent has finished its sentence.
flacli m3u writes the M3U8 and stores the same playlist in MPD by name, so it is in the
player's Playlists view with the tracks that exist and a list of the ones that do not. Bios, wikis and
artist pictures are artist.md, wiki.md and artist.jpg next to the
files; Flaclify reads them itself, before any online provider, and again whenever one changes, so the text
and the pictures no longer depend on anything being written into the player's own database.
MPD is found through $MPD_HOST, then the usual local sockets, then localhost:6600;
flacli config set mpd pins a socket or host, or turns it off. Over a local socket flacli reads
MPD's music directory and stays quiet when it is not the library it files into. An MPD that is not there is a
skipped field in the output, never a failure. The next steps, in the player rather than the
shell, are on the roadmap.
WHAT IT WILL NOT DO.
It will not queue a transfer before you have seen the totals and agreed, except when you named the music yourself. It will not raise the search rate limit, or suggest it. It will not touch the Spotify API: their terms forbid feeding platform data to a model, so the data export is the route. It will not delete a file the plan did not list, nor write a tag without a backup of the old one. It will not send anything anywhere but MusicBrainz, your own Nicotine+, and a streaming service you have connected yourself. It does not care which model is driving.
Tested against Nicotine+ 3.3.10, 3.3.11 and master. 201 tests: a headless Nicotine+ core in-process, fake Soulseek peers, all three MCP servers over stdio, the CLI end to end through a real detached worker, a synthetic library tidied, the service connectors on recorded fixtures. Nothing touches the network.
github.com/h-3303/flacli · llms.txt · a fork of claude-music · GPL-3.0-or-later