MuseFlow is an assistant for your music provider account, built with Python, FastAPI and Typer.
Its main goal is to help you discover new music by providing recommendations based on your listening history. MuseFlow fetches suggestions from various providers and curates them into new dedicated playlists. A key feature is that it prioritizes artists and tracks that are unknown to you, ensuring true discovery rather than replaying your favorites.
For now, only Spotify is supported.
To work with this project, you will need the following tools installed on your machine:
- Python: 3.13
- UV: 0.10.8
- Docker Compose: v2
- direnv: For automatic environment variable loading (install guide)
For the Spotify connector:
- Spotify Developer Account: You need a Spotify account and access to the Spotify Developer Dashboard.
- Spotify App: Create an app in the Spotify Developer Dashboard to get a
Client IDandClient Secret.
Follow these steps to set up the project locally:
-
Clone the repository:
git clone https://github.com/ychab/museflow cd museflow -
Install dependencies:
You can install dependencies and pre-commit hooks in one go using the Makefile:
make install
Alternatively, you can install them manually:
-
Install dependencies:
make install-deps # OR uv sync --all-groups -
Install pre-commit hooks:
make install-precommit # OR uv run pre-commit install
-
Before running the application, you need to configure the environment variables and your Spotify App.
-
Environment Variables:
Non-secret defaults are in
.envrcand loaded automatically bydirenvwhen you enter the project directory. You only need to supply secrets.# Copy the example secrets file and fill in your values cp .env.example .env # Allow direnv to load .envrc (one-time, per clone) direnv allow
Open
.envand fill in the required secrets:SPOTIFY_CLIENT_ID: Your Spotify App Client ID.SPOTIFY_CLIENT_SECRET: Your Spotify App Client Secret.GEMINI_API_KEY: Your Gemini API key.MUSEFLOW_SECRET_KEY: A secret key for the application (min 32 characters, generate withopenssl rand -hex 32).
Personal overrides (e.g. a non-standard
DATABASE_PORT) can also be added to.env— they take precedence over.envrcdefaults. -
Spotify App Configuration:
You must add the redirect URI to your Spotify App settings in the Developer Dashboard.
- Go to your app in the Spotify Developer Dashboard.
- Click on "Edit Settings".
- Under "Redirect URIs", add the callback URL.
- By default, the application uses:
http://127.0.0.1:8000/api/v1/spotify/callback - Ensure this matches the
SPOTIFY_CLIENT_REDIRECT_URIin your.envrc(default:http://127.0.0.1:8000/api/v1/spotify/callback).
You can run the application and the database using Docker Compose or the provided Makefile.
Using Makefile:
-
Start the whole stack (DB + App):
make up
-
Run the API server locally (with hot reload):
make run
Note: You need to have the database running (
make up-db).
Using Docker Compose directly:
docker compose up -dOnce the application is running and configured, here is the typical flow to go from zero to discovering new music:
# 1. Create a user account
uv run museflow users create --email user@example.com
# 2. Connect your Spotify account (requires the API server to be running)
uv run museflow spotify connect --email user@example.com
# 3. Import your full streaming history from Spotify's data export
uv run museflow tracks history --email user@example.com --directory ~/Downloads/MySpotifyData
# 4. (Optional) Rate tracks from your history to enrich the taste profile
uv run museflow rate history --email user@example.com --play
# 5. Build your personal taste profile with AI analysis
# If you rated tracks in step 4, add --rated-only to seed the profile exclusively from rated tracks
uv run museflow taste build --email user@example.com --name my-profile
# 6. Discover new music and generate a playlist
uv run museflow playlist discover --email user@example.comStep 5 is optional but enriches the recommendations. Steps 4 and 5 work best together — rating tracks before building gives the AI an explicit preference signal (confirmed likes and dislikes) on top of behavioral play-count data.
MuseFlow provides a Command Line Interface (CLI) to manage users and interact with Spotify.
To use the CLI, you can use the museflow command if installed in your environment, or run it via UV:
uv run museflow [COMMAND]--log-level,-l: Set the logging level (e.g., DEBUG, INFO, WARNING, ERROR).--log-handlers: Set the logging handlers.--version,-v: Show the application's version and exit.--help: Show help message.
Manage application users.
Create a user:
uv run museflow users create --email <email>You will be prompted to enter and confirm the password.
Update a user:
uv run museflow users update <user_id> --email <new_email> --password <new_password>Interact with Spotify data.
Connect a user to Spotify:
Initiates the OAuth flow. You need to open the URL in a browser and authorize the app.
Prerequisite: The FastAPI application must be running to handle the Spotify callback.
Ensure you have started the application (e.g., using make up) before running this command.
uv run museflow spotify connect --email <email>--timeout: Seconds to wait for authentication (default: 60.0).--poll-interval: Seconds between status checks (default: 2.0).
Import streaming history:
Imports a user's extended streaming history from the JSON files exported via a music provider's data export (Spotify by default). Parses all JSON files in the given directory, deduplicates track IDs, fetches unknown tracks from the provider, and upserts them into the database.
Prerequisite: Export your data from Spotify (Account → Privacy Settings → Request your data) and unzip the archive. Only the Streaming_History_Audio_*.json files are used.
uv run museflow tracks history --email <email> --directory <path/to/history/folder> [OPTIONS]History Options:
--directory: Path to the directory containing the streaming history JSON files (required).--provider: Music provider to import streaming history from (default:spotify).--min-duration-played: Minimum playback duration in seconds to count a track as played (default: 90).--batch-size: Number of tracks to fetch from the provider and upsert per batch, between 1 and 500 (default: 20).--purge/--no-purge: Purge all existing history tracks before importing (default: no purge).
Example: Import history, ignoring plays shorter than 30 seconds
uv run museflow tracks history --email user@example.com --directory ~/Downloads/MySpotifyData --min-duration-played 30On completion, a summary table is printed showing items read, items skipped, unique track IDs found, and tracks created.
Build and manage your personal taste profile using AI analysis of your library.
Analyzes your imported library tracks with Gemini AI to generate a master taste profile — including era breakdowns, personality archetype, and life-phase insights.
Prerequisite: You must have imported your streaming history first (via tracks history).
uv run museflow taste build --email <email> --name <name> [OPTIONS]Options:
--name: Profile name, unique per user (required).--track-limit: Maximum number of seed tracks used to build the profile (default: 3000, max: 20000).--batch-size: Number of tracks sent per profiler batch (default: 200, max: 1000).--profiler: The profiler to use (default:gemini).--resume/--no-resume: Resume from last checkpoint if a previous build was interrupted (default: no resume).--rated-only/--no-rated-only: Restrict seed tracks to only those you have explicitly rated (score 0–10). Useful once you have rated a significant portion of your library (default: no restriction — all tracks are used, rated ones annotated with their score).
Example: Build a taste profile for a user
uv run museflow taste build --email user@example.com --name my-profileOn completion, the command prints the number of tracks processed, the profiler model and logic version, the number of musical eras detected, the personality archetype, and any life-phase insights.
Lists all taste profiles for a user.
uv run museflow taste list --email <email>Displays a taste profile in detail.
uv run museflow taste view --email <email> --name <name> [OPTIONS]--name: Profile name (required).--format: Output format:json,python, orhtml(opens in browser) (default:json).
Exports a taste profile to a YAML file (for backup or transfer).
uv run museflow taste export --email <email> --name <name> --output <path>--name: Profile name (required).--output: Path to the output YAML file (required).
Imports a taste profile from a previously exported YAML file.
uv run museflow taste import --email <email> --input <path>--input: Path to the input YAML file (required).
Commands for generating and managing playlists.
Prerequisite: You must have built a taste profile first (via taste build).
Discovers new music guided by your AI taste profile and creates a new playlist. Uses your full taste profile to generate contextually-aware recommendations — factoring in era, mood, genre preferences, and a configurable focus strategy.
uv run museflow playlist discover --email <email> [OPTIONS]Options:
--advisor: The AI advisor to use (default:gemini).--provider: The music provider to use (default:spotify).--focus: The discovery focus strategy (default:expansion). Controls how the advisor interprets your taste profile to generate suggestions.--name: Taste profile name to use (defaults to the latest profile).--genre: Optional genre hint for the advisor (e.g."jazz").--mood: Optional mood hint for the advisor (e.g."melancholic").--custom-instructions: Optional freeform instructions passed to the advisor.--advisor-limit: Number of recommended tracks to request from the advisor per attempt (default:10, max:20).--reconciler-limit: Maximum search candidates per suggestion (default:10, max:20).--playlist-limit: Target number of tracks in the generated playlist (default:10, max:30).--max-attempts: Maximum number of advisor calls before stopping (default:3, max:10).--max-tracks-per-artist: Maximum tracks per artist in the final playlist (default:3, max:10).--dry-run: Discover tracks without creating a playlist.
Example: Discover new music guided by your taste profile
uv run museflow playlist discover --email user@example.com --focus expansion --playlist-limit 15Example: Discover jazz tracks with a melancholic mood
uv run museflow playlist discover --email user@example.com --genre jazz --mood melancholic --dry-runLists all discovery playlists for a user.
uv run museflow playlist list --email <email>Displays a discovery playlist with its tracks and their ratings.
uv run museflow playlist view <playlist_id> --email <email>Rate discovered tracks by score (0–10). Ratings influence future blacklisting prompts.
Single-track rating:
uv run museflow rate track <track_id> <score> --email <email>Interactive playlist rating (walks through every track in a discovery playlist):
uv run museflow rate playlist <playlist_id> --email <email>In interactive mode, for each low-scored track you are prompted to optionally blacklist the track and/or its artist.
Manage artists and tracks that should be excluded from future discovery playlists.
Add one or more artists to the blacklist:
uv run museflow blacklist add-artist <artist_name> [<artist_name> ...] --email <email>Add a track to the blacklist:
uv run museflow blacklist add-track <track_name> --artist <artist_name> --email <email>List your blacklist:
uv run museflow blacklist list --email <email>Remove entries by ID (IDs shown in blacklist list):
uv run museflow blacklist remove <id> [<id> ...] --email <email>Purge your entire blacklist:
uv run museflow blacklist purge --email <email> [--yes]--yes/-y: Skip the confirmation prompt.
Displays diagnostic information about a user's Spotify account.
uv run museflow spotify info --email <email> [OPTIONS]--token/--no-token: Display the current Spotify OAuth token (default: on).
Linting and Formatting:
make lintRunning Tests:
make testThis project is configured for Claude Code, Anthropic's AI coding assistant. The configuration lives in:
CLAUDE.md— project conventions and architecture rules loaded into every Claude sessionCONVENTIONS.md— detailed architecture reference (the source of truth).claude/commands/— custom slash commands (skills) for common development workflows.claude/agents/— autonomous subagents for specialized tasks
Skills are project-specific slash commands that encode the project's conventions so you don't have to repeat them. Invoke them in a Claude Code session with /command-name [arguments].
| Skill | Invocation | What it does |
|---|---|---|
/new-feature |
/new-feature <name> |
Scaffolds a full feature across all layers: entity → input schema → port → use case → SQLAlchemy model → repository → API endpoint → CLI command → unit and integration tests |
/new-migration |
/new-migration <description> |
Guides an Alembic migration: generates the file, reviews nullable defaults and downgrade(), verifies it runs cleanly |
/add-tests |
/add-tests <file_path> |
Analyzes a source file and generates unit + integration tests targeting 100% branch coverage, reusing existing fixtures and factories |
/new-provider |
/new-provider <name> |
Scaffolds a new music provider integration: client, session, library adapter, DTOs, mappers, schemas, types, exceptions, settings, WireMock stubs, and tests — mirroring the Spotify pattern |
/arch-review |
/arch-review [files] |
Reviews changed files for Clean Architecture violations: framework imports in domain, repositories instantiated in use cases, wrong JSONB/ARRAY dialect, missing to_entity(), logging secrets, etc. |
/security-review |
/security-review [files] |
Reviews changed files for security issues: hardcoded secrets, unprotected endpoints, unbounded Retry-After sleeps, raw SQL, missing input validation, path traversal, and runs uv audit for CVEs |
Agents are autonomous subagents that Claude routes to automatically or that you can trigger explicitly. They run as subprocesses with their own tools and specialized instructions.
| Agent | What it does |
|---|---|
python |
Fixes lint errors autonomously — runs make lint, fixes ruff/mypy/deptry issues, iterates until clean |
test |
Fixes failing tests and fills coverage gaps — runs make test, traces failures, writes missing branches |
arch |
Architecture compliance review — checks changed files against hexagonal architecture rules |
security |
Security review — checks changed files for vulnerabilities, runs uv audit for CVEs |
engineer |
Read-only codebase explorer — explains feature flows, locates code, guides implementation approach |