Label anything with words you invent. Search your library in plain English. Find near-duplicates. LensLab runs a vision model on your own machine — no API key, no upload, no per-image cost.
Runs on your machine · your pictures are never uploaded · no API key
A decade of photographs, screenshots, scans and exports sits on a disk somewhere, and the only ways in are the filename, the date, and whatever folder structure you had the discipline to maintain.
Manual tagging is a chore nobody finishes. The library grows faster than the labels do.
Off-the-shelf models recognise a fixed list of classes. Your question is rarely on it.
Per-image pricing, an upload, and a copy of your library on somebody else's disk.
LensLab runs CLIP locally. CLIP places pictures and short phrases into the same mathematical space, so a phrase you invent on the spot can rank a photograph you took years ago. Everything below is that one comparison, asked differently.
Drop an image in. It scores against a built-in vocabulary across four facets — kind, subject, setting, look — and says plainly when it isn't sure.
Type any labels at all. No training, no fixed class list, confidence bars back in milliseconds.
Search the whole library in plain English, ranked by meaning rather than by filename.
Exact byte-identical matches and perceptual near-duplicates, reported separately rather than lumped together.
Throughput and latency were measured on the build machine at build time. The test count was re-verified on 2026-09-04: 48 passed, 1 skipped, 0 failed.
A Python web application, a local model, and one SQLite file. The vector for each image is computed once at ingest and stored in its row — which is why describing a library tile costs a row read and four dot products rather than another look at the pixels.
Every row states its own evidence. Where something is not built, it says so and says why — a matrix showing everything complete is a matrix nobody believes.
| Requirement | What was built | Evidence | Status |
|---|---|---|---|
| Label an image with words the user invents | Zero-shot label studio. Any labels, one per line, no training and no fixed class
list. Renders confidence bars for one image, a contact sheet for many.
Presets can be saved and reused. |
5 endpoint tests + browser walk | Built |
| Tell me what an image is without me typing anything | Identify scores against a built-in vocabulary across four independent facets,
with a refinement pass that turns a category into a thing (“fruit” → “a mango”).
Says “No confident match” rather than asserting a wrong answer. |
5 tests, both branches | Built |
| Ingest a folder without dying on one bad file | Batched folder walk with live progress, resumable, and a skip report naming every rejected file and the reason. Re-ingesting a folder is a no-op. | 24/25 on a planted corpus | Built |
| Search the library in plain English | Exact cosine ranking across every stored embedding — brute force, which is exact and fast to roughly 100,000 images. | 114 ms avg, 205 ms max | Built |
| Find duplicates | Byte-identical matches and perceptual near-duplicates, clustered and reported as separate categories rather than merged. | both planted pairs found | Built |
| “More like this” from a library image | Ranks the library against one of its own tiles using the stored vector, and excludes the source image from its own results. | 2 tests | Built |
| Get the data back out | Every result table exports as CSV or JSON. | 3 tests | Built |
| Nothing leaves the machine | No fonts, scripts, styles or analytics load from anywhere; the favicon is inline so even that costs no request. The only outbound call in the product's life is the one-time model download, which is hash-pinned. | asserted by test, not promised | Built |
| Safe to point at a real folder | Ingest roots are bounded by configuration, paths are resolved before they are trusted, the thumbnail route refuses traversal, and forgetting an image removes the row and never the file. | 6 safety tests | Built |
| Authentication | Not built. LensLab is a single-user tool bound to the loopback interface. The demo you can try is gated by this site, not by the application. Publishing it means putting an authenticating proxy in front — the compose file says so at the line where a reader would be tempted otherwise. | deliberate scope boundary | Not built |
| Text and OCR extraction | Reading text inside images needs a second model and a second pipeline. | — | V2 |
| Libraries beyond ~100k images | Brute-force ranking stays exact and quick to roughly 100,000 images. Past that it wants an approximate-nearest-neighbour index, which trades exactness for scale. | — | V2 |
| Face clustering | Deliberately excluded. Grouping people by face creates a biometric compliance surface that this product does not want and does not need. | scope decision | Out of scope |
| Item | Note | State |
|---|---|---|
| Zero-shot label studio | Type any labels — no training, no fixed class list | Shipped |
| Identify without labels | Built-in vocabulary, four facets, refinement pass | Shipped |
| Folder ingest with live progress | Batched, resumable, with a skip report | Shipped |
| Semantic library search | Exact cosine ranking over every embedding | Shipped |
| Near-duplicate finder | Perceptual clusters and exact byte matches, separately | Shipped |
| Paste-anywhere and batch contact sheet | Ctrl-V, or drop many at once | Shipped |
| CSV / JSON export | Every result table is exportable | Shipped |
| OCR / text extraction | Needs a second model | Planned |
| Index for 1M+ images | Brute force is exact to ~100k | Planned |
| Face clustering | Deliberately out — biometric compliance surface | Excluded |
The same application runs both ways. The lanes differ only in where the model runs and whether the library is live — flipped with environment variables, never with a code change.
Your data and your model stay on your hardware. Egress is zero.
127.0.0.1 — no public listenerThe same image, somewhere else. Nothing to install beyond a container runtime.
docker compose up — publishes to loopback only by default./data mounted read-write for the library database:ro — structural, not a promise.env.exampleA cloud-hosted twin — the same build pointed at an API-backed model behind a keyless gateway, with a synthetic library instead of live data — is a supported shape but is not deployed today. Only the on-premises lane above is running.
LensLab is a local-first tool: the model and your images stay on the machine it runs on, which is the whole point of it. There is no hosted instance — but the walkthrough below is the real application, recorded end to end. Enter your email, we'll show you a one-time PIN, and the demo plays.
Runs on your hardware · no API key · no per-image cost
Enter your email and we'll issue a one-time PIN to unlock the walkthrough.
Enter a valid email address.
Enter it below to watch the demo.
That PIN was not correct.