A local, collaborative music player (main-branch-only mirror of forge.ejuarezg.com/ejuarezg/jam-session)
jam-session AGENTS.md
7.4 kB
Markdown
at main

Project #

Jam Session

A locally-hosted web application for collaborative music queuing at gatherings. People connected to the home network can add YouTube songs to a shared queue, vote on what plays next, and skip songs democratically — all without accounts or logins, using ephemeral nicknames valid for the session. The host machine plays the music through mpv + yt-dlp (ad-free), and playback survives server restarts because mpv runs as a separate process.

Core Value: The music keeps playing no matter what — server crashes, disconnects, browser restarts, nothing should interrupt audio playback on the host machine.

Constraints #

  • Tech stack: Backend must run on Linux (host machine), control mpv via IPC, and serve a web UI
  • Network: LAN-only, no WAN exposure required
  • Music source: YouTube only for v1, with adapter pattern for future sources
  • Auth: None — ephemeral nicknames tied to session
  • Playback: mpv + yt-dlp for audio-only, ad-free YouTube playback
  • Resilience: mpv as separate process, web server must handle reconnection and state resync

Technology Stack #

Core Technologies #

Technology Version Purpose Why Recommended
Python 3.12+ Backend language yt-dlp is a Python package — direct integration. Unix socket IPC, process management, and async I/O are all mature in Python.
FastAPI 0.115+ Web framework Built-in WebSocket support, async-first, automatic OpenAPI docs, lightweight. Pydantic models for request/response validation.
uvicorn 0.34+ ASGI server Production-grade async server for FastAPI with autoreload for development.
yt-dlp 2025.5+ YouTube URL resolution Python package. Extract audio stream URLs, metadata (title, duration, thumbnail). Ad-free by nature — resolves direct stream URLs, no browser embeds.
mpv 0.39+ Audio playback engine Runs as independent process, JSON IPC over Unix socket for control. Survives server restarts. --vid=no for audio-only mode.

Supporting Libraries #

Library Version Purpose When to Use
python-socketio + aiohttp latest WebSocket abstraction If you want higher-level WebSocket messaging with room/channel support instead of raw FastAPI WebSocket
aiofiles 24.1+ Async file I/O Saving/loading session state to disk
Jinja2 3.1+ HTML templating Server-side rendering for the web UI (bundled with FastAPI)
httpx 0.28+ Async HTTP client If adding music source adapters that call external APIs

External Dependencies (System) #

Tool Purpose Notes
mpv Audio playback Must be installed on host system. Use --input-ipc-server=/tmp/jam-session-mpv.sock for control.
yt-dlp YouTube extraction Can be pip-installed as a package or used as CLI fallback.
ffmpeg Audio processing Used internally by yt-dlp for format conversion. Install via system package manager.

Installation #

Core Python packages #

Optional: higher-level WebSocket abstraction #

System dependencies (Fedora example) #

Alternatives Considered #

Recommended Alternative When to Use Alternative
Python + FastAPI Node.js + Express If team is JS-only and doesn't mind yt-dlp child process overhead
Python + FastAPI Go + Fiber If you want a compiled binary with zero Python dependency on the host
Raw FastAPI WebSocket python-socketio If you want automatic reconnection, rooms, and event namespacing built in
Vanilla JS frontend Svelte or Solid If the web UI grows complex enough to warrant reactive state management
yt-dlp Python API yt-dlp CLI via subprocess If you prefer process isolation at the cost of parsing stdout

What NOT to Use #

Avoid Why Use Instead
YouTube iframe embeds Has ads, requires a browser open on host, no IPC control, can't survive server restarts mpv + yt-dlp for direct audio stream playback
Flask Synchronous, no built-in WebSocket, clumsy async support FastAPI (async-native, WebSocket built in)
SQLite / PostgreSQL Overkill for an ephemeral party queue stored in memory In-memory Python data structures + optional JSON file persistence
React / Next.js Heavy for a simple queue UI. Build step complexity for a LAN party app. Vanilla JS + WebSocket, or minimal Svelte
Docker Adds complexity for a local-only app. mpv needs direct audio device access anyway. Run directly on the host

Stack Patterns by Variant #

  • Use FastAPI with raw WebSocket endpoints
  • Vanilla JS frontend with new WebSocket() and DOM manipulation
  • Queue stored as Python list in memory
  • Jinja2 templates for HTML pages
  • Add proper REST API endpoints alongside WebSocket
  • Use Pydantic models for all data structures (reusable across web and GTK)
  • Keep WebSocket as the real-time transport, REST for CRUD operations
  • Define a MusicSource abstract base class with resolve(url) -> AudioTrack method
  • YouTube implementation as first adapter
  • Spotify/Apple Music as future implementations

Version Compatibility #

Package A Compatible With Notes
yt-dlp 2025.x Python 3.10+ Check yt-dlp release notes for Python version deprecations
FastAPI 0.115+ uvicorn 0.34+ Standard pairing, always compatible
mpv 0.39+ JSON IPC protocol v1 JSON IPC is stable across mpv releases

Sources #

  • mpv manual — JSON IPC protocol, command reference, option reference
  • yt-dlp GitHub — Python API embedding, format selection, supported sites
  • FastAPI docs — WebSocket endpoints, async patterns

Conventions #

Conventions not yet established. Will populate as patterns emerge during development.

Architecture #

Architecture not yet mapped. Follow existing patterns found in the codebase.

Project Skills #

No project skills found. Add skills to any of: .claude/skills/, .agents/skills/, .cursor/skills/, .github/skills/, or .codex/skills/ with a SKILL.md index file.

GSD Workflow Enforcement #

Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.

Use these entry points:

  • /gsd-quick for small fixes, doc updates, and ad-hoc tasks
  • /gsd-debug for investigation and bug fixing
  • /gsd-execute-phase for planned phase work

Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.

Developer Profile #

Profile not yet configured. Run /gsd-profile-user to generate your developer profile. This section is managed by generate-claude-profile -- do not edit manually.