Skip to content

ychab/museflow

Repository files navigation

MuseFlow

Python CI codecov License: MIT

Ruff Checked with mypy uv pre-commit

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.

Requirements

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 ID and Client Secret.

Installation

Follow these steps to set up the project locally:

  1. Clone the repository:

    git clone https://github.com/ychab/museflow
    cd museflow
  2. 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

Configuration

Before running the application, you need to configure the environment variables and your Spotify App.

  1. Environment Variables:

    Non-secret defaults are in .envrc and loaded automatically by direnv when 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 .env and 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 with openssl rand -hex 32).

    Personal overrides (e.g. a non-standard DATABASE_PORT) can also be added to .env — they take precedence over .envrc defaults.

  2. 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_URI in your .envrc (default: http://127.0.0.1:8000/api/v1/spotify/callback).

Running the Application

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 -d

Getting Started

Once 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.com

Step 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.

CLI User Guide

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]

Global Options

  • --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.

User Management (users)

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>

Spotify Interaction (spotify)

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).

Manage Tracks (tracks)

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 30

On completion, a summary table is printed showing items read, items skipped, unique track IDs found, and tracks created.

Taste Profile (taste)

Build and manage your personal taste profile using AI analysis of your library.

taste build

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-profile

On 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.

taste list

Lists all taste profiles for a user.

uv run museflow taste list --email <email>

taste view

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, or html (opens in browser) (default: json).

taste export

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).

taste import

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).

Playlist (playlist)

Commands for generating and managing playlists.

Prerequisite: You must have built a taste profile first (via taste build).

playlist discover

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 15

Example: Discover jazz tracks with a melancholic mood

uv run museflow playlist discover --email user@example.com --genre jazz --mood melancholic --dry-run

playlist list

Lists all discovery playlists for a user.

uv run museflow playlist list --email <email>

playlist view

Displays a discovery playlist with its tracks and their ratings.

uv run museflow playlist view <playlist_id> --email <email>

Rate Tracks (rate)

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.

Blacklist (blacklist)

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.

Spotify Account Info (spotify info)

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).

Development

Linting and Formatting:

make lint

Running Tests:

make test

Claude Code

This 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 session
  • CONVENTIONS.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

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

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

About

MuseFlow helps you discover new music by offering recommendations based on your listening history.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages