Skip to main content

lookbook

Distill raw image pools into optimized, high-diversity reference sets for training personalized models (character LoRAs, product LoRAs, style LoRAs).

Status: All five v1 phases are shipped. The package can: clean a photo dump (200→20 in <30s, no GPU); run the full embeddings + facility-location workflow with CLIP or DINOv2; curate a person / character LoRA with face detection, ArcFace identity diversity, and pose-bin quotas; serve every verb over HTTP (FastAPI via qh); and expose every verb over MCP (via fastmcp) so an LLM agent can drive curation directly. Since then it has also gained one-call character / environment reference picks, a human-in-the-loop curate_interactive, and compare_to_reference — "is this generation still the same subject?" as a number. See misc/docs/lookbook_development_plan.md for the full roadmap and misc/docs/lookbook_design_report.md for the design rationale.

Why

Training a personalized image model needs ~15–30 carefully chosen reference images, where each adds new context — pose, lighting, expression, distance. "Top-K by score" collapses to near-duplicates; this is fundamentally a set-selection problem with diversity as a constraint, not a tiebreaker.

lookbook separates per-image scoring (is this image individually good?) from set-level selection (does this collection cover the concept?), and makes both extensible.

Install

pip install lookbook                  # core: Pillow, numpy, dol, meshed, config2py
pip install lookbook[funnel]          # + cv2 / imagededup for the cheap funnel
pip install lookbook[embed]           # + torch, CLIP, DINOv2, pyiqa, apricot
pip install lookbook[person]          # + InsightFace, head pose, mediapipe
pip install lookbook[http]            # + FastAPI / qh server
pip install lookbook[mcp]             # + fastmcp (Anthropic MCP server)

The base install has no ML dependencies — Phase 1 (cheap funnel) works on a plain laptop. [embed] and beyond pull torch.

Quickstart

CLI:

# Phase 1: clean up a photo dump (drops blurry, dark, duplicate, tiny).
lookbook curate ./photos --k 20 --recipe funnel

# Phase 2: same funnel + DINOv2 embeddings + facility-location selection
# for "diverse but sharp" picks. Downloads ~350MB on first run; subsequent
# runs are fast and cached. Use --recipe diverse_clip for CLIP semantic
# embeddings instead.
lookbook curate ./photos --k 20 --recipe diverse

# Phase 3: full character/person LoRA curation. Detects faces, embeds
# with ArcFace, applies pose-bin quotas, and runs cluster-coverage
# diagnosis. Pulls insightface + sixdrepnet (lazy on first use).
lookbook curate ./photos --k 20 --recipe person

# Same shape with no model downloads (mock backends; useful for tests):
lookbook curate ./photos --k 8 --recipe person_mock

# Phase 4: HTTP server. Every verb is POST /<verb> with a JSON body;
# Swagger UI at /docs.
lookbook serve --port 8000 --host 127.0.0.1
# curl examples:
#   curl -X POST localhost:8000/list_recipes -H 'Content-Type: application/json' -d '{}'
#   curl -X POST localhost:8000/curate_source -H 'Content-Type: application/json' \
#        -d '{"source_path":"/abs/photos","k":20,"recipe":"funnel"}'

# Phase 5: MCP server (stdio transport — for Claude Desktop, Anthropic SDK).
# Each verb is exposed as an MCP tool an agent can call.
lookbook mcp

# See available scorers, embedders, filters, selectors, recipes / profiles:
lookbook list-plugins
lookbook list-recipes

Python:

from lookbook import curate

result = curate(
    "./photos",
    k=20,
    scorer_ids=("resolution", "file_hash", "phash", "blur", "exposure"),
    filter_ids=(
        ("min_resolution", {"min_long_side": 800}),
        "exposure_range",
        "min_blur",
        "no_exact_duplicate",
        "no_near_duplicate",
    ),
    selector_id=("top_k", {"metric_id": "blur"}),
)
print(result.report)  # drop counts attributed to each filter
print([r.image_id for r in result.kept])

One-call presets: character and environment references

Two opinionated facades over curate for the "pick the best reference image(s) from this pool" job:

from lookbook import curate_for_character, curate_for_environment

# Known character: scores resolution / sharpness / exposure / face quality,
# ranks by the composite `face_quality`. face_detector="mock_face" runs it
# offline; the default "insightface" needs `pip install lookbook[person]`.
best = curate_for_character("./frames", k=1)

# No-face pools (environment plates, props, style boards): ranks by the
# composite `technical_quality`. No ML dependency at all.
best = curate_for_environment("./plates", k=3)

Identity check: does this generation still match the reference?

from lookbook import compare_to_reference

result = compare_to_reference(reference, candidate, embedder="arcface")
result.score  # [0, 1], 1 = same identity
result.passed  # score >= threshold (0.85 default) — advisory
result.per_reference  # per-view breakdown when the reference is a pool

reference is one image ref or a list of them (folded by aggregation, "max" by default). Use "clip" / "dinov2" as the embedder for scenes, props and architecture. Also exposed as POST /compare_to_reference and as the compare_to_reference MCP tool.

Interactive curate (keep the human in the loop)

Pipeline-only top-k can rank "boring but sharp" above "stylistically perfect but slightly blurry". curate_interactive invites the caller into the loop, one round at a time:

from lookbook import curate_interactive, InteractiveDecision


def decide(presented, info):
    # show `presented` to the user; collect their picks
    return InteractiveDecision(keep=("img-abc",), reject=("img-xyz",))


result = curate_interactive(
    "./photos",
    on_decision=decide,
    k=20,
    present=8,
    scorer_ids=("blur", "exposure"),
)

Pre-recorded decisions (a list of InteractiveDecision) are accepted in place of the callable — handy for tests, headless replays, and agent-scripted flows.

local_path() on every ImageRef

PathImageRef, BytesImageRef, and UrlImageRef all expose local_path(cache_dir=None) -> str. Path refs return their existing path; bytes/url refs materialize once into a content-addressed cache (honors $LOOKBOOK_REFS_CACHE_DIR). The free function lookbook.to_local_path(ref) dispatches across all subtypes — useful when downstream tools (ffmpeg, fal upload) need a real file.

Architecture

Five layers; the heavy ML libs live only at the bottom so the upper layers stay laptop-installable.

Interface       (CLI, HTTP via qh, MCP via fastmcp, Python lib)
   ↓
Recipe / facade (lookbook.curate, named recipes, profiles)
   ↓
Orchestration  (lookbook.pipeline, manifest, drop attribution, run records)
   ↓
Plugin layer   (Scorer | Filter | Embedder | Selector — Protocols)
   ↓
Backend        (CLIP, DINOv2, InsightFace, 6DRepNet — wrapped, lazy-imported)

The manifest — MutableMapping[(image_id, metric_id), Annotation] — is the SSOT. Persistence is pluggable via dol: filesystem (default), SQLite, S3, Mongo, Redis. The default location is the user's app data folder via config2py: ~/.local/share/lookbook on Linux and macOS (it follows the XDG convention, not ~/Library/Application Support), %LOCALAPPDATA% on Windows.

New scorers/selectors/filters are registered, never subclassed. See the .claude/skills/ directory for developer skills (lookbook-dev, lookbook-add-scorer, lookbook-add-selector, lookbook-storage).

Project layout

lookbook/
  base.py               Protocols + Annotation + Manifest type
  store.py              dol-backed Stores bundle, manifest codec
  _paths.py             config2py-backed default folders
  refs.py               PathImageRef, BytesImageRef, UrlImageRef
  manifest.py           Manifest helpers
  registry.py           Plugin registries
  pipeline.py           Orchestrator (topo-sorted scorers + filters + selector)
  facade.py             curate, score, curate_for_character/environment
  interactive.py        curate_interactive + InteractiveDecision
  report.py             Drop-attributing Report
  scorers/              random, resolution, file_hash, phash, blur, exposure,
                          technical_quality
                          + person.py: face detection, area, head pose, quality
                          + identity.py: cross-image identity similarity
  embedders/            mock, clip, dinov2, arcface (lazy-imported)
  filters/              min_resolution, min_blur, exposure_range, dedup
                          + person.py: has_face, single_face_only, min_face_*
  selectors/            top_k, facility_location, quota
  profiles/             person.yaml, person_mock.yaml (+ user-edited via config2py)
  diagnose.py           cluster_coverage (set-level diagnosis)
  io/                   ingest, ingest_to_store
  http.py               qh-built FastAPI surface; mk_lookbook_app, serve
  mcp.py                fastmcp-built MCP server; mk_lookbook_mcp, serve
  __main__.py           CLI (cw): curate, list-plugins, list-recipes

.claude/skills/         Claude Code skills for development & agent use
misc/docs/              Design report + development plan
tests/                  pytest, hermetic

Claude Code skills

The .claude/skills/ directory ships nine skills covering both ends of the workflow:

Dev skills (used while building / extending lookbook):

  • lookbook-dev — overall architecture, cross-references between modules
  • lookbook-storage — repository pattern, swapping storage backends
  • lookbook-add-scorer — adding a new per-image metric
  • lookbook-add-selector — adding a new set-selection algorithm
  • lookbook-profile — adding a subject profile (YAML)
  • lookbook-http — HTTP route layout + adding endpoints

Usage skills (for agents driving lookbook to curate):

  • lookbook-curate — the headline workflow
  • lookbook-diagnose — interpreting reports, querying the manifest
  • lookbook-recipe — customizing recipes per-call or via user YAML

Metadata

Release files for lookbook 0.0.12

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lookbook 0.0.12
File Size Uploaded
lookbook-0.0.12.tar.gz 138.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lookbook 0.0.12
File Interpreter ABI Platform
lookbook-0.0.12-py3-none-any.whl Python 3 none any Details

Total release size: 209.4 kB

Release files / lookbook-0.0.12.tar.gz

Download URL lookbook-0.0.12.tar.gz
Size 138.4 kB
Tags Source
SHA-256 checksum
How to use checksums
81454a2814e0182f8459bed5e6d8fa5d615c8225b44e9da27c246f3c9b192e7c
BLAKE2b-256 checksum
How to use checksums
7b944bbe8ff94b1658a56bdd2052cdfb80024779707a0c6356716c1b9d4033c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / lookbook-0.0.12-py3-none-any.whl

Download URL lookbook-0.0.12-py3-none-any.whl
Size 71.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2e6b178a2d494873cc047ca0ee384b93dfd10f985147a1cfb1f1f5222b10c4a1
BLAKE2b-256 checksum
How to use checksums
0e490724d9fda303fd7c9edb3ea9bf7fda2b2d84ab5466eebdf552472bcad18a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.0.12 This release

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

1 release file

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page