Skip to main content

Development Setup

Get the project running locally for development. The full contribution guidelines are in CONTRIBUTING.md.

Prerequisites

  • Python 3.11+
  • FFmpeg (for video processing tests)
  • uv (Python package manager)
  • GNU Make

Clone and install

git clone https://github.com/sam-dumont/immich-video-memory-generator.git
cd immich-video-memory-generator
make dev-test

make dev-test installs the dev tools (pytest, ruff, mypy and the other CI gates) plus the gpu and speech extras — the same set the CI test jobs use. It is the fast path: no torch, no CUDA. Run it before any other make target.

Other install targets, when you need them:

TargetInstallsWhen
make dev-cidev tools onlyLint/typecheck-only work
make dev-testdev + gpu + speechDefault for contributors (what CI tests with)
make dev-macdev + all-mac (Apple Vision, Metal, ACE-Step MLX)Apple Silicon, full feature set
make devevery extra (torch, ACE-Step, demucs — slow)Only if you work across all optional backends

Verify everything works

make check

This runs lint, format check, type check, file length gate, complexity gate, and all unit tests. If it passes, your setup is correct.

Key commands

CommandWhat it does
make testUnit tests
make lintRuff linter
make formatAuto-format code
make typecheckmypy type checking
make ciFull CI pipeline (the 16 local gates, plus the unit tests)
make critiqueAI smell audit
make test-integrationIntegration tests (needs FFmpeg + Immich)

The Makefile is the single source of truth. Never run ruff, pytest, or mypy directly: the make targets match what CI runs, so local results are consistent.

Before submitting a PR

make ci

If make ci passes locally, CI will pass too. Use conventional commit messages: feat(scope): description, fix(scope): description, etc.

Testing tiers

Unit tests (make test): pure logic, no external dependencies. Run in CI on every PR.

Integration tests (make test-integration, or one suite such as make test-integration-assembly): real FFmpeg assembly, real Immich API reads. They live in per-suite folders under tests/integration/ (assembly, audio, audio_mixing, auth, automation, cli, live_photos, photos, pipeline, processing, titles) and skip gracefully if a service isn't available. They run locally and on a self-hosted Linux GPU runner, which uploads its coverage to Codecov under the integration-linux flag. The per-suite coverage XMLs they write under tests/ are gitignored — do not try to commit them.

If diff-cover fails on your PR

Every PR needs 80% coverage on the lines it changes. Before checking that, CI runs the FFmpeg-only integration suites covering the paths your diff touches, and only those, then merges their coverage into the diff-cover run. So code reachable only through FFmpeg is covered for you: you do not need to write unit tests for it.

To reproduce locally exactly what CI will see:

make integration-coverage-for-diff   # runs only the suites your diff touches
make diff-cover-local # merges them with unit coverage, same as CI

If diff-cover still fails after that, the uncovered lines are not reachable from an integration suite and do need unit tests. Subprocess boundaries can be stubbed rather than run for real: tests/test_ffmpeg_pipe.py shows the pattern.

Project structure

src/immich_memories/
api/ # Immich API client
analysis/ # Video analysis, scoring, clip selection
speech/ # VAD + transcription for cut placement
photos/ # Photo-to-video animation
processing/ # Video assembly (FFmpeg)
titles/ # Title screens, map fly-overs
audio/ # Music generation, audio ducking
ui/ # NiceGUI web interface
cli/ # Click commands
cache/ # Analysis and video caching
tracking/ # Run history
operations/ # Lifecycle phases, storage report
planning/ # Auto-duration planning
scheduling/ # Cron-based generation
automation/ # auto suggest/run
memory_types/ # Preset system

See ARCHITECTURE.md for the full module map with class relationships.