
When Good Enough Ships: Automating Image Quality in Python Packages
Example content is a great way to showcase a Plone add-on — until the images bundled with it quietly bloat your Python package. This is how we automated the fix.
At kitconcept, we build and maintain several Plone add-ons and distributions. To showcase them properly, we create example content — and that example content comes with images. Beautiful, full-resolution, completely overkill images. Over time, those images quietly bloated our Python packages to a point where something had to be done. This post is about how we tackled the problem, why we published the solution as an open source GitHub Action even though it's far from perfect, and why automating quality checks is almost always better than trusting that people (yourself included) will always notice the problem manually.
The Problem Nobody Talks About
When you develop a Plone add-on or distribution, you often ship example content alongside the code. That content is meant to give developers a quick, realistic preview of what the product looks like in action — a populated site, some demo pages, a few images to avoid the dreaded grey-box placeholder.
The problem is that the images that look great on a live demo website are not the images you want bundled inside a Python package that someone downloads with pip install. A 6 MB JPG of a happy team in a meeting room might be entirely appropriate for a public website. It is absolutely not appropriate as part of a development scaffold.
We noticed this issue at kitconcept while working on our Plone distributions. Repository size crept up. Package downloads became slower. And because no single commit was responsible — the bloat accumulated gradually, image by image, PR by PR — there was no obvious moment where someone said "wait, this is too much."
That's the thing about gradual problems: they don't fail loudly. They fail slowly.
The Human Element Problem
Once we identified the issue, the tempting first solution was the obvious one: let's just be careful from now on. We'll review images before committing them. We'll remember to resize things. We'll have a checklist.
This kind of solution works for exactly one sprint. Then life happens — deadlines, context switches, a new developer onboarding — and the next 4 MB PNG lands in the repository unnoticed.
The hard truth is that relying on human alertness for repetitive quality checks is not a sustainable strategy. Not because people are careless, but because our attention is a finite and valuable resource. Every mental check we're expected to do manually is one more thing competing for focus that should be going elsewhere.
The right answer is automation. Not because humans are bad at this, but because machines are much better at it, and they don't get tired.
Introducing kitconcept/image-checker
So we built kitconcept/image-checker: a GitHub Action that validates image files in a repository against configurable size and dimension constraints.
The premise is simple. You define your limits — maximum file size, maximum width and height, even minimum values if you want — and the action checks every image in the paths you specify. If something doesn't meet the criteria, it tells you. And if you want, it can also block the PR entirely.
A basic configuration looks like this:
- name: Check images
uses: kitconcept/[email protected]
with:
file-extensions: 'jpg,png'
paths: 'src/plonetheme.mytheme/static, docs'
max-size: '2097152' # 2 MB
max-width: '1920'
max-height: '1080'That's it. Drop this into a workflow and you have an automated guard at the gate.
The fail-on-error Setting: Start Gentle, Then Enforce
One of the most useful configuration options is fail-on-error. By default it's set to true, which means that any violation will cause the workflow to fail and block the PR. That's exactly what you want once your repository is in a known-good state.
But what if you're adding this to an existing repository that already has some images that don't meet your intended standards? Blocking every PR until all historical images are fixed is not a great way to introduce a new tool to your team.
This is where fail-on-error: false becomes valuable. With this setting, the action runs its checks and reports all violations in the GitHub Step Summary — a clean, readable overview of every file that didn't pass and why — but it does not fail the workflow. PRs go through, work continues, and the team gets visibility into what needs to be cleaned up, without being blocked.
- name: Check images
uses: kitconcept/[email protected]
with:
paths: 'src/content'
max-size: '2097152'
fail-on-error: 'false' # Report issues without blocking PRsThink of it as a migration mode: run in warning mode first, fix the existing issues at your own pace, and then flip fail-on-error back to true once everything is clean. This makes adoption much smoother, especially in established projects with a long history.
On Shipping Imperfect Things
I want to be honest: kitconcept/image-checker is not a finished product. It does what it was designed to do, and it does it well enough to be useful. But there are features it doesn't have yet, edge cases we haven't handled, and improvements that could be made.
We shipped it anyway.
I've seen too many useful internal tools die in a private repository because the team was waiting until it was "ready." Ready for what, exactly, is rarely specified. The result is that something genuinely useful never reaches the people who could benefit from it.
Open source is built on the principle that sharing an imperfect solution is almost always better than hoarding a perfect one that doesn't exist yet. If kitconcept/image-checker saves someone else the work of building the same thing from scratch, that's a win. If someone finds a bug and opens an issue, that's also a win. If someone contributes a feature we hadn't thought of, that's the best possible outcome.
The barrier to publishing something useful should be: does it work? does it solve a real problem? — not is it perfect?
kitconcept/image-checker is available at github.com/kitconcept/image-checker and on the GitHub Actions Marketplace. It's MIT licensed, and contributions are welcome.
If you've been dealing with repository bloat from large image assets — in Plone projects or anywhere else — give it a try. And if you find something that could be better, let us know.