# Overview [← Documentation index](index.md) Photo Pipeline sorts a photo library. It finds duplicates before anything expensive happens to them, asks a human which pictures may leave the machine, describes the ones that may, proposes album names from what it found, renames folders under a crash-safe journal, uploads through `immich-go`, and can archive a finished album off active storage without ever forgetting it existed. It runs locally. It talks to exactly three things outside itself: a vision provider, an Immich server, and `exiftool` — and it will tell you before it uses any of them. ## The workflow Each stage is a gate, not a tab. A later stage can always be looked at; its actions stay disabled until what they depend on is true. ```mermaid flowchart TD I["0 · Inventory
discover, hash, cluster duplicates"] --> S["1 · Safety
score and human decision"] S -->|sfw| A["2 · Analysis
vision provider, EXIF checkpoint"] S -->|nsfw| U A --> B["3 · Albums
proposal, then guarded rename"] B --> U["4 · Upload
immich-go, verified bytes"] U --> R["5 · Archive
copy, verify, then reclaim space"] ``` | Stage | What it decides | What it changes | |---|---|---| | Inventory | which file is the canonical copy of a picture | nothing — it only reads | | Safety | whether a photo may be sent to a cloud provider | one `sfw`/`nsfw` EXIF keyword | | Analysis | what a photo shows | a managed caption segment and additive keywords | | Albums | what a folder should be called | folder names, through a journaled rename | | Upload | which exact bytes reach Immich | nothing locally; assets appear in Immich | | Archive | which album leaves active storage | files move to the archive, after verification | ## What it will not do These are enforced in code, not by convention, and each one is why some action you expected is sometimes refused. - **Nothing under `_IGNORE/` is ever read.** Not scanned, not counted, not thumbnailed, not sent anywhere. - **A path is not an identity.** Every picture has a stable id, so moving or renaming it loses no history. - **Only a confirmed-SFW photo reaches the vision provider.** A photo marked NSFW is still uploadable to Immich; it simply never leaves for analysis. - **Metadata is verified, not hoped for.** Every stage that writes EXIF reads it back and proves that what it did not own is unchanged. - **One writer at a time.** A library lock, held by one process, is what makes a crash recoverable instead of ambiguous. - **Nothing irreversible happens without a preview and an explicit approval** that names the exact count. ## Where things live | | | |---|---| | the photo library | wherever you point `PHOTO_PIPELINE_LIBRARY_ROOTS`; mounted read-write | | the database, cache, logs, backups | the data directory, never inside the library | | secrets | the environment, never the database and never a log line | | these documents | `docs/` in the repository, served at `/docs` by the application | ## Running it The short version, for a host installation: ```bash python -m photo_pipeline migrate python -m photo_pipeline serve # the API and this browser application python -m photo_pipeline worker # the process that does the long work ``` The full procedure, the container path, and every setting are in the [installation manual](installation.md); if you would rather start using it, take [the guided first pass](first-pass.md).