v0.5.0Standalone binary — no Node.js required

Batch automation for professional photography workflows.

shoots is a CLI for photographers who shoot a lot and edit in Lightroom, Capture One or anything else. It is not an editor and not a catalog: it sits before and after your editor and automates the boring parts of a shoot.

curl -fsSL https://raw.githubusercontent.com/stefanopascazi/shoots/main/install.sh | bash
  • Nothing is ever deleted or overwritten
  • Everything runs locally — no cloud, no upload
  • Every command speaks --json and honours --dry-run
shoots — interactive shell
A cull run executed from the shoots interactive shell, with per-frame sharpness scores streaming into the scrollback

Real terminal capture — every screenshot on this page is generated from actual output.

Nothing is ever deleted

Originals stay untouched and edits go to sidecars. Rejects are moved, never removed; a failed checksum deletes the corrupt copy, never the source.

Everything runs locally

No cloud, no upload, no subscription. The CLIP model and the develop predictor run on your machine, from ~/.shoots.

Editor-agnostic

XMP sidecars are the interface. Lightroom, Bridge and Capture One read them — no host editor has to be installed for the engine to run.

Built to be scripted

Every command speaks --json and honours --dry-run, with meaningful exit codes, so it drops straight into scripts, cron and CI.

Focus-aware culling

A shallow-DoF portrait is mostly bokeh

A single global sharpness number throws away your best wide-open frames. Alongside it, cull builds a focus map over a tile grid and takes the sharpest region: a frame below --threshold is still kept when that peak clears --focus-threshold. Move the sliders and watch the verdicts change.

50
62
87
69
44
75
249
624
536
81
62
137
218
150
56
37
50
75
56
31
global 78.14focus peak 623.55f/1.4

Mostly bokeh: the global score is low, but the eyes are tack sharp.

--threshold100

Global Laplacian variance below this counts as blurry

--focus-threshold250

Keep a soft frame when its sharpest region clears this

$ shoots cull ./raw --threshold 100 --focus-threshold 250
verdictscorefocusaperfile
sharp412.83891.20f/2.8./raw/IMG_0001.CR3
sharp*78.14623.55f/1.4./raw/IMG_0002.CR3
blurry31.0244.18f/2.8./raw/IMG_0003.CR3
3 analyzed @ threshold 100: 2 sharp (1 rescued), 1 blurry, 0 failed

Classic computer vision — Laplacian variance plus a tile-based focus map. No model, no inference. How the scoring works →

Develop predictor

Your own develop style, learned and re-applied

It learns the global look from a catalog you have already developed and writes a per-image starting point as an XMP sidecar. It does not do local masks, generative edits or a finished image — the goal is the best starting point to refine.

Once, from a catalog you have already developed

Learn your style

Exports a training dataset from your edited photos and fits a develop profile. Under the hood: export --edited-only + train.

shoots develop init ~/Catalogs/2025

writes ~/.shoots/develop/profile/export.json

Every step accepts --dry-run. Read the predictor guide →

The surface

The 60-second tour

Every mutating command accepts --dry-run. Every command accepts --json. Nothing is ever deleted.

a full shoot, start to finish
# Install external tools and the AI model into ~/.shoots
shoots setup
# Offload a card into a dated catalog, checksum-verified
shoots import E:/DCIM/100CANON --dest D:/Shoots/2026/smith-wedding
# Stamp studio metadata onto everything
shoots exif D:/Shoots/2026/smith-wedding --set-artist "Jane Doe Photography" --set-copyright "© 2026 Jane Doe"
# Move the out-of-focus frames out of the way (keepers stay put)
shoots cull D:/Shoots/2026/smith-wedding --dest D:/Shoots/2026/smith-wedding/rejects
# Star-rate what is left, as XMP sidecars Lightroom will read
shoots rate D:/Shoots/2026/smith-wedding --profile wedding --write-xmp

Command map

  • importcard → catalog, renamed and SHA-256 verified
  • renamein-place batch rename with the same template engine
  • exifbatch read/write EXIF·IPTC·XMP via exiftool
  • cullfocus-aware blur detection; relocate or review rejects
  • rate0–5 star ratings + keywords via the ONNX CLIP model
  • embeddingsprofile-neutral CLIP export for preference learning
  • matchlearn your eye from duels → a personal rating profile

    └─ import · serve · train

  • developpersonal develop-setting predictor

    └─ init · edit · refine · export · train · predict · calibrate · diagnose

  • schedulerun develop refine daily and unattended
  • setupprovision exiftool + LibRaw + the inference model
  • doctorenvironment health check
  • updateself-update the standalone binary
  • shellthe interactive shell (default with no arguments)
Full command reference →
In the terminal

What it actually looks like

Terminal captures generated from real runs — the interactive UIs driven by keystrokes, the batch commands actually executed.

The interactive shell as it opens: wordmark, environment line, empty prompt.
The interactive shell as it opens: wordmark, environment line, empty prompt.
The project

Source-available, not open source.

shoots is licensed under the PolyForm Noncommercial 1.0.0. You are free to read, use, modify and share the source code — but only for noncommercial purposes. Any commercial use of the software, in whole or in part, is not permitted under this license.

Copyright © 2026 Stefano Pascazi. All commercial rights are reserved by the copyright holder.