a11y-toolkit 3.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- a11y_toolkit-3.3.0/LICENSE +21 -0
- a11y_toolkit-3.3.0/PKG-INFO +188 -0
- a11y_toolkit-3.3.0/README.md +167 -0
- a11y_toolkit-3.3.0/a11y.py +53 -0
- a11y_toolkit-3.3.0/a11y_toolkit.egg-info/PKG-INFO +188 -0
- a11y_toolkit-3.3.0/a11y_toolkit.egg-info/SOURCES.txt +20 -0
- a11y_toolkit-3.3.0/a11y_toolkit.egg-info/dependency_links.txt +1 -0
- a11y_toolkit-3.3.0/a11y_toolkit.egg-info/entry_points.txt +6 -0
- a11y_toolkit-3.3.0/a11y_toolkit.egg-info/top_level.txt +12 -0
- a11y_toolkit-3.3.0/a11yaudit.py +828 -0
- a11y_toolkit-3.3.0/a11ybadge.py +89 -0
- a11y_toolkit-3.3.0/a11ybudget.py +119 -0
- a11y_toolkit-3.3.0/a11ycrit.py +250 -0
- a11y_toolkit-3.3.0/a11ydiff.py +181 -0
- a11y_toolkit-3.3.0/a11ydom.py +563 -0
- a11y_toolkit-3.3.0/a11ysarif.py +138 -0
- a11y_toolkit-3.3.0/arialive_js.py +104 -0
- a11y_toolkit-3.3.0/contrast.py +437 -0
- a11y_toolkit-3.3.0/declaracion.py +256 -0
- a11y_toolkit-3.3.0/pyproject.toml +39 -0
- a11y_toolkit-3.3.0/server.py +508 -0
- a11y_toolkit-3.3.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jesús Quintana Fernández
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a11y-toolkit
|
|
3
|
+
Version: 3.3.0
|
|
4
|
+
Summary: The accessibility layer for AI coding agents — MCP server + CLI for WCAG 2.2: express static audit, rendered audit (contrast, 2.5.8 target size, focus), contrast math (pairs, CSS names, hsl/rgba, text-over-image pixel sampling), EAA/RD 1112/2018 declarations, snapshot regression diffs, aria-live monitor. Zero dependencies at core; es/en.
|
|
5
|
+
Author: Jesús Quintana Fernández
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kinti/a11y-toolkit
|
|
8
|
+
Project-URL: Issues, https://github.com/kinti/a11y-toolkit/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/kinti/a11y-toolkit/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: mcp,accessibility,a11y,wcag,wcag22,contrast,audit,eaa,ada,screen-reader,playwright,ai-agents
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# a11y-toolkit — the accessibility layer for AI coding agents
|
|
23
|
+
|
|
24
|
+
[](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
|
|
25
|
+
[](https://pypi.org/project/a11y-toolkit/)
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
[](pyproject.toml)
|
|
28
|
+
[](https://modelcontextprotocol.io)
|
|
29
|
+
[](https://smithery.ai)
|
|
30
|
+
|
|
31
|
+
**12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
|
|
32
|
+
Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
|
|
33
|
+
its core; every finding ships with a concrete remediation your agent can apply.
|
|
34
|
+
|
|
35
|
+
Accessibility is not optional anymore: the **European Accessibility Act is in force since
|
|
36
|
+
June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
|
|
37
|
+
makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
|
|
38
|
+
|
|
39
|
+
## What no other a11y tool gives an agent
|
|
40
|
+
|
|
41
|
+
| Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
|
|
44
|
+
| Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
|
|
45
|
+
| **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
|
|
46
|
+
| **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
|
|
47
|
+
| **Focus-order regression detection** | ✗ | ✓ |
|
|
48
|
+
| Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
|
|
49
|
+
| Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
|
|
50
|
+
| **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
|
|
51
|
+
| **Criterion explanations** on demand for agents | ✗ | ✓ |
|
|
52
|
+
| Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
|
|
53
|
+
| Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
|
|
54
|
+
|
|
55
|
+
## The tools (10)
|
|
56
|
+
|
|
57
|
+
| Tool | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `a11y_audit_url` | Express static WCAG audit of a URL **or raw HTML**: 20+ signals with a **weighted 0-100 score** (alt, accessible names, labels, autocomplete 1.3.5, keyboard onclick, unknown ARIA roles, broken aria-labelledby, unnamed duplicated landmarks, meta refresh, skip mechanism, lang validity, title, headings, blocked zoom, captions, autoplay audio, generic/duplicated link text, target=_blank warnings, tabindex>0, aria-hidden-on-focusable, tables, duplicate ids, accesskeys). Per-finding remediation. |
|
|
60
|
+
| `a11y_audit_dom` | **Rendered audit** (local Playwright/Chromium): real computed text contrast vs effective backgrounds with alpha compositing (1.4.3), minimum target size 24×24 (**2.5.8 — new in WCAG 2.2**), focus-indicator heuristic (2.4.7), all static checks on the live DOM. |
|
|
61
|
+
| `a11y_contrast_pair` | Exact ratio + verdicts 1.4.3/1.4.6/1.4.11. Accepts `#hex`, `rgb()`, `hsl()`, **CSS color names**; alpha composites over the background. Suggests the nearest passing color. |
|
|
62
|
+
| `a11y_contrast_image` | **Text over images**: pixel-level sampling of the actual background → worst/median/p95 ratio, % area passing AA, hostile-zone detection on a 3×3 grid. |
|
|
63
|
+
| *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
|
|
64
|
+
| `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
|
|
65
|
+
| `a11y_generate_declaration` | Legal accessibility statement in HTML: RD 1112/2018 art. 10 (Spanish public sector) or **European Accessibility Act** wording (Directive (EU) 2019/882 / Ley 11/2023). es/en. The document is itself accessible. |
|
|
66
|
+
| `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
|
|
67
|
+
| `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
|
|
68
|
+
| `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
|
|
69
|
+
| `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
|
|
70
|
+
| `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
|
|
71
|
+
| `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
|
|
72
|
+
|
|
73
|
+
**Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
|
|
74
|
+
what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
|
|
75
|
+
`declaration-eaa` (collects legal fields, generates).
|
|
76
|
+
|
|
77
|
+
## Install
|
|
78
|
+
|
|
79
|
+
**Claude Code** (one command):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"a11y-toolkit": {
|
|
91
|
+
"command": "uvx",
|
|
92
|
+
"args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
|
|
93
|
+
"timeoutMs": 60000
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Or from the repo without publishing:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{ "mcpServers": { "a11y-toolkit": {
|
|
103
|
+
"command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The rendered audit, snapshots and diffs use Playwright **if present**
|
|
107
|
+
(`pip install playwright && playwright install chromium`); everything else works with
|
|
108
|
+
zero dependencies.
|
|
109
|
+
|
|
110
|
+
### The skill (teaches your agent when/how to use all of this)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
|
|
114
|
+
./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## CLI — same engine, one command
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
|
|
121
|
+
a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
|
|
122
|
+
a11y audit --url https://example.com --lang en # express static audit
|
|
123
|
+
a11y declaration --entidad "Acme" --url https://acme.example \
|
|
124
|
+
--estado parcial --marco eaa --lang en --output decl.html
|
|
125
|
+
a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
|
|
126
|
+
a11y diff before.json after.json # after deploy
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
|
|
130
|
+
a11y-toolkit a11y …`.
|
|
131
|
+
|
|
132
|
+
### Watch it continuously (the deployment gate)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
a11y audit --url https://mysite --pages 5 > audit.json # light crawl
|
|
136
|
+
python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
|
|
137
|
+
a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
|
|
138
|
+
a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
|
|
142
|
+
on regressions and publishes the SARIF to code scanning.
|
|
143
|
+
|
|
144
|
+
## Honesty, built in
|
|
145
|
+
|
|
146
|
+
Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
|
|
147
|
+
bundled skill then have the agent check what it *can* (keyboard operability, focus
|
|
148
|
+
visibility, zoom reflow, announced errors) using
|
|
149
|
+
[the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
|
|
150
|
+
recommend a screen-reader pass for the rest. A filter, not a verdict.
|
|
151
|
+
|
|
152
|
+
## Security & scope
|
|
153
|
+
|
|
154
|
+
A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
|
|
155
|
+
(statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
|
|
156
|
+
machine except the URL you explicitly audit.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
|
|
165
|
+
(trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
|
|
166
|
+
[Smithery](https://smithery.ai) too. Contributions welcome — see
|
|
167
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
|
|
168
|
+
es/en strings everywhere, honest scope notes).
|
|
169
|
+
|
|
170
|
+
## Roadmap
|
|
171
|
+
|
|
172
|
+
- [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
|
|
173
|
+
- [x] 0-100 weighted score · ARIA validity · criterion explanations
|
|
174
|
+
- [x] Computed accessibility tree in snapshots + tree diff
|
|
175
|
+
- [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
|
|
176
|
+
- [x] Honest dated badge as accessible SVG (`a11y_badge`)
|
|
177
|
+
- [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
|
|
178
|
+
- [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
|
|
179
|
+
- [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
|
|
180
|
+
- [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
|
|
181
|
+
- [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Author
|
|
186
|
+
|
|
187
|
+
**Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
|
|
188
|
+
web-accessibility practitioner since 2003. MIT © 2026.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# a11y-toolkit — the accessibility layer for AI coding agents
|
|
2
|
+
|
|
3
|
+
[](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/a11y-toolkit/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](pyproject.toml)
|
|
7
|
+
[](https://modelcontextprotocol.io)
|
|
8
|
+
[](https://smithery.ai)
|
|
9
|
+
|
|
10
|
+
**12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
|
|
11
|
+
Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
|
|
12
|
+
its core; every finding ships with a concrete remediation your agent can apply.
|
|
13
|
+
|
|
14
|
+
Accessibility is not optional anymore: the **European Accessibility Act is in force since
|
|
15
|
+
June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
|
|
16
|
+
makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
|
|
17
|
+
|
|
18
|
+
## What no other a11y tool gives an agent
|
|
19
|
+
|
|
20
|
+
| Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
|
|
23
|
+
| Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
|
|
24
|
+
| **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
|
|
25
|
+
| **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
|
|
26
|
+
| **Focus-order regression detection** | ✗ | ✓ |
|
|
27
|
+
| Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
|
|
28
|
+
| Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
|
|
29
|
+
| **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
|
|
30
|
+
| **Criterion explanations** on demand for agents | ✗ | ✓ |
|
|
31
|
+
| Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
|
|
32
|
+
| Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
|
|
33
|
+
|
|
34
|
+
## The tools (10)
|
|
35
|
+
|
|
36
|
+
| Tool | What it does |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `a11y_audit_url` | Express static WCAG audit of a URL **or raw HTML**: 20+ signals with a **weighted 0-100 score** (alt, accessible names, labels, autocomplete 1.3.5, keyboard onclick, unknown ARIA roles, broken aria-labelledby, unnamed duplicated landmarks, meta refresh, skip mechanism, lang validity, title, headings, blocked zoom, captions, autoplay audio, generic/duplicated link text, target=_blank warnings, tabindex>0, aria-hidden-on-focusable, tables, duplicate ids, accesskeys). Per-finding remediation. |
|
|
39
|
+
| `a11y_audit_dom` | **Rendered audit** (local Playwright/Chromium): real computed text contrast vs effective backgrounds with alpha compositing (1.4.3), minimum target size 24×24 (**2.5.8 — new in WCAG 2.2**), focus-indicator heuristic (2.4.7), all static checks on the live DOM. |
|
|
40
|
+
| `a11y_contrast_pair` | Exact ratio + verdicts 1.4.3/1.4.6/1.4.11. Accepts `#hex`, `rgb()`, `hsl()`, **CSS color names**; alpha composites over the background. Suggests the nearest passing color. |
|
|
41
|
+
| `a11y_contrast_image` | **Text over images**: pixel-level sampling of the actual background → worst/median/p95 ratio, % area passing AA, hostile-zone detection on a 3×3 grid. |
|
|
42
|
+
| *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
|
|
43
|
+
| `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
|
|
44
|
+
| `a11y_generate_declaration` | Legal accessibility statement in HTML: RD 1112/2018 art. 10 (Spanish public sector) or **European Accessibility Act** wording (Directive (EU) 2019/882 / Ley 11/2023). es/en. The document is itself accessible. |
|
|
45
|
+
| `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
|
|
46
|
+
| `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
|
|
47
|
+
| `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
|
|
48
|
+
| `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
|
|
49
|
+
| `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
|
|
50
|
+
| `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
|
|
51
|
+
|
|
52
|
+
**Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
|
|
53
|
+
what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
|
|
54
|
+
`declaration-eaa` (collects legal fields, generates).
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
**Claude Code** (one command):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"a11y-toolkit": {
|
|
70
|
+
"command": "uvx",
|
|
71
|
+
"args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
|
|
72
|
+
"timeoutMs": 60000
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or from the repo without publishing:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{ "mcpServers": { "a11y-toolkit": {
|
|
82
|
+
"command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The rendered audit, snapshots and diffs use Playwright **if present**
|
|
86
|
+
(`pip install playwright && playwright install chromium`); everything else works with
|
|
87
|
+
zero dependencies.
|
|
88
|
+
|
|
89
|
+
### The skill (teaches your agent when/how to use all of this)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
|
|
93
|
+
./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CLI — same engine, one command
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
|
|
100
|
+
a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
|
|
101
|
+
a11y audit --url https://example.com --lang en # express static audit
|
|
102
|
+
a11y declaration --entidad "Acme" --url https://acme.example \
|
|
103
|
+
--estado parcial --marco eaa --lang en --output decl.html
|
|
104
|
+
a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
|
|
105
|
+
a11y diff before.json after.json # after deploy
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
|
|
109
|
+
a11y-toolkit a11y …`.
|
|
110
|
+
|
|
111
|
+
### Watch it continuously (the deployment gate)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
a11y audit --url https://mysite --pages 5 > audit.json # light crawl
|
|
115
|
+
python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
|
|
116
|
+
a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
|
|
117
|
+
a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
|
|
121
|
+
on regressions and publishes the SARIF to code scanning.
|
|
122
|
+
|
|
123
|
+
## Honesty, built in
|
|
124
|
+
|
|
125
|
+
Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
|
|
126
|
+
bundled skill then have the agent check what it *can* (keyboard operability, focus
|
|
127
|
+
visibility, zoom reflow, announced errors) using
|
|
128
|
+
[the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
|
|
129
|
+
recommend a screen-reader pass for the rest. A filter, not a verdict.
|
|
130
|
+
|
|
131
|
+
## Security & scope
|
|
132
|
+
|
|
133
|
+
A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
|
|
134
|
+
(statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
|
|
135
|
+
machine except the URL you explicitly audit.
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
|
|
144
|
+
(trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
|
|
145
|
+
[Smithery](https://smithery.ai) too. Contributions welcome — see
|
|
146
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
|
|
147
|
+
es/en strings everywhere, honest scope notes).
|
|
148
|
+
|
|
149
|
+
## Roadmap
|
|
150
|
+
|
|
151
|
+
- [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
|
|
152
|
+
- [x] 0-100 weighted score · ARIA validity · criterion explanations
|
|
153
|
+
- [x] Computed accessibility tree in snapshots + tree diff
|
|
154
|
+
- [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
|
|
155
|
+
- [x] Honest dated badge as accessible SVG (`a11y_badge`)
|
|
156
|
+
- [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
|
|
157
|
+
- [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
|
|
158
|
+
- [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
|
|
159
|
+
- [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
|
|
160
|
+
- [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Author
|
|
165
|
+
|
|
166
|
+
**Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
|
|
167
|
+
web-accessibility practitioner since 2003. MIT © 2026.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""a11y — un solo comando para todo el toolkit.
|
|
3
|
+
|
|
4
|
+
a11y pair "#texto" "#fondo" [--lang es|en]
|
|
5
|
+
a11y image ruta.jpg --text "#ffffff" [--region x,y,w,h] [--sample 4]
|
|
6
|
+
a11y audit --url https://cliente.web | --file pagina.html
|
|
7
|
+
a11y declaration --entidad "Nome" --url https://… --estado parcial [opciones]
|
|
8
|
+
a11y snapshot https://miweb --out antes.json # requiere Playwright
|
|
9
|
+
a11y diff antes.json despues.json
|
|
10
|
+
a11y audit --url https://web --pages 5 # crawl ligero mismo dominio
|
|
11
|
+
a11y sarif --url https://web -o a11y.sarif # para GitHub code scanning
|
|
12
|
+
a11y badge --score 92 --lang en --out badge.svg # insignia SVG honesta
|
|
13
|
+
a11y budget --budget budget.json --audit hoy.json # solo lo NUEVO bloquea
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
import a11yaudit
|
|
19
|
+
import a11ybadge
|
|
20
|
+
import a11ybudget
|
|
21
|
+
import a11ycrit
|
|
22
|
+
import a11ydiff
|
|
23
|
+
import a11ysarif
|
|
24
|
+
import contrast
|
|
25
|
+
import declaracion
|
|
26
|
+
|
|
27
|
+
SUBCOMANDOS = {
|
|
28
|
+
'pair': (contrast, 'pair'),
|
|
29
|
+
'image': (contrast, 'image'),
|
|
30
|
+
'audit': (a11yaudit, None),
|
|
31
|
+
'declaration': (declaracion, None),
|
|
32
|
+
'snapshot': (a11ydiff, 'snapshot'),
|
|
33
|
+
'diff': (a11ydiff, 'diff'),
|
|
34
|
+
'criterion': (a11ycrit, None),
|
|
35
|
+
'sarif': (a11ysarif, None),
|
|
36
|
+
'badge': (a11ybadge, None),
|
|
37
|
+
'budget': (a11ybudget, None),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main(argv=None):
|
|
42
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
43
|
+
if not argv or argv[0] in ('-h', '--help') or argv[0] not in SUBCOMANDOS:
|
|
44
|
+
print(__doc__)
|
|
45
|
+
print('Subcomandos disponibles:', ', '.join(SUBCOMANDOS))
|
|
46
|
+
return 0 if argv and argv[0] in ('-h', '--help') else 1
|
|
47
|
+
modulo, sub = SUBCOMANDOS[argv[0]]
|
|
48
|
+
args = ([sub] + argv[1:]) if sub else argv[1:]
|
|
49
|
+
return modulo.main(args)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == '__main__':
|
|
53
|
+
sys.exit(main())
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a11y-toolkit
|
|
3
|
+
Version: 3.3.0
|
|
4
|
+
Summary: The accessibility layer for AI coding agents — MCP server + CLI for WCAG 2.2: express static audit, rendered audit (contrast, 2.5.8 target size, focus), contrast math (pairs, CSS names, hsl/rgba, text-over-image pixel sampling), EAA/RD 1112/2018 declarations, snapshot regression diffs, aria-live monitor. Zero dependencies at core; es/en.
|
|
5
|
+
Author: Jesús Quintana Fernández
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kinti/a11y-toolkit
|
|
8
|
+
Project-URL: Issues, https://github.com/kinti/a11y-toolkit/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/kinti/a11y-toolkit/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: mcp,accessibility,a11y,wcag,wcag22,contrast,audit,eaa,ada,screen-reader,playwright,ai-agents
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# a11y-toolkit — the accessibility layer for AI coding agents
|
|
23
|
+
|
|
24
|
+
[](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
|
|
25
|
+
[](https://pypi.org/project/a11y-toolkit/)
|
|
26
|
+
[](LICENSE)
|
|
27
|
+
[](pyproject.toml)
|
|
28
|
+
[](https://modelcontextprotocol.io)
|
|
29
|
+
[](https://smithery.ai)
|
|
30
|
+
|
|
31
|
+
**12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
|
|
32
|
+
Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
|
|
33
|
+
its core; every finding ships with a concrete remediation your agent can apply.
|
|
34
|
+
|
|
35
|
+
Accessibility is not optional anymore: the **European Accessibility Act is in force since
|
|
36
|
+
June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
|
|
37
|
+
makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
|
|
38
|
+
|
|
39
|
+
## What no other a11y tool gives an agent
|
|
40
|
+
|
|
41
|
+
| Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
|
|
44
|
+
| Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
|
|
45
|
+
| **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
|
|
46
|
+
| **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
|
|
47
|
+
| **Focus-order regression detection** | ✗ | ✓ |
|
|
48
|
+
| Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
|
|
49
|
+
| Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
|
|
50
|
+
| **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
|
|
51
|
+
| **Criterion explanations** on demand for agents | ✗ | ✓ |
|
|
52
|
+
| Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
|
|
53
|
+
| Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
|
|
54
|
+
|
|
55
|
+
## The tools (10)
|
|
56
|
+
|
|
57
|
+
| Tool | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `a11y_audit_url` | Express static WCAG audit of a URL **or raw HTML**: 20+ signals with a **weighted 0-100 score** (alt, accessible names, labels, autocomplete 1.3.5, keyboard onclick, unknown ARIA roles, broken aria-labelledby, unnamed duplicated landmarks, meta refresh, skip mechanism, lang validity, title, headings, blocked zoom, captions, autoplay audio, generic/duplicated link text, target=_blank warnings, tabindex>0, aria-hidden-on-focusable, tables, duplicate ids, accesskeys). Per-finding remediation. |
|
|
60
|
+
| `a11y_audit_dom` | **Rendered audit** (local Playwright/Chromium): real computed text contrast vs effective backgrounds with alpha compositing (1.4.3), minimum target size 24×24 (**2.5.8 — new in WCAG 2.2**), focus-indicator heuristic (2.4.7), all static checks on the live DOM. |
|
|
61
|
+
| `a11y_contrast_pair` | Exact ratio + verdicts 1.4.3/1.4.6/1.4.11. Accepts `#hex`, `rgb()`, `hsl()`, **CSS color names**; alpha composites over the background. Suggests the nearest passing color. |
|
|
62
|
+
| `a11y_contrast_image` | **Text over images**: pixel-level sampling of the actual background → worst/median/p95 ratio, % area passing AA, hostile-zone detection on a 3×3 grid. |
|
|
63
|
+
| *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
|
|
64
|
+
| `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
|
|
65
|
+
| `a11y_generate_declaration` | Legal accessibility statement in HTML: RD 1112/2018 art. 10 (Spanish public sector) or **European Accessibility Act** wording (Directive (EU) 2019/882 / Ley 11/2023). es/en. The document is itself accessible. |
|
|
66
|
+
| `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
|
|
67
|
+
| `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
|
|
68
|
+
| `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
|
|
69
|
+
| `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
|
|
70
|
+
| `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
|
|
71
|
+
| `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
|
|
72
|
+
|
|
73
|
+
**Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
|
|
74
|
+
what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
|
|
75
|
+
`declaration-eaa` (collects legal fields, generates).
|
|
76
|
+
|
|
77
|
+
## Install
|
|
78
|
+
|
|
79
|
+
**Claude Code** (one command):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"a11y-toolkit": {
|
|
91
|
+
"command": "uvx",
|
|
92
|
+
"args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
|
|
93
|
+
"timeoutMs": 60000
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Or from the repo without publishing:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{ "mcpServers": { "a11y-toolkit": {
|
|
103
|
+
"command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The rendered audit, snapshots and diffs use Playwright **if present**
|
|
107
|
+
(`pip install playwright && playwright install chromium`); everything else works with
|
|
108
|
+
zero dependencies.
|
|
109
|
+
|
|
110
|
+
### The skill (teaches your agent when/how to use all of this)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
|
|
114
|
+
./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## CLI — same engine, one command
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
|
|
121
|
+
a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
|
|
122
|
+
a11y audit --url https://example.com --lang en # express static audit
|
|
123
|
+
a11y declaration --entidad "Acme" --url https://acme.example \
|
|
124
|
+
--estado parcial --marco eaa --lang en --output decl.html
|
|
125
|
+
a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
|
|
126
|
+
a11y diff before.json after.json # after deploy
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
|
|
130
|
+
a11y-toolkit a11y …`.
|
|
131
|
+
|
|
132
|
+
### Watch it continuously (the deployment gate)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
a11y audit --url https://mysite --pages 5 > audit.json # light crawl
|
|
136
|
+
python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
|
|
137
|
+
a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
|
|
138
|
+
a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
|
|
142
|
+
on regressions and publishes the SARIF to code scanning.
|
|
143
|
+
|
|
144
|
+
## Honesty, built in
|
|
145
|
+
|
|
146
|
+
Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
|
|
147
|
+
bundled skill then have the agent check what it *can* (keyboard operability, focus
|
|
148
|
+
visibility, zoom reflow, announced errors) using
|
|
149
|
+
[the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
|
|
150
|
+
recommend a screen-reader pass for the rest. A filter, not a verdict.
|
|
151
|
+
|
|
152
|
+
## Security & scope
|
|
153
|
+
|
|
154
|
+
A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
|
|
155
|
+
(statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
|
|
156
|
+
machine except the URL you explicitly audit.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
|
|
165
|
+
(trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
|
|
166
|
+
[Smithery](https://smithery.ai) too. Contributions welcome — see
|
|
167
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
|
|
168
|
+
es/en strings everywhere, honest scope notes).
|
|
169
|
+
|
|
170
|
+
## Roadmap
|
|
171
|
+
|
|
172
|
+
- [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
|
|
173
|
+
- [x] 0-100 weighted score · ARIA validity · criterion explanations
|
|
174
|
+
- [x] Computed accessibility tree in snapshots + tree diff
|
|
175
|
+
- [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
|
|
176
|
+
- [x] Honest dated badge as accessible SVG (`a11y_badge`)
|
|
177
|
+
- [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
|
|
178
|
+
- [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
|
|
179
|
+
- [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
|
|
180
|
+
- [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
|
|
181
|
+
- [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Author
|
|
186
|
+
|
|
187
|
+
**Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
|
|
188
|
+
web-accessibility practitioner since 2003. MIT © 2026.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
a11y.py
|
|
4
|
+
a11yaudit.py
|
|
5
|
+
a11ybadge.py
|
|
6
|
+
a11ybudget.py
|
|
7
|
+
a11ycrit.py
|
|
8
|
+
a11ydiff.py
|
|
9
|
+
a11ydom.py
|
|
10
|
+
a11ysarif.py
|
|
11
|
+
arialive_js.py
|
|
12
|
+
contrast.py
|
|
13
|
+
declaracion.py
|
|
14
|
+
pyproject.toml
|
|
15
|
+
server.py
|
|
16
|
+
a11y_toolkit.egg-info/PKG-INFO
|
|
17
|
+
a11y_toolkit.egg-info/SOURCES.txt
|
|
18
|
+
a11y_toolkit.egg-info/dependency_links.txt
|
|
19
|
+
a11y_toolkit.egg-info/entry_points.txt
|
|
20
|
+
a11y_toolkit.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|