# Share a Ruff Report as HTML — SARIF In, One Link Out

Canonical: https://commareports.com/share-ruff-report
Published: 2026-08-31

> Ruff has no HTML writer, but it emits SARIF and JUnit. Convert either, publish the page to Comma, and the Python lint backlog becomes a URL people can triage on.

# Share a Ruff report as HTML

Ruff is fast enough that teams run it on everything, which is exactly how you
end up with a backlog of a few thousand findings and no good way to talk about
them. It has no HTML writer — but it has SARIF, and SARIF converts.

## SARIF → HTML

```bash
pip install ruff sarif-tools

ruff check . --output-format=sarif > ruff.sarif || true
sarif html ruff.sarif --output ruff.html
```

SARIF keeps the rule id, severity and code region for every finding, so the
converted page is a real triage surface rather than a flattened list.

## Or JUnit → HTML

If your image already has `junit2html` for test reports, reuse it:

```bash
pip install junit2html
ruff check . --output-format=junit > ruff-junit.xml || true
junit2html ruff-junit.xml ruff.html
```

Less detail, one fewer dependency.

Either way `|| true` matters — `ruff check` exits non-zero whenever it finds
anything, and you want the report on exactly those runs.

## Publish it

Drag `ruff.html` into [the app](https://commareports.com/), or from CI:

```bash
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 ruff.html \
        --arg title "Ruff — $GITHUB_REF_NAME" '{title: $title, html: $html}')"
```

Keep `ruff check .` as a separate, unmuted step if you want the build to fail;
the report step should never be the gate.

## Turning the backlog into work

PATCH one report id per repo and you get a stable URL whose revision history
is the cleanup record. Then:

- **Anchored threads** on a rule cluster — "we're disabling `ANN` project-wide,
  here's why" — recorded next to the findings instead of only in
  `pyproject.toml`. See [commenting on HTML](/comment-on-html).
- **A [routine](/features/routines/scheduled-html-reports)** that re-runs
  weekly, so the number moving is visible without anyone maintaining it.

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, 250 MB and 500 files total.
  A first-run report on a big legacy codebase is the one that gets close —
  scope it with `--select` for the shareable view.
- **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 Pylint report](/share-pylint-report) · [Share an ESLint report](/share-eslint-report)
- [Share a Bandit report](/share-bandit-report) · [Share a Semgrep report](/share-semgrep-report)
- [Scheduled reports](/features/routines/scheduled-html-reports) · [Publish from CI](/docs/ci)
