Skip to main content
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║                                                                                            ║
║                    ██████╗  █████╗ ████████╗███████╗██╗  ██╗██╗████████╗                   ║
║                   ██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝██║ ██╔╝██║╚══██╔══╝                   ║
║                   ██║  ███╗███████║   ██║   █████╗  █████╔╝ ██║   ██║                      ║
║                   ██║   ██║██╔══██║   ██║   ██╔══╝  ██╔═██╗ ██║   ██║                      ║
║                   ╚██████╔╝██║  ██║   ██║   ███████╗██║  ██╗██║   ██║                      ║
║                    ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝╚═╝  ╚═╝╚═╝   ╚═╝                      ║
║                                                                                            ║
║                           three gates a linter will not give you                           ║
║                                                                                            ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝

Three gates for defects a linter does not have an opinion about, because none of them is a syntax error. Each one exists because a real person read something and could not.

Gate Fails the build when
typefloor Type is declared below a readable floor (13px by default)
contrast-gate A declared colour cannot reach 4.5:1 on any surface the file also declares
deadname-gate A retired name reaches anything a human reads

Install

pip install legible

Use

typefloor ./src                  # every CSS and inline declaration
contrast-gate ./src              # WCAG 4.5:1 against declared surfaces
deadname-gate ./src              # a name that should be gone

Each exits non-zero on a finding and prints the file and line. --list shows every offender rather than the summary.

Why these three

typefloor. Six-point type is not a style choice. This was written after the same reader reported the same thing more than once, and the first time it was pointed at a folder it found every violation immediately — what was missing was never the tool, it was anything that pulled it.

contrast-gate. It reads CSS custom properties — --ink: #hex against --bg: #hex — and reports the best surface each ink can reach. Dark grey on navy measured 2.64:1 where body text needs 4.5, and a person found that, not a build.

It does not read literal color: declarations. A stylesheet using neither has nothing to compare, and it says so and exits 0 — which in CI reads as a pass on a site nobody checked. Pass --require-pairs to fail instead when nothing was found. The Action sets it.

deadname-gate. Fails a build when a name that should be gone reaches a title, a footer, a byline, alt text or a comment — while leaving machine identifiers alone, because renaming a repository path or a published artifact breaks working links or contradicts a deposited record. Both halves matter: a gate that cannot tell those apart gets switched off.

Written for a company rename. It is the same shape as the problem of a person changing their name and finding it in three hundred places, which is the harder version and the one worth getting right.

Exit codes

Code Means
0 Clean
1 It found something. The file and line are printed.
2 Misconfigured — it could not check, and will not report clean

The third one matters. deadname-gate forbids nothing out of the box, so a fresh install exits 2 with an explanation rather than 0. A gate that reports a pass while checking nothing is worse than no gate, and every one of these three shipped a version that did exactly that before it was caught.

Configuration

Each gate reads a JSON file of exceptions, so a deliberate choice is recorded with a reason rather than silently re-flagged.

typefloor ./src --config typefloor.json
contrast-gate ./src --config contrast.json
deadname-gate ./src --config deadname_gate.json

TYPEFLOOR_CONFIG, CONTRAST_CONFIG and DEADNAME_CONFIG do the same.

In CI

- run: pip install legible
- run: typefloor ./src
- run: contrast-gate ./src --require-pairs
- run: deadname-gate ./src

There are Actions too, in .github/actions/ of the source repository.

A note on the argument

An earlier version ignored a bare path and scanned its own directory instead, then printed OK. A gate that reports a pass on a tree it never opened is worse than no gate, so a positional path is now the root. If you pinned an earlier build, check what it is actually reading.

Licence

MIT.

Metadata

Release files for legible 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for legible 0.1.0
File Size Uploaded
legible-0.1.0.tar.gz 16.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for legible 0.1.0
File Interpreter ABI Platform
legible-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.7 kB

Release files / legible-0.1.0.tar.gz

Download URL legible-0.1.0.tar.gz
Size 16.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3b29774f2edc547dbb54c9f67bcd4061b3deb45b69ec75f284333b4a3d05068b
BLAKE2b-256 checksum
How to use checksums
2f6afef8b1d692dd00c1632cbd1304fd9f922ccdcfe3874a041e5f3a374d164d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / legible-0.1.0-py3-none-any.whl

Download URL legible-0.1.0-py3-none-any.whl
Size 16.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
37beb99f788884d8fb5b24507f7acc93d68cbc31660f414d2106871f79c11b89
BLAKE2b-256 checksum
How to use checksums
43cbbb42811847d8704175c802cf0719c4e4b8cdc54dcad0fd6a17d533480a20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page