# Share a flake8 HTML Report — A Backlog People Can Claim

Canonical: https://commareports.com/share-flake8-report
Published: 2026-09-14

> flake8-html turns a wall of terminal output into a browsable per-file report. Publish it to Comma: one URL, comments on the violations worth fixing, a revision per run.

# Share a flake8 HTML report

Lint output is the least-read text in software. `flake8 src/` prints four
thousand lines, CI folds them into a log nobody expands, and the accumulated
result is a codebase where everyone knows there is a lint backlog and nobody
knows what is in it.

The fix is not a stricter gate. It is making the backlog something a person can
look at and take a piece of.

```bash
pip install flake8-html
flake8 --format=html --htmldir=flake-report src/
```

```
flake-report/
├── index.html          # files ranked by violation count
├── src.app.views.html  # one page per file, violations in context
└── styles.css
```

## Publish the folder

Drag `flake-report/` (or a zip of it) into
[Comma](https://commareports.com/):

- `index.html` becomes the **report body** — the ranked file list.
- Per-file pages and the stylesheet upload alongside it, with relative
  references rewritten to the uploaded copies, so the drill-down works.
- Scripts run inside a sandboxed iframe (`allow-scripts`, no
  `allow-same-origin`).

One URL. No artifact download, no CI login, no Python environment needed by the
person reading it — which matters, because the person who should decide whether
`C901` complexity warnings are worth fixing is often a tech lead who is not
going to install your dev dependencies to find out.

## From CI

```bash
flake8 --format=html --htmldir=flake-report src/ || true

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html flake-report/index.html \
        --arg t "Lint backlog — $(git rev-parse --short HEAD)" \
        '{title: $t, html: $html}')"
```

`|| true` because flake8 exits non-zero whenever it finds anything, and the run
that found something is the run worth publishing. Supporting pages go up
through `POST /api/v1/reports/$REPORT_ID/assets` as base64 — see the
[API reference](/docs/api) and [publishing from CI](/docs/ci).

## Two gates, one report

The pattern that works on a legacy codebase:

- **Gate on the diff.** `flake8 --diff` against the merge base, failing on
  anything new. Nobody argues with that.
- **Publish the whole report.** One permanent URL, PATCHed every run,
  revisions showing the total moving.

The second is what turns "we should clean up lint sometime" into a list with
owners. Anchored comments — "taking E501 in `views/`", "these E731s are
deliberate, see the ADR" — keep the claims and the exemptions on the rows they
apply to rather than in a spreadsheet. See
[commenting on HTML](/comment-on-html).

## Who can see it

Per report: private, your team, anyone signed in at your domain, or anyone with
the link. A lint report exposes file structure and source excerpts, so team
access is usually right. See [sharing & access control](/docs/sharing).

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, **250 MB and 500 files total**.
  flake8-html writes a page per offending file — past 500, publish the index
  alone or scope the run to a package.
- **Scripts run, sandboxed** — no same-origin access.
- **60 requests/minute per token.**

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision
history.

**[Publish a lint report →](https://commareports.com/)**

### Related

- [Share a Ruff report](/share-ruff-report) · [Share a pylint report](/share-pylint-report)
- [Share a mypy HTML report](/share-mypy-report) · [Share a Bandit report](/share-bandit-report)
- [Share an ESLint report](/share-eslint-report) · [Share a SonarQube report](/share-sonarqube-report)
