Apply professional-grade color grading to camera photos via RawTherapee CLI, driven by JSON parameters.
RawTherapee CLI is the sole processing engine, providing:
FeatureRawTherapeeDemosaicingMulti-algorithm (AMAZE, IGT, etc.)SharpeningRL Deconvolution (Richardson-Lucy)Noise ReductionIWT / astronomy denoiseLens Correctionlensfun autoColor ManagementProPhoto internal pipelineCamera MatchingAuto-Matched Curve (~50 cameras)Output QualityProfessional
All RAW formats: NEF, CR2, CR3, ARW, RAF, ORF, RW2, DNG, PEF, SRW, 3FR, IIQ, X3F, etc. Plus: JPEG (.jpg/.jpeg) and Apple HEIC/HEIF (.heic/.heif).
Note: RAW files provide full 16-bit editing latitude for maximum quality. JPG/HEIC are 8-bit — grading range is more limited, exposure adjustments should be more conservative.
Declaration file: requirements.txt
Prefer venv: Before running scripts, activate the project-root virtual environment (e.g. .venv/). If it doesn't exist, create one first:
bash
# Create venv and install dependencies (recommended)
python3 -m venv .venv
source .venv/bin/activate
pip install -r photo-grader/requirements.txt
# Or use the skill's setup script (checks + installs)
bash photo-grader/scripts/setup_deps.sh
# Before each session, activate venv
source .venv/bin/activate
bash
# macOS
# Install RawTherapee from the official package, then copy the standalone
# rawtherapee-cli into a directory in PATH (for example ~/.local/bin).
rawtherapee-cli -h # verify it prints "RawTherapee, version ..., command line"
# Debian / Ubuntu
sudo apt install rawtherapee-cli
# Fedora / RHEL
sudo dnf install RawTherapee
macOS note: always verify with
rawtherapee-cli -h. If it exits with133/SIGTRAP, macOS likely blocked it before startup. This is common when an agent installs RawTherapee via Homebrew and the user has not explicitly opened/authorized the app or CLI yet. A user-installed and authorized Homebrew CLI can work; otherwise use the official standalonerawtherapee-clifrom the RawTherapee package.
Copy config.example.toml to config.toml and edit to set your directories. See config.example.toml for all available options.
bash
# With absolute paths in grading_params.json (--raw-dir not needed)
python3 scripts/grade.py grading_params.json --output ~/Photos/graded
# With relative filenames in params (needs --raw-dir)
python3 scripts/grade.py grading_params.json \
--raw-dir ~/Photos/RAW --output ~/Photos/graded
# Full resolution
python3 scripts/grade.py grading_params.json --no-resize
# Uniform mode: apply one parameter set to ALL files in a directory
# (useful for timelapse or batch-processing with identical settings)
python3 scripts/grade.py grading_params.json \
--uniform-dir ~/data/timelapse --output ~/data/output/graded
# Preview
python3 scripts/grade.py grading_params.json --dry-run
# Export PP3 only (for manual inspection or external use)
python3 scripts/grade.py grading_params.json --pp3-only --pp3-output ./pp3_files/
# Fast export mode (skip heavy modules for speed)
python3 scripts/grade.py grading_params.json --fast-export
# Control lens correction and camera matching
python3 scripts/grade.py grading_params.json --lens-corr
python3 scripts/grade.py grading_params.json --no-lens-corr
python3 scripts/grade.py grading_params.json --auto-match
python3 scripts/grade.py grading_params.json --no-auto-match
OptionDescriptionDefaultparams_jsonGrading parameters JSONrequired--raw-dirRAW files directory (only needed for relative paths)from config--uniform-dirApply first param set to ALL files in directory—--outputOutput directoryfrom config--qualityJPEG quality (1-100)95--workersParallel workersauto (max 8)--overwriteOverwrite existing filesoff--dry-runPreview onlyoff--pp3-onlyOnly generate PP3 files, don't renderoff--pp3-outputDirectory for PP3-only output./pp3/``--fast-exportUse RT fast export mode (skip heavy modules)off--lens-corrEnable/disable lens correctionfrom config--auto-matchEnable/disable Auto-Matched Camera Curvefrom config
Note:
--uniform-dirignores thefilefield in the JSON and applies the first parameter set to every supported photo in the directory. Useful for timelapse sequences where all frames share one grading preset.
All standard Lightroom parameters are supported with intelligent mapping:
The find_raw_file() function intelligently matches filenames across camera brands and formats:
grading_params.json has "file": "/path/to/DSC_0001.NEF" and the file exists, it's used directly"file": "DSC_0001.NEF", searches under --raw-dir by stem name--raw-dir, the output filename gets a prefix: 001_DSC_0001_暖春丝滑.jpgStem-based matching works across formats:
grading_params.json says DSC_0001.NEF but the actual file is DSC_0001.CR2, it will still be foundIMG_0001.HEIC or DSC_0001.JPGbash scripts/setup_deps.shphoto-toolkit firstphoto_curator_prompt.md prompt with multimodal LLMpython3 scripts/grade.py grading_params.json --raw-dir ... --output ...