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 #
Recommended 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
MusicSourceabstract base class withresolve(url) -> AudioTrackmethod - 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-quickfor small fixes, doc updates, and ad-hoc tasks/gsd-debugfor investigation and bug fixing/gsd-execute-phasefor 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-userto generate your developer profile. This section is managed bygenerate-claude-profile-- do not edit manually.