TL;DR: DockRx analyzes Dockerfiles and explains size, caching, and security problems with actionable fixes — not just lint warnings. You get a health score, quick wins, estimated impact, and (for a subset of rules) non-destructive auto-fixes. Install with pip install dockrx or uv tool install dockrx. Try the playground with no install at dockrx.vercel.app. v0.1.1 is on PyPI and GitHub Releases.
This post covers the problem, the product, how we built it with AI without shipping slop, and what the first release does not do yet.
The loop I was tired of
Most Dockerfile “optimization” still looks like this:
- Paste a Dockerfile into a linter
- Get a wall of rule IDs and style nits
- Guess which ones actually matter for image size / cache / security
- Rewrite by hand, hope you didn’t break something
- Rebuild and wait
- Repeat
Tools like Hadolint are excellent at linting Dockerfiles — especially shell hygiene inside RUN. They still tend to stop at warnings, not treatment. You leave knowing something is wrong, not what to do first or what you’ll get back.
I wanted something closer to a diagnosis:
Analyze → score the patient → show the highest-ROI fixes → preview treatment → compare before/after.
That became DockRx.
What DockRx does
At a high level:
parse Dockerfile → instruction graph
↓
run hybrid rules (YAML + Python plugins)
↓
score findings (overall + categories)
↓
render diagnosis (health, quick wins, lost points, estimates)
↓
optional: explain / fix / suggest / compare / badge / format
Install
Requires Python 3.12+.
uv tool install dockrx
# or: pipx install dockrx
# or: pip install dockrx
From GitHub (repo name is docrx; the CLI/package is dockrx):
git clone https://github.com/kiwi-07/docrx.git
cd docrx
uv sync
uv run dockrx --version
Basic usage
dockrx analyze .
dockrx analyze Dockerfile --json
dockrx analyze . --score-only
dockrx explain DRX018
dockrx fix . --dry-run --yes
dockrx compare before/ after/
dockrx badge . --format markdown
dockrx suggest . --yes
dockrx format Dockerfile --check
Useful commands:
| Command | Meaning |
|---|---|
analyze |
Full health report (or --json / --score-only / --badge) |
explain |
Deep dive on a rule ID |
fix |
Non-destructive rewrite to Dockerfile.fixed (subset of rules) |
suggest |
Walk fixes interactively |
compare |
Before/after score and finding deltas |
badge |
SVG / markdown / shields-style badge |
format |
Style formatter (--check / --diff / --write) |
Try it without installing
Paste a Dockerfile into the live playground:
The web UI is intentionally analyze-only. The CLI still owns fix / compare / badge / format and project-context checks (like whether a .dockerignore exists).
Try the bundled example
git clone https://github.com/kiwi-07/docrx.git
cd docrx
uv sync
uv run dockrx analyze examples/test
You should see something like:
Overall Health
█████████░░░░░░░░░░░
47 / 100
Needs Attention · Grade: F (Poor)
Quick Wins
1. Switch JDK → JRE runtime ↓ ~100–300 MB 2 min
2. Add .dockerignore ↑ 20-70% 30 sec
3. Remove debug networking tools ↓ ~15–80 MB 1 min
There’s a terminal capture of this flow in the README.
From 47 to 85 with one command
Analysis is only half the point. Here’s the same example after dockrx fix --yes, which rewrites a subset of rules into Dockerfile.fixed (your original is never touched):
# prepare runtime env
-FROM eclipse-temurin:21-jdk-jammy
+FROM eclipse-temurin:21-jre-jammy
LABEL maintainer="Example Team <maintainer@example.com>"
RUN apt-get update && apt-get install -y --no-install-recommends \
- iputils-ping \
- telnet \
curl \
wget \
- traceroute \
- netcat \
- net-tools \
iproute2 \
- dnsutils \
&& rm -rf /var/lib/apt/lists/*
-ENTRYPOINT exec java $JAVA_OPTS -jar /opt/app/service-events/service-events.jar
+RUN useradd --system --create-home appuser && chown -R appuser:appuser /opt/app
+USER appuser
+RUN printf '%s\n' '#!/bin/sh' 'exec java $JAVA_OPTS -jar /opt/app/service-events/service-events.jar' > /entrypoint.sh && chmod +x /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
Plus a generated .dockerignore. Re-analyze the result and the score moves the way you’d hope:
47 / 100 → 85 / 100 (applied: DRX018, DRX005, DRX019, DRX003, DRX023)
JDK → JRE, debug tooling out of the runtime image, a non-root user, an exec-form entrypoint, and a .dockerignore — the five highest-ROI fixes, previewed before anything is written.
What it finds on real projects
To keep myself honest, I ran DockRx against 18 Dockerfiles from popular open-source projects (Grafana, Keycloak, Gitea, Prometheus, Traefik, MinIO, and friends). The spread:
| Metric | Value |
|---|---|
| Best | filebrowser — 99 |
| Worst | keycloak — 47 |
| Median | 73 |
| Average | 72 |
| Scoring below 70 | 6 of 18 |
The most common findings weren’t exotic: missing non-root USER, :latest/untagged bases, missing HEALTHCHECK, and debug tooling shipped into runtime images — the boring stuff linters mention but rarely prioritize. The full regenerated scoreboard lives in examples/realworld/RESULTS.md.
(Scores use DockRx’s “spill” model and are deliberately harsher than a naive lint count.)
Design choices that matter
1. Diagnosis over lint spam
A finding without impact ranking is noise. DockRx leads with overall health, grade, quick wins, lost points, and estimated results — then the detailed ROI-ranked list. The goal is “what should I do in the next 10 minutes?”, not “here are 40 rule IDs.”
2. Hybrid rule engine
Simple patterns live as YAML. Messier logic (stage-aware checks, package-manager cache order, JDK-in-runtime heuristics) lives as Python plugins. Teams can override either via .dockrx/rules and .dockrx/plugins.
3. Fixes are non-destructive by default
dockrx fix writes Dockerfile.fixed. It never overwrites your original unless you opt into something like format --write. That made it safe to ship auto-fixes early without pretending every rule is auto-fixable.
4. Estimates are labeled as heuristic
Size and build-time numbers are not measured from real builds in Milestone 1. The report says so. Shipping fake precision would be worse than shipping honest heuristics.
5. Exit codes are a public contract
--json, --score-only, and --badge are mutually exclusive. Empty/invalid Dockerfiles exit 2. Unknown explain IDs exit 1. Non-TTY fix/suggest refuse to prompt. CI should be able to trust the CLI without reading the human report.
6. Scoring must move when you fix something
An early scoring bug floored category scores at zero and hid further progress. The spill model counts every finding toward the overall score, so fixing anything always moves the number. Category displays stay floored at 0.
7. Hadolint is a partner, not a rival
DockRx is not trying to replace Hadolint’s shell linting. The pairing that actually works:
- Hadolint for deep Dockerfile + shell linting
- DockRx for prioritization, explainability, fixes, and team-facing UX
DockRx is also not a CVE scanner.
MVP scope (honest)
Supported in v0.1.x:
- Static Dockerfile parsing into an instruction graph
- Built-in YAML rules + Python plugins (~27 rule IDs)
- Rich terminal diagnosis + JSON for CI
analyze/explain/fix/suggest/compare/badge/format- Project-local rule/plugin overrides
- GitHub Action with PR commenting + severity gate
- Live playground + small public HTTP API
Not yet (intentional cuts, not forever):
- Measured image/layer sizes from real builds
- Full auto-fix coverage for every rule
- Remote rule packs
- VS Code extension
- HTML reports as a first-class product surface
If a Dockerfile is empty or missing FROM, we fail loudly — never invent a “clean” report.
If you want to contribute, the highest-value areas are richer auto-fixes, measured metrics, and more language/ecosystem cache rules. File issues or PRs against develop on github.com/kiwi-07/docrx.
How AI helped build this (without becoming the product)
I built DockRx with Cursor as a pair programmer — not as an autopilot that one-prompted a repo onto PyPI.
What AI was good at
- Scaffolding the Typer CLI surface once the command set was decided
- Rule/plugin boilerplate and presentation metadata
- Test suites once success criteria were explicit (exit codes, scoring spill, API validation)
- Release choreography: README/docs accuracy, CHANGELOG, Vercel playground, packaging, tags
What AI was not allowed to own alone
- Product thesis — “doctor, not linter” came from the pain of warning-only tools
- Scope cuts — analyze-only web UI; CLI keeps the sharp tools
- Failure semantics — exit codes, invalid Dockerfile handling, non-TTY refusal
- QA — treat the agent like a junior: prescribe smoke tests, re-run, demand fixes, re-verify against real-world Dockerfiles
The workflow that actually worked
- Write a short product brief (problem, non-goals, CLI UX)
- Let the agent implement against that brief
- Run a prescribed QA matrix myself (CLI + UI + real-world examples)
- Feed failures back as concrete bugs
- Re-run the same matrix until green
- Only then: docs, playground link, PyPI, branch protection
AI compressed calendar time. It did not remove engineering judgment. The quality bar was: would I trust this on a laptop while reviewing a teammate’s Dockerfile?
If you’re shipping with agents, the underrated skill is writing acceptance tests and invariants the agent can fail against. Vague “make Docker better” prompts produce demos. Explicit “exit 2 on invalid FROM / never overwrite without --write / fixing must move overall score” prompts produce tools.
Architecture sketch
Rough module map under src/dockrx/:
| Module | Role |
|---|---|
cli.py |
Typer entrypoint |
parser/ |
Dockerfile → instruction graph |
engine/ |
Rule loading + runner |
rules/builtin/ |
YAML rule definitions |
plugins/ |
Python checks |
scoring/ |
Severity → health score |
reporters/ |
Rich / JSON / compare / explain / badge |
fixer.py |
Deterministic non-destructive fixes |
formatter.py |
Dockerfile style formatter |
Plus a small FastAPI surface in api/ for the playground.
Repo defaults:
- Day-to-day work on
develop - Releases via PR into
main, then tag (v0.1.0,v0.1.1, …) - Branch protection on
main(PR + review)
Release checklist we used for v0.1.x
- Fix CLI/API QA gaps and regenerate real-world scoreboard
- Document exit codes and the public web API
- Sanitize demo fixtures and scrub private paths from git history
- Merge
develop→main - Tag
v0.1.0, publish to PyPI, verify install - Patch
v0.1.1for corrected author metadata - Verify:
uvx --from dockrx dockrx --version
Links:
- Repo: https://github.com/kiwi-07/docrx
- PyPI: https://pypi.org/project/dockrx/
- Playground: https://dockrx.vercel.app
- Releases: https://github.com/kiwi-07/docrx/releases
Who should try it today
Good fit if you:
- Care about image size, cache order, and runtime hardening — not only style lint
- Want prioritized fixes you can explain to a teammate
- Already use Hadolint (or want something that pairs with it)
- Prefer a CLI-first tool with an optional playground
Wait (or open an issue) if you need measured layer sizes from real builds, full auto-fix coverage, or a VS Code extension on day one.
Closing
DockRx is small on purpose. The bet is that prioritized diagnosis is more valuable than pretending to be a full Docker platform on the first release.
If you try it on a real Dockerfile and it breaks in an interesting way, please file an issue — that feedback is how the roadmap gets ordered.
uv tool install dockrx
dockrx analyze .
# or just paste into https://dockrx.vercel.app
Thanks for reading — and if you build with AI too: keep the taste and the tests human.