Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rbv
Personal photo library indexer with facial recognition and semantic search. Extracts CLIP embeddings and face detections from image galleries via an immich-ml compatible ML API, clusters faces into person identities, and serves results through a mTLS-authenticated HTTPS API with a React web UI.
Workspace layout
Cargo.toml workspace root
migrations/ PostgreSQL migrations (sqlx)
crates/
rbv-entity shared type definitions (no logic)
rbv-hash BLAKE3 content-addressed ID generation
rbv-data database access layer (sqlx + pgvector)
rbv-ml ML API client (immich-ml wire format)
rbv-cluster face embedding clustering (DBSCAN / union-find)
rbv-ingest gallery discovery and ingest pipeline
rbv-auth mTLS validation, argon2 passwords, sessions
rbv-search combined CLIP + face search queries
rbv-cli binary: `rbv`
rbv-api binary: `rbv-api` (axum HTTPS server)
ui/ Vite + React + TypeScript frontend
Crate dependency graph
rbv-entity (no deps)
rbv-hash → rbv-entity
rbv-data → rbv-entity, rbv-hash
rbv-ml → rbv-entity
rbv-cluster → rbv-entity
rbv-ingest → rbv-entity, rbv-hash, rbv-data, rbv-ml
rbv-auth → rbv-entity
rbv-search → rbv-entity, rbv-data, rbv-ml
rbv-cli → rbv-entity, rbv-hash, rbv-data, rbv-ml, rbv-ingest, rbv-cluster
rbv-api → rbv-entity, rbv-data, rbv-ml, rbv-auth, rbv-search
Prerequisites
- PostgreSQL with the
pgvectorextension - An immich-ml compatible ML API (e.g. the immich
machine-learningcontainer) - Rust toolchain (stable)
- Node.js + npm (for the UI)
Building
cargo build --release
Binaries are written to target/release/rbv and target/release/rbv-api.
Build the UI:
cd ui && npm install && npm run build
The built assets land in dist/ui/ and are served by rbv-api --ui-dir.
Deployment
See script/deploy.sh for the build-and-deploy script used to push to the
server, and asset/ for the systemd unit and Podman quadlet files.
Usage
See crates/rbv-cli/README.md for the full
rbv index / rbv cluster workflow, incremental re-indexing, and how to
reset face assignments.
API server
rbv-api \
--ca-cert /etc/rbv/ca.pem \
--server-cert /etc/rbv/server.pem \
--server-key /etc/rbv/server.key \
--database "$DATABASE_URL" \
--ml-uri http://127.0.0.1:3003 \
--ui-dir /srv/rbv/ui \
--face-cache /srv/rbv/cache/faces \
[--listen 0.0.0.0:8443] \
[--client-cn browser.local]
The server requires mTLS: clients must present a certificate signed by the
configured CA. --client-cn restricts access to specific certificate common
names; if omitted, any valid client cert is accepted.
API routes
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/login |
Authenticate (sets session cookie) |
POST |
/api/auth/register |
Create account |
POST |
/api/auth/logout |
Invalidate session |
GET |
/api/auth/me |
Current user |
GET |
/api/galleries |
Paged gallery list |
GET |
/api/galleries/random |
Random gallery sample |
GET |
/api/galleries/:id |
Gallery metadata |
GET |
/api/galleries/:id/images |
Images in a gallery |
GET |
/api/images/:id/file |
Full image file |
GET |
/api/images/:id/thumbnail |
Resized thumbnail |
GET |
/api/persons |
Paged person list |
GET |
/api/persons/:id |
Person detail + names |
GET |
/api/persons/:id/galleries |
Galleries containing person |
GET |
/api/persons/:id/faces |
Face detections for person |
PUT |
/api/persons/:id/name |
Set primary name |
POST |
/api/persons/:id/alias |
Add alias name |
POST |
/api/persons/merge |
Merge two persons |
GET |
/api/faces/:id/crop |
Cropped face image (cached) |
POST |
/api/search |
Combined CLIP + person search |
All routes except the auth endpoints require a valid session cookie.
Gallery directory format
A gallery directory must contain:
index.json— metadata (id, collection, source name/url, subjects, tags)tn/— thumbnail subdirectory (used to detect gallery directories)- Image files (jpg, png, gif, webp, tiff, bmp)
Directories are discovered recursively from --target; the structure may be
flat, chunked (galleries grouped in subdirectories), or mixed.