Wildlife Photo Review Workflow
Wildlife Photo Review Workflow
How wildlife photos are triaged, curated, and added to the /wildlife/ gallery. This is the repeatable process to run whenever a new folder of raw photos arrives.
Canonical data model
D:\Photos\Wildlifeâ the canonical folder of curated originals. Only photos that made it into (or were reviewed for) the gallery live here. Originals never enter the git repo._data/wildlife.ymlâ single source of truth for the catalog. One entry per photo:file,date,species,scientific,group(bird | mammal | reptile | insect | amphibian | crustacean),location(""until filled),notes.images/wildlife/{web,thumb}/<file>.jpgâ derivatives (1600 px / 400 px), generated bypython scripts/build_wildlife_images.py build. The build only processes files listed in the YAML, and reads originals fromD:\Photos\Wildlife, so a selected original must be copied there first.- After any change, verify: catalog entries == web derivatives == thumb derivatives, with no orphans and nothing missing.
Progress so far (as of 2026-07-10)
| Folder | Contents | Status |
|---|---|---|
D:\Photos\Wildlife | Curated originals, DSCN0030âDSCN2218 (2026-02-04 â 2026-07-05) | Fully reviewed; 136 photos in the gallery |
D:\Photos\All_2026_06-16 | Full trip dump, 431 JPGs, DSCN1766âDSCN2216 (2026-05-28 â 2026-07-05, Outer Banks NC + South Florida) | Reviewed â 61 already-curated skipped, 370 triaged, 14 new-species photos added |
D:\Photos\All_2025-05 | ~207 JPGs, May 2025 | Not yet processed |
D:\Photos\All_2025_01-04 | ~1476 JPGs, JanâApr 2025 | Not yet processed |
âDate range processedâ = 2026-02-04 through 2026-07-05. Everything from the 2026 spring/summer trips has been reviewed. The 2025 dumps are pending.
The review pipeline (run this for each new folder)
1. Generate stubs, excluding already-reviewed photos
For every *.JPG in the new folder, make a 400 px stub â but skip any basename already present in D:\Photos\Wildlife (those were reviewed in a prior round). Also capture EXIF date_taken into a manifest for dedup context.
# 400px stub generator (run once per new folder). Note: on Windows the
# filesystem is case-insensitive, so glob EITHER "*.JPG" OR "*.jpg" â not both,
# or every file is processed twice.
from pathlib import Path
from PIL import Image
SRC = Path(r"D:\Photos\<NEW_FOLDER>"); OUT = Path(r"<scratch>\stubs")
REVIEWED = {p.stem.upper() for p in Path(r"D:\Photos\Wildlife").glob("*.JPG")}
OUT.mkdir(parents=True, exist_ok=True)
for p in sorted(SRC.glob("*.JPG")):
if p.stem.upper() in REVIEWED: continue
with Image.open(p) as im:
im.load(); s = 400/max(im.size)
(im if s>=1 else im.resize((round(im.width*s),round(im.height*s)), Image.LANCZOS)
).convert("RGB").save(OUT/f"{p.stem}.jpg","JPEG",quality=82)
2. Triage with Sonnet sub-agents
Split the stub list into batches of ~31 and dispatch one Sonnet sub-agent per batch (they run in parallel). Each agent reads its batch list + stubs and, for every file, decides:
- Is it wildlife?
- INCLUDE free-ranging wild animals of any kind, including free-living introduced/invasive species (e.g., peacocks, iguanas, Egyptian geese, Brown Anoles in Miami).
- EXCLUDE captive zoo/aquarium animals (enclosures, tanks, signage, exotic non-native captives), pets, and non-animal photos (scenery, people, food, buildings, plants).
- If wildlife: identify species, rate quality 1â5, note behavior, verdict KEEP / DROP. Relax the quality bar for rare species or rare/interesting behavior. Drop lesser duplicates within the batch.
- Give the agents the current collectionâs species list so they can flag
(common in collection)for dedup.
Output: a table File | Date | Wildlife? | Species | Quality | Verdict | Reason plus a tally. Persist each batchâs result to a scratch file (long task â guards against context loss).
3. Aggregate and dedup against the existing collection
The overriding rule is avoid duplicates with whatâs already published. In practice, only keep:
- New species not yet in the catalog, or
- A clearly superior or distinctly different shot/behavior for a species already present (be conservative â the gallery should not fill with near-dupes).
4. Verify uncertain cases on the original yourself
Do not trust sub-agent IDs blindly for anything going public. Generate ~1200 px versions of the shortlisted candidates and review them directly to: confirm the species, pick the single best frame per species, and catch misidentifications. (This round alone that caught a âBald Eagleâ that was a cormorant, a âGreat Blue Heronâ that was a female Anhinga, a âYellow-rumped Warblerâ that was a Northern Parula, and a âdeer leapâ that was feral horses.)
5. Raise borderline photos for human review (required)
Do not silently decide borderline cases. Before adding anything, present a short list to the user for a decision on every photo that is any of:
- an uncertain species ID (including ones where you overrode a sub-agent),
- a rare species/behavior kept at low quality (the relaxed-bar cases),
- a possible duplicate of a species already in the collection,
- a borderline quality call (obscured, distant, soft) that is otherwise a new species or notable shot.
Give each a one-line reason and a recommended pick, and let the user confirm, swap the frame, or drop it. Only the clearly-good, clearly-new-species photos may be added without asking. (This step matters: past rounds the user swapped in a better frame â e.g. Common Gallinule 2123 over the obscured 2122 â and chose to keep a borderline record the pipeline had set aside.)
6. Add to the collection
- Copy the selected originals from the new folder into
D:\Photos\Wildlife. - Add entries to
_data/wildlife.yml(keep it reverse-chronological;location: ""for manual fill later). python scripts/build_wildlife_images.py build- Verify counts/consistency (catalog == web == thumb, no orphans/missing).
- Commit (originals stay out of git; only YAML + derivatives are committed).
Conventions & reminders
- Quality bar: well-shot, subject prominent, in focus â except relax for rare species and rare behavior (say so in the notes when you do).
- Invasive vs zoo: free-ranging invasives are in; captive non-native zoo animals are out.
- Locations are added manually (photos have no GPS EXIF); the map shows only photos whose
locationresolves to a lat/lng in thelocations:table. - No Ruby/Jekyll on this machine â verify the GitHub Pages build after pushing rather than rendering locally.
