This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This project uses devenv (Nix-based development environment) for consistent development setup across machines.
This repository includes Claude Code settings in the .claude/ directory that control what operations Claude can perform.
Settings Structure:
.claude/settings.json- Base permissions for all environments (local + CI/CD).claude/settings.local.json- Your local overrides (gitignored).claude/settings.local.json.example- Template for creating local settings
Precedence Hierarchy:
settings.local.json → settings.json → ~/.claude/settings.json
(highest) (lowest)
Settings are automatically merged, with local settings overriding base settings.
Creating Local Overrides:
If you need additional permissions for local development:
cp .claude/settings.local.json.example .claude/settings.local.json
# Edit .claude/settings.local.json to add your permissionsYour local settings are gitignored and won't affect other developers or CI/CD.
Documentation: See .claude/README.md for detailed information about the settings system.
devenv shell- Enter the development environmentdevenv-help- Display available helper scriptsgit lfs pull- Pull Git LFS artifacts (done automatically on shell init)
- The project automatically initializes Git LFS and pulls artifacts when entering an interactive shell
- Locale is set to C.UTF-8 for consistent behavior
- DO_NOT_TRACK=1 is set by default
- Poetry keyring backend is disabled to avoid keyring queries
The devenv provides:
- Git and Git LFS
- Claude Code CLI
- VS Code with pre-configured extensions (interactive mode only)
- Nix language support
Pre-commit hooks are automatically configured and include:
- dos2unix - Convert line endings (excludes assets)
- trim-trailing-whitespace - Remove trailing whitespace
- nixfmt-rfc-style - Format Nix files
- shellcheck - Shell script analysis with extended checks
- hadolint - Dockerfile linting
- markdownlint - Markdown formatting (120 char line limit)
- yamllint - YAML validation (excludes pnpm-lock.yaml, charts/)
- check-json/check-toml - JSON/TOML validation
- trufflehog/ripsecrets - Secret detection
- typos - Spell checking (excludes SVG files)
CRITICAL: After making ANY code changes, you MUST run make check
before proceeding or considering the task complete. This command runs:
- make fmt - Format all Go code with
go fmtandgofmt -s - make vet - Run
go vetto catch common Go mistakes - make lint - Run
golangci-lintfor comprehensive linting - make test - Run all tests with race detection
- make build - Ensure the code builds successfully
Never skip this step. All changes must pass these checks. If any check fails, fix the issues before proceeding.
Running the application:
# Quick run requires real credentials
# See .env.example for required Telegram, Spotify, and LLM configuration
# Run with debug logging
go run ./cmd/djalgorhythm --log-level=debug
# Run with custom config file
go run ./cmd/djalgorhythm --config=myconfig.envTesting specific components:
# Test a specific package
go test ./internal/flood/
go test ./internal/chat/telegram/
go test ./internal/core/
# Run tests with verbose output
go test -v ./internal/core/
# Test with coverage
go test -cover ./...
go tool cover -html=coverage.out # After running with -coverprofile=coverage.outDebugging and troubleshooting:
# Check application help and all CLI flags
go run ./cmd/djalgorhythm --help
# Validate configuration without running
go run ./cmd/djalgorhythm --config=.env --help
# Test with different languages
env DJALGORHYTHM_LANGUAGE=ch_be go run ./cmd/djalgorhythmThis project enforces strict code quality through golangci-lint with comprehensive linter configuration. All code must satisfy these requirements:
- godot: All comments must end with a period (
.)- Example:
// ProcessMessage handles incoming messages.✓ - Example:
// ProcessMessage handles incoming messages✗
- Example:
- Comments should start with the function/type name they document
- Use complete sentences for all public function/type comments
-
gocyclo: Cyclomatic complexity must not exceed 15
- Cyclomatic complexity measures independent paths through code
- If exceeded, refactor by extracting helper functions or simplifying conditional logic
-
gocognit: Cognitive complexity should be reasonable
- Cognitive complexity measures how hard code is to understand
- Break down complex functions into smaller, focused helpers with clear names
- Reduce nested conditionals and loops
-
cyclop: Package-level complexity limit is 10
- Entire packages should maintain low overall complexity
-
nestif: Avoid deeply nested if statements
- Maximum nesting depth should be limited
- Use early returns to reduce nesting
- Extract complex conditionals into well-named boolean functions
-
mnd: No magic numbers in code
- All numeric literals (except 0, 1, 0.0, 1.0) must be named constants
- Applies to: arguments, case statements, conditions, operations, returns, assignments
- Example:
const maxRetries = 3then usemaxRetriesin code
-
goconst: Repeated strings (2+ occurrences) must be constants
- Minimum string length: 2 characters
- Prevents string duplication and typos
-
errcheck: Never ignore errors
- All error returns must be checked explicitly
- Use
_ = func()with comment if intentionally ignoring (rare cases only)
-
errorlint: Use modern Go 1.13+ error wrapping
- Use
fmt.Errorf("context: %w", err)for error wrapping - Check for
errors.Is()anderrors.As()usage where appropriate
- Use
-
funlen: Functions should not exceed 100 lines or 50 statements
- Long functions are hard to test and understand
- Extract logical blocks into helper functions
-
dupl: Avoid code duplication (threshold: 100 tokens)
- Extract common logic into shared functions
-
lll: Line length must not exceed 140 characters
- Break long lines appropriately at logical boundaries
- No unused parameters: Rename unused parameters to
_(underscore) - HTTP requests: Use
http.NoBodyinstead ofnilfor requests without body - Context usage: Pass context through function calls for cancellation/timeout
- govet: Enable shadow variable detection to catch accidental variable shadowing
When writing new code or refactoring existing code:
- Start simple: Write the logic first, then refactor to meet complexity limits
- Extract early: If a function grows beyond 50 lines, look for extraction opportunities
- Name well: Helper functions should have clear, descriptive names explaining their purpose
- Document everything: Public functions, types, and constants need godoc comments with periods
- Test helpers: Mark test helper functions with
t.Helper()for better error reporting - Iterate: Run
make lintfrequently during development to catch issues early
CRITICAL: When introducing new configuration options:
- Add to config structs - Update the relevant config struct in
internal/core/config.go - Update .env.example - ALWAYS add the new option to
.env.examplewith:- Clear documentation comment explaining the option
- Sensible default value or example
- Required/optional status indication
- Add CLI flags - Add corresponding command-line flags in
cmd/djalgorhythm/main.go - Update README.md - Add the new option to the configuration table in README.md
- Test the option - Ensure the new configuration works with both environment variables and CLI flags
Never add a config option without updating .env.example - this is the primary reference for users.
The project includes a comprehensive Makefile with targets for:
make build- Build the binarymake test- Run tests with race detectionmake fmt- Format codemake vet- Run go vetmake lint- Run golangci-lintmake check- Run all quality checks (fmt, vet, lint, test, build)make clean- Clean build artifactsmake run- Build and run the application
Use make help to see all available targets.
DJAlgoRhythm is an AI-powered chat-to-Spotify DJ bot built with Go. Key architectural components:
cmd/djalgorhythm/main.go- Application entry point using Cobra CLI frameworkinternal/core/dispatcher.go- Central message dispatcher that coordinates all componentsinternal/core/config.go- Configuration management with environment variables and CLI flagsinternal/chat/- Unified chat frontend interface with platform-specific implementationsinternal/spotify/- Spotify Web API client for playlist managementinternal/llm/- LLM provider abstraction (OpenAI primary, others experimental)
- Chat Frontend → receives messages from Telegram/other platforms
- Dispatcher → processes messages and determines track requests
- LLM Provider → disambiguates natural language requests
- Spotify Client → adds tracks to playlist
- Dedup Store → prevents duplicate additions using Bloom filters + LRU cache
- Shadow Queue (
internal/core/shadow_queue.go) - Tracks queued songs for reliable state management - Queue Manager (
internal/core/queue_manager.go) - Maintains continuous playback by managing queue ahead duration - Approval Handler (
internal/core/approval_handler.go) - Manages user confirmations via reactions/buttons - Flood Protection (
internal/flood/) - Anti-spam protection with sliding window rate limiting - Internationalization (
internal/i18n/) - Multi-language support (English, Swiss German)
- Unit tests for all core components (use
go test ./...) - Integration tests for chat frontends with disabled configurations
- Race detection enabled by default in
make test - Test-specific patterns: Mock external dependencies, test error conditions
- OpenAI: Fully implemented (
internal/llm/openai.go) - Anthropic/Ollama: Planned but not yet implemented (only interfaces exist)
- Current Reality: Only OpenAI provider works; others will return "not implemented" errors
- All configuration goes through dual validation: environment variables AND CLI flags
- USE CLI flags in
cmd/djalgorhythm/main.goas the authoritative source for configuration options .env.examplemust match CLI flags.- Required fields: Spotify credentials, Telegram bot token (if enabled), LLM provider
- Frontend Layer - Chat platform abstraction (
internal/chat/frontend.go) - Dispatcher - Central coordinator with context management and concurrent safety
- Message Contexts - Track ongoing conversations with users (
MessageContextin dispatcher) - Shadow Queue - Maintains reliable queue state separate from Spotify's queue
- Approval Flow - Reaction-based confirmations with configurable timeouts
- Context-based cancellation throughout the application
- Mutex protection for shared state (queue, contexts, admin warnings)
- Graceful shutdown with 30-second timeout and 2-second delay
- Race-safe operations for all map access patterns
- Structured logging with zap logger throughout
- Context propagation for request tracing
- Fallback behaviors when external services fail
- User-friendly error messages via i18n system