Skip to main content

Health, logs and caches

Health endpoints​

EndpointReturnsUse it for
GET /health/live200 while the web process answers, {"status": "alive", "version": …}. Never contacts Immichliveness probe
GET /health/ready200 with status: ready when configuration and authenticated Immich access work; 503 with status: degraded otherwisereadiness probe, Uptime Kuma, blackbox exporter
GET /healthalways 200: a ready payload is rewritten to ok, a degraded one passes through as degradedcompatibility only, never a probe

Because GET /health always returns HTTP 200 and rewrites a ready payload to ok, it is useless as a probe.

All three are unauthenticated, on purpose: a container runtime has no session. The Immich check is bounded at 5 seconds, and the answer is reused for up to 10 seconds so a busy poller doesn't hammer Immich. With login on, only a logged-in session sees the automation and run detail (it carries person names and paths); a probe gets the status and the version. A degraded status never stops the app: the UI still serves.

{"status": "ready", "immich_reachable": true, "last_successful_run": "2025-12-15T10:30:00", "version": "<the running version>"}

Preflight​

The endpoints answer "is the web process up". preflight answers "will a film work on this box":

immich-memories preflight        # one row per check: OK, WARNING, ERROR or SKIPPED
immich-memories preflight -v # adds a Details column

In Docker: docker compose exec immich-memories immich-memories preflight.

It checks the Immich connection and API key (and each extra account), the model files and their digests, the title renderer, hardware encoding, the output folder, the home base, config paths that don't exist on this machine, notification delivery, the memory the box has, and every server you configured: caption server, text model, render worker, and ACE-Step when it is set to run on this machine. It also prints one row per outside host you switched on (Privacy). A warning names what is missing and the cut still runs without it, for example Music (ACE-Step) falling back to a bundled track. Any error exits 1, so a script or a setup step can stop on it. Run it after an install, an upgrade or a config change.

Model files​

immich-memories models fetch               # once per install, and after an upgrade
immich-memories models fetch --force # download again even when the files check out
immich-memories models fetch --laya # also the Laya checkpoint on the nas tier
immich-memories models fetch --no-detectors

About 140 MB of pinned files, each checked against a SHA-256: the DINOv2 encoder (88 MB) behind the eight context heads, the sensitive-content detector, the document classifier and the WordNet dictionary. They land under ~/.immich-memories/models/, the document classifier in the Hugging Face cache (in Docker both sit on the config volume, so a docker compose pull keeps them). A file already there with the right digest is not downloaded again, so running it twice costs nothing. On the gpu and full tiers it fetches the Laya audience checkpoint too (tiers). --no-detectors skips the detector files, for an install without the editorial extra. A cut that needs a missing file stops with an error naming this command; preflight flags it first.

Logging​

INFO by default. immich-memories -v generate … logs at DEBUG; --log-level WARNING keeps warnings and errors. Both are root options, so they go before the subcommand and work for ui too. In a container, set IMMICH_MEMORIES_LOG_LEVEL=DEBUG. generate --quiet and auto run --quiet change what the terminal shows, not what is logged.

Lines look like 2025-12-15 10:30:00,123 [INFO] immich_memories.generate [abc123]: Assembling final video...: the bracketed run id ties one run's lines together (- outside a run). IMMICH_MEMORIES_LOG_FORMAT=json writes one JSON object per line with the same fields, so jq 'select(.run_id=="abc123")' works. IMMICH_MEMORIES_LOG_FILE=/path/to/file.log writes the same lines to a file as well; in Docker, point it at a mounted path.

Log lines go to stderr. Stdout only carries what a command prints, so runs storage --json, report --json and auto status --json give you one JSON document you can pipe straight into jq, whatever the log level. docker logs shows both streams.

Model usage records​

Only with a model. Each selection attempt keeps llm-usage.json under cache/editorial-runs/<memory>/attempts/<attempt>/: calls, cache hits and tokens, split by_stage (caption_controls, caption, motion, reader) and by_model. It is checkpointed as the run goes, so a killed run leaves its last count. When a server returns no token counts, unmetered_calls counts those calls and usage_complete is false: the totals are then a floor. Provider batch lines count the same way, with batch_unmetered_calls and batch_usage_complete.

Caches​

Everything lives under ~/.immich-memories/cache/ (or cache.directory):

Directory or fileWhat it holdsCap
thumbnails/one Immich preview per candidate a film can reachthumbnail_cache_max_size_mb, 10 GB
video-cache/downloaded Immich clipsvideo_cache_max_size_gb 10 GB, video_cache_max_age_days 7
editorial-runs/each cut's attempt directories: the plan, its progress and llm-usage.json. The store links each run to onenone
structure-banks/the thumbnail-hash and scene-print caches; rebuilt when missingnone
preview-cache/clip previews the old web pages played; nothing writes it now. Delete a leftover folder by handnone
../cache.db (one level up)a pre-store file nothing writes; its run history and scores are imported into the store once, then it can gonone

output.directory (default ~/Videos/Memories, one level up from cache/) is not a cache, but it grows the same way: one file per run. A run that delivers to Immich has its local film and run directory removed right after the upload is confirmed, so a container with upload on stays bounded without any setting. A run that never uploads (upload_enabled: false, or a delivery that stays pending) keeps its output on disk, same as before: use immich-memories runs delete or runs storage to see and clear it by hand.

Both output.directory and cache.directory get a free-space preflight before a run starts and again right before the film is written. Below output.min_free_space_gb (5 GB by default) the run logs a warning naming the volume and the free space; if the estimated film would not fit at all, the run stops before rendering instead of failing halfway through. The estimate comes from the target duration and the configured output.quality.

The facts the app banked (head answers, detector verdicts, measurements, and captions and readings when a model is used, each keyed by producer and exact input) and your own picture decisions are not a cache: they live in the store, ~/.immich-memories/store.db by default. An annotations.sqlite from an older install is imported into it once and then left alone.

cache:
directory: ~/.immich-memories/cache
database: ~/.immich-memories/cache.db
video_cache_enabled: true
video_cache_max_size_gb: 10.0
video_cache_max_age_days: 7
thumbnail_cache_max_size_mb: 10000

What a second cut asks again​

Nothing in the store's banked facts is keyed to a run, so a second cut over the same pictures reuses every fact the first one banked. Standing is read from each picture's facts and asks nothing at all. With a model, the period reading is banked one calendar month at a time, so a monthly cut after a yearly one asks nothing again for that month. A warm cut spends its time on video work. When a release changes a prompt, the answers that prompt produced are asked again once; captions, head answers and detector verdicts are keyed by their own producers and stay warm.

The facts a cut measures​

Three facts are measured only once a cut has chosen a picture, and banked in the store:

TableWhat it holdsWritten when
motion_residualsthe optical flow of one Live Photo's companion video, including the residual the 1.5 threshold readsa cut measures a chosen Live Photo
speech_regionsthe utterances a clip holds, in its own seconds; an empty list means "listened, heard none"a cut keeps a video or a playing Live Photo
live_clock_offsetshow the clocks of a Live burst's companion videos line up; an empty answer means the burst ships as its photographa cut keeps a burst of two or more Live Photos

Each row is keyed by the picture, its source metadata, and a producer version that includes the method and, for speech, speech.vad_threshold and speech.min_silence_ms. Change any of those and the next cut measures again. The next cut reads these before it plans: a Live Photo whose banked residual is under 1.5 is planned as a still from the start. Only pictures a cut reaches are measured, and every later cut reads them for free.

The preview cache scales with your library​

A run reads each candidate's preview several times. One preview is about 315 KB, so size the cache as thumbnail_cache_max_size_mb ≈ 0.35 × pictures a film can reach; the 10 GB default holds about 31,000. Previews the current run uses are never evicted, so a run that doesn't fit overflows the cap rather than losing facts, and one WARNING says how far over you are. The next overlapping run pays for it by downloading those previews again.

Video cache mechanics​

Files sit at {id[:2]}/{id}{ext}. A hit is ffprobed first and fetched again if unreadable. A download streams into {id}{ext}.part and is renamed only when complete, so a killed run leaves nothing the next one would trust; .part files idle for an hour go at the next start. Age eviction runs at the start of every run, size eviction after each download and once at the end.

Clearing​

The Caches section of the Settings page shows each cache's usage, with a Clear button per cache. From a shell, the video and thumbnail caches are plain directories, safe to delete while the app is idle:

rm -rf ~/.immich-memories/cache/video-cache
rm -rf ~/.immich-memories/cache/thumbnails

Deleting ~/.immich-memories/cache costs previews, clips and the attempt directories under editorial-runs/, not facts: those are in the store. Don't delete store.db: without it every fact about your library is prepared again, and every picture you cleared or ruled out is held again.

Moving an install​

immich-memories store backup and store restore move everything the store holds. Or copy ~/.immich-memories (in Docker: the config volume) whole.