Winnow
Winnow your media library — organize photos and videos, detect duplicates, and keep the best copies. Local-first, offline-capable, and designed as a greenfield rewrite of py-organizer.
Status
Pre-alpha. The published CLI is a skeleton: winnow, winnow --help, and
winnow --version are the only user-facing commands today. Domain models, exception
types, and CI are in place; scanning, deduplication, and organization workflows are
tracked in open issues (see
#2 for the parent epic).
Install
Requirements: Python 3.11+ and a package manager (uv recommended).
From PyPI
Use uv's project workflow so the dependency and command run from the same managed environment:
uv init winnow-demo
cd winnow-demo
uv add winnow-media
uv run winnow --version
Optional dependency groups (face, ai-detect) are declared in pyproject.toml but
not wired to features yet.
From source
git clone https://github.com/lgtm-hq/winnow.git
cd winnow
make setup # uv sync --dev
uv run winnow --help
Docker
docker pull ghcr.io/lgtm-hq/winnow:latest
docker run --rm ghcr.io/lgtm-hq/winnow:latest --version
Images are published to ghcr.io/lgtm-hq/winnow on merges to main and on version
tags. Platforms: linux/amd64 and linux/arm64.
Usage
Only the commands below work in the current release. There are no media-processing subcommands yet.
uv run winnow # prints version and points to --help
uv run winnow --help # show available options
uv run winnow --version # print package version
Example output:
$ uv run winnow
winnow 0.2.0 — use --help for commands.
$ uv run winnow --version
winnow, version 0.2.0
Planned usage (not implemented)
Future releases will add subcommands for scanning libraries, grouping duplicates, and
applying organization rules. Shapes will follow the domain models in winnow/models/
and the API-first plan in ADR 0001. Do not expect
the examples below to work today:
# PLANNED — not available yet
uv run winnow scan /path/to/photos
uv run winnow duplicates review
uv run winnow organize --dry-run
Features
Available now
- Skeleton CLI — Click entry point with
--helpand--version - Domain models — Pydantic v2 models for media files, duplicates, pipeline steps,
and configuration (
winnow/models/) - Exception hierarchy — structured errors with context
(
winnow/exceptions.py) - Quality bar — lintro lint/format, 85% test coverage gate, multi-version CI
Roadmap
Winnow follows an API-first, CLI-first phasing plan:
| Phase | Focus | Highlights |
|---|---|---|
| Now | Foundation | Models, CLI skeleton, CI/CD, ADRs |
| Phase 1 | Core product | Scan, dedupe, and organize via CLI and API |
| Phase 2 | Web UI | Presentation-only frontend over OpenAPI |
Planned capabilities (not shipped):
- Scan local photo and video libraries with rich metadata extraction
- Detect duplicates via perceptual hashing and related signals
- Rank and keep the best copy; organize or quarantine the rest
- Local SQLite storage; no cloud dependency required
- OpenAPI schema as the stable integration surface for automation and UI
Track progress on the issue board and in the in-repo documentation.
Development
make setup # install dev dependencies (uv sync --dev)
make lint # uv run lintro chk
make fmt # uv run lintro fmt
make test # pytest with 85% coverage gate
make test-integration # run integration tests explicitly (CI always runs them)
See CONTRIBUTING.md for commit conventions, signed commits, and PR expectations.
Documentation
License
MIT — see LICENSE.
Metadata
Release files for winnow-media 0.36.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| winnow_media-0.36.0.tar.gz | 722.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| winnow_media-0.36.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 920.3 kB
Release files / winnow_media-0.36.0.tar.gz
| Download URL | winnow_media-0.36.0.tar.gz |
|---|---|
| Size | 722.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
01308df0aac7c95c5caaeff66d12e0bcc1da59dba95f50a22ec96fa49941a467
|
|
BLAKE2b-256 checksum How to use checksums |
9e126acfcdea27fe939f9ee2bdbaf2c2b0edd104baf6ce525c6d9dd8c7d99f70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency logRelease files / winnow_media-0.36.0-py3-none-any.whl
| Download URL | winnow_media-0.36.0-py3-none-any.whl |
|---|---|
| Size | 197.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5fe31fa9875260409dbf01a280d277851971ba0480b6e19cf0a6081c68e7858a
|
|
BLAKE2b-256 checksum How to use checksums |
25cb4ff0f8ae4a83d861f44abfe9417c7da50250fa907c55a4cdc16c07ea66e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency log