Skip to main content

Development setup

The full contribution guidelines are in CONTRIBUTING.md.

You need Python 3.11 to 3.13, FFmpeg, uv and GNU Make. The web UI also needs Node 22: a checkout builds its own client (see The web client). On 3.14, uv sync installs fine but skips the GPU title renderer (quadrants has no wheel for it yet): pin the checkout's virtualenv with uv venv --python 3.12 before make dev-test.

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

make dev-test is uv sync --extra dev --locked: the dev tools (pytest, ruff, mypy and the other CI gates) and nothing else. No torch, no CUDA, and it is what the CI test jobs install. There is no gpu extra to add: the GPU title kernels are a base dependency wherever they publish a wheel. Run it before any other make target.

TargetInstallsWhen
make dev-testdev tools onlyDefault for contributors (what CI tests with)
make dev-cidev tools onlyIdentical to dev-test today
make dev-macdev + all-mac (Apple Vision, Metal, the editorial stack)Apple Silicon app dependencies; Laya and ACE-Step need the installs below
make devCPU all + mac + dev, and the built web client; includes torch and demucsOnly if you work across all optional backends

For CUDA editorial development on Linux, use uv sync --extra dev --extra editorial-cuda. Do not combine it with editorial, all or all-mac: CPU and GPU ONNX distributions share an import namespace, and uv refuses these combinations. --all-extras is therefore unsupported. When running check or ci in that prepared CUDA environment, set ENSURE_DEV_COMMAND=true so the CPU setup does not replace it.

GPU or Full on Apple Silicon also needs Laya. After make dev-mac, run uv pip install --python .venv/bin/python laya-mlx. It is not part of all-mac. Use uv run --no-sync immich-memories ... to preserve that separately installed runtime; repeat its install after an explicit environment sync. The Mac recipe also checks HEIC decoding and the effective FFmpeg build before generation.

Rendering with generated music on a Mac? Also run make install-acestep. None of the targets above install ACE-Step: it lives in a sibling .venv-acestep next to the checkout, so every new clone and every git worktree needs its own make install-acestep. Without it, a config with ace_step.mode: lib renders every film with a bundled track and one warning in the log. immich-memories preflight shows a Music (ACE-Step) warning when it is missing, and make check-local-audio proves the install end to end. Details: Generated music.

Households and cultures​

Changes for different families, households and celebrations are welcome. An issue is enough to start; you don't have to write code.

Give an anonymized example: who belongs to the household, which people or dates matter, what the app does now, and what you expected instead. For holidays, include the country or culture and how the date is determined. Made-up names and synthetic pictures are fine. Please keep API keys, birth dates and private photos out of public issues.

Help me check the result against your example. Inclusive labels alone don't prove the selection, people groups, titles or calendar behave correctly. Once we have a reproducible case, it can become a regression test.

Check the install​

make check runs lint, format check, type check, the file length and complexity gates, and the unit tests. If it passes, your setup is correct. make ci adds everything else and is what you run before opening a PR: passing locally catches the checks you can reproduce before CI. Both depend on ensure-dev, which syncs the same CPU extras as make dev, so either adds the heavy optional packages to a make dev-test environment. On Linux, demucs pulls torch and NVIDIA wheels even though ONNX stays on the CPU variant. To keep a prepared lightweight environment, set ENSURE_DEV_COMMAND=true explicitly.

make help lists common targets; the Makefile contains the full list. Never run ruff, pytest or mypy directly: the make targets match what CI runs, so local results are consistent. Use conventional commit messages.

The test tiers, what each needs, and what to do when diff-cover fails on your PR are in the Testing guide.

The web client​

The web UI is a SvelteKit client in web/ at the repository root, built into the Python package and served by the app at /app. The built client is not committed: the release wheel and the Docker image build it, and a checkout builds its own. make dev does it for you. After make dev-test, run make web-client once (Node 22, what CI uses). Until then /app says the client is not built and names the command.

make web-client # npm ci, then build the client into the package
make web-build # rebuild the client after a change, as the app serves it
make web-check # type-check, check the API contract and types, build, refuse Immich logos

For hot reload, run the development server separately from the repository root:

npm --prefix web run dev

The build lands in src/immich_memories/web/client/, which git ignores, so generated hashed filenames stay out of source control. A wheel can't be built without it: hatch_build.py refuses one and names make web-build. make build builds the client first.

The client talks to the app through /api/v1. After changing an endpoint, run make web-api: it regenerates the OpenAPI document and the client's TypeScript types from it, and make web-check fails while they are stale.

Release process​

Maintainers use the release workflow. It covers candidate promotion, image-only publishes and the private terms gate.

Project structure​

src/immich_memories/
api/ # Immich API client
analysis/ # Story-first selection (the editorial route)
store/ # The annotation store: every banked fact and reading
db/ # The store's engine, tables, migrations, backup and restore
triage/ # The pinned ONNX encoder and its eight context heads
people/ # The people graph and registry
photos/ # Photo-to-video animation
processing/ # Video assembly (FFmpeg)
titles/ # Title screens, map fly-overs
audio/ # Music generation, audio ducking
web/ # The web server: /api/v1, sign-in, health (the Svelte client is web/ at the repo root)
cli/ # Click commands
cache/ # Thumbnail, judgment and embedding caches
tracking/ # Run history
operations/ # Lifecycle phases, storage report
planning/ # Auto-duration planning
automation/ # auto suggest/run
memory_types/ # Preset system

ARCHITECTURE.md has the full module map with class relationships.

Interface translations​

Web client labels use t('Text') from web/src/lib/i18n.svelte.ts. For inserted values, keep a named placeholder in the template: t('Connected as: {name}', {name: username}). Mark labels stored in tables with N_('Text'), then translate them with t where they are shown.

Run make ui-catalogues after changing labels. It reads the literal first argument of every t and N_ in web/src and updates ui.po beside each language's film-text messages.po, preserving translations and leaving new messages for translation. The app serves the same catalogues to the client at /api/v1/i18n. Keep placeholders and their format specifications intact. The catalogue test checks every supported language for missing messages and mismatched placeholders. Non-English catalogues are marked AI-drafted until reviewed; native-speaker corrections are welcome.

The app reads the shipped PO files directly and caches them. No separate compilation step is needed. Restart the app after editing a catalogue.

Merging and releasing are covered in the release workflow.