Imported from andrewmy/gallinor (
AGENTS.md). Install upstream withnpx skills add andrewmy/gallinor. Copyright stays with the author.
AGENTS.md
Concise development guide for this repository.
Project Snapshot
Gallinor is a PHP 8.5+ CLI for reducing media size while preserving quality.
- Video: re-encode to HEVC (NVENC / Apple VideoToolbox / Intel Quick Sync / CPU fallback), validate with VMAF.
- Images: JPEG -> HEIC (SSIMULACRA2 threshold), archive ARW with xz.
Primary contexts:
src/Video/*src/Images/*src/Shared/*
Architecture is clean/DDD-ish per context:
Domain/Infrastructure/Ui/Cli/
Daily Commands
composer install
just ci
just stan
just test
just smoke
just cbf
just markdown
php app.php help
Common app flows:
php app.php videos:squeeze <path> [--force-any-bitrate]
php app.php videos:rename <path>
php app.php images:squeeze <path> [--parallel] [--concurrency=N | --adaptive-concurrency=N]
php app.php images:remove-originals <path>
Hard Constraints
- PHP 8.5+ with strict types.
- Native runtime targets: macOS + Windows (
Platformguards this). - Linux is supported via Docker workflows.
- Docker GPU wrappers:
./bin/docker-run.sh --nvidia ...for NVENC./bin/docker-run.sh --intel ...for Quick Sync (/dev/dri, Linux host)
- Runtime expects ffmpeg v8+.
- Domain flows should report operational failures via result objects where already modeled (avoid widening exception-driven control flow).
- Keep constructor injection/manual wiring in
app.php(no DI container).
Video Rules To Preserve
- Quality gate: VMAF threshold is 90.
- Skip files that already have
.optimal.mp4(default command behavior). - Skip bitrate-acceptable sources by default; allow explicit override via
--force-any-bitrate. - Bitrate search behavior:
- start from resolution base bitrate
- adaptive upward retries on VMAF fail
- downward probing on headroom
- stop downward probing early when pass lands in
[90, 91] - midpoint fail/pass refinement to avoid >10% overshoot
- VFR/rotation safety:
- use
-fps_mode passthrough - keep source stream as VMAF reference with decode-order alignment (
settb=AVTB,setpts=N) - use CPU encoder for rotated sources when active encoder is NVENC (to avoid HW QC drift)
- allow Apple VideoToolbox/Intel Quick Sync for rotated sources
- use
- Hardware flags must be capability-gated by encoder help output (NVENC, VideoToolbox, and QSV options vary by ffmpeg build).
- VideoToolbox keeps
-maxrateenabled and leaves reference-frame selection on encoder auto. - Quick Sync keeps
-maxrateenabled and enables quality knobs only when exposed by the active ffmpeg build. - VMAF requires
libvmaffilter availability (notvmafmotion).
Image Rules To Preserve
- JPEG quality search targets SSIMULACRA2 >= 85.
- Orientation normalization is explicit and deterministic (avoid double-rotation drift).
- Metadata verification stays strict for core capture/user metadata.
- If metadata verification behavior changes:
- add failing test first in
tests/Unit/Images/Domain/StrictMetadataVerifierTest.php - then update
src/Images/Domain/StrictMetadataVerifier.phpwith brief rationale.
- add failing test first in
- Parallel mode applies to JPEG optimization only; ARW archival remains sequential.
Testing + Validation
- Unit tests:
tests/Unit/ - Smoke tests:
tests/Smoke/(run viajust smoke) - Prefer
FsTestCasefor filesystem-dependent tests. - Test doubles preference:
- local stubs
TestHandlerfor logs- Mockery when needed
After meaningful code changes:
- Run
just ci.
Markdown-only changes:
- Run
just markdown(notjust ci).
If style fails:
just cbf
just ci
Documentation Sync
When behavior/tooling/CLI semantics change, update docs in the same change:
README.mdAGENTS.md(this file)- relevant docs under
docs/
Keep docs aligned with actual code paths, option names, and thresholds.
Adding A New CLI Command
- Add command class in
src/{Context}/Ui/Cli/. - Use
#[AsCommand(name: '...')]. - Implement
__invoke(OutputInterface $output, ...): int. - Use
CliHelper::startCommand()prelude. - Wire dependencies and register in
app.php.