Folder → browser contact sheet → keyboard CULL → XMP sidecars → keepers export. For one small wedding or a big family shoot.
- Up to 750 JPEG/PNG per run
- Stars 1-5 · x reject · RYGBP labels
- Keepers copy, originals untouched
XMP Originals safe
You came home with 3000 frames. The CULL is the unpaid shift — every image, one decision, stars, color, reject. We make that pass fast: a keyboard-driven contact sheet in your browser, every keypress saved instantly as a standard XMP sidecar. Then one command copies your keepers out.
Operated by OpenCode Studio. No fake freelancer identity or invented work history. No AI auto-reject — you CULL, we remember.
Powered by products/photo-cull-bundle — 21/21 round-trip PASS (XMP sidecars + SHA-256 identical keepers). Reuse, not rebuild.
All three run the same local contact sheet + XMP writer + keeper export. No cloud, no account, Python 3.10+.
Folder → browser contact sheet → keyboard CULL → XMP sidecars → keepers export. For one small wedding or a big family shoot.
XMP Originals safe
Most weddings. Same workflow, bigger batch, subfolders preserved.
Best for 1500-frame evenings.
Double-shooter weddings + second card. Batch export with suffix renaming.
Rejected (-1) never exported. Ever.
.xmp next to each CULLed photo (+ .CR2.xmp beside same-named RAW siblings) + --export keepers copies into <shoot>_keepers with folder structure preserved. No overwrite of originals.Contact sheet as you CULL it, an XMP file as Lightroom sees it, and the keeper folder after export. All from a real 12-shot round-trip.
CULL · keyboard — j/k move · 1-5 stars · x reject · RYGBP label · v zoom
Live counts: picked · rejected · total. Served at 127.0.0.1, offline.
Keys: j/k move 1-5 stars x reject G green
Standard XMP · what we write next to your file
File: WED-0100.xmp beside WED-0100.jpg — Lightroom / Bridge read this.
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Photo-Cull Bundle 1.0">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<xmp:Rating>5</xmp:Rating>
<photoshop:Label>Green</photoshop:Label>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
independent_read("WED-0100.xmp")
# → {"rating": 5, "label": "Green"}
# same as products/photo-cull-bundle/scripts/killtest_roundtrip.py
# regex cross-check: <xmp:Rating>5</xmp:Rating>Keepers · after --export keepers --min-stars 4 --suffix
Rejected WED-0105 never arrives. Structure preserved (sub/ stays sub/). Every copy SHA-256 identical to source.
sha256(WED-0100.jpg) == sha256(keepers/WED-0100-cull5G.jpg) # pass sha256(sub/WED-0111.jpg) == sha256(keepers/sub/WED-0111-cull4.jpg) # pass
ROUNDTRIP-RESULT.md — same 12-shot plan the kill test uses. No stock photos, no fake testimonials.We only write .xmp sidecars + copies to _keepers. Never moves, never renames, never edits a source pixel. Delete the .xmp to clear, delete .photocull_cache any time — it rebuilds.
This version has no AI that silently rates or hides photos. You CULL. A wrong auto-reject can throw away the only shot of a moment — we won't build that.
Contact sheet is served on 127.0.0.1 only (no DNS lookup, no internet). JPEG/PNG today; RAW preview decoding phase-2 — but RAW+JPEG pairs get a .CR2.xmp sibling automatically so catalogs see it.
.xmp was already there, we back it up once as .xmp.photocull-backup.CULL FORGE reuses products/photo-cull-bundle verbatim — same photocull.py, same XMP writer, same keepers export. The number is real.
12 generated shots (incl. 1 nested sub/, 1 PNG, 1 fake .CR2 sibling) → tags through real CLI → independent XML+regex reader → --export keepers → SHA-256 identical copies.
python scripts/killtest_roundtrip.py
# → 21/21 PASS (ROUNDTRIP-RESULT.md)
Result: Verdict PASS, 2026-08-27, Pillow 12.3.0, 0 failed.
10 sidecars round-tripped: 5 Green, 4, 3 Yellow, 2, 1 Purple, reject -1, 5 Red, 4 Blue, nested — plus 2 clears left no file. RAW sibling got identical 5 Green. Rejected & below-threshold never exported, structure preserved.
Every exported keeper SHA-256 matches source — the files that arrive are the files that left.
Static site only. Reuses sites/_theme/bridges.css (system fonts, no CDN) + beacon.js (dormant, cookieless). No framework, no CMS, no DB, no tracking.
Fewest files wins: 7 HTML files total. Disclosure before any price — this page passes the gate.
One folder → CULL → keepers. If it saves you one late night, it paid for itself.
Questions? Read Disclosure and Privacy first — they answer price and data in one minute. Or see the 3 samples again →