This file provides guidance to AI coding agents when working with code in this repository.
Jukebox is an NFC-based music player system. It uses NFC tags to trigger playback on speakers. The repo contains three modules:
- jukebox — Main music player app (reads NFC tags, controls playback)
- discstore — Library management tool (manages the tag → music URI mapping)
- pn532 — NFC reader library (excluded from linting/type-checking)
# Install dependencies
uv sync # base installation (always safe)
# Install optional extras (EXPLICIT ONLY — do not guess)
uv sync --extra nfc # enable NFC tag reading in jukebox (requires compatible hardware)
uv sync --extra api # enable REST API for discstore
uv sync --extra ui # enable Web UI for discstore
# NEVER use:
# uv sync --all-extras
# Reason: extras are environment-dependent (Python version, OS, hardware like NFC reader).
# Installing all extras may fail or introduce unnecessary dependencies.
# Rule for agents:
# - Only install extras if explicitly required by the task.
# - Do not assume availability of NFC hardware.
# - Prefer minimal installation.
# Run
uv run jukebox PLAYER READER
uv run discstore --help
uv run --extra api discstore api # REST API server
uv run --extra ui discstore ui # Web UI
# Format, lint, test, typecheck
uv run ruff format # auto-format code
uv run ruff format --check # check formatting
uv run ruff check # lint code
uv run ruff check --fix # auto-fix lint issues
uv run pytest # run all tests
uv run ty check # run type checker
# Run a single test
uv run pytest tests/path/to/test_file.py::test_function_name
uv run pytest -k "test_pattern"
# Run tests including those needing specific extra
uv run --extra ui pytestBoth jukebox and discstore follow Hexagonal Architecture (Ports & Adapters):
<module>/
├── domain/
│ ├── entities/ # Pydantic value objects
│ ├── repositories/ # Abstract port interfaces
│ └── use_cases/ # Business logic (no external deps)
├── adapters/
│ ├── inbound/ # CLI, API, UI controllers
│ └── outbound/ # Players, readers, JSON persistence
└── di_container.py # Wires all dependencies
Jukebox:
See jukebox/domain/entities/ for data models and jukebox/domain/use_cases/ for business logic.
The state machine lives in DetermineAction and HandleTagEvent.
Disc— music item with URI, metadata (artist, album, etc.), and playback options (shuffle, is_test)Library— collection ofDiscassociated with atag_id
Discstore:
See discstore/domain/entities/ for data models and discstore/domain/use_cases/ for business logic.
All components are wired in di_container.py. There is no global state — dependencies flow through constructors. Entry points call build_*() functions that instantiate the full object graph.
Pydantic-based config with union types + discriminators for plugin-style player/reader selection. Config can come from CLI args or environment variables. See adapters/inbound/config.py.
The library is stored as library.json via json_library_adapter.py. No database.
- Use type hints for function parameters and return types
- Use
Optional[X]overX | Nonefor Python 3.9 compatibility
- Tests mirror source structure under
tests/ - Use
pytestandpytest-mock; mock repositories viaMockRepo(not the real JSON adapter) - Conditional skip for Python version requirements (UI tests require 3.10+)