a11y-loop 0.1.0

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.
Files changed (36) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +409 -0
  3. package/THIRD-PARTY-NOTICES.md +32 -0
  4. package/package.json +51 -0
  5. package/skill/a11y-loop/SKILL.md +332 -0
  6. package/skill/a11y-loop/evals/evals.json +168 -0
  7. package/skill/a11y-loop/evals/trigger-evals.json +20 -0
  8. package/skill/a11y-loop/references/ai-failure-modes.md +272 -0
  9. package/skill/a11y-loop/references/apg-patterns.md +264 -0
  10. package/skill/a11y-loop/references/manual-testing.md +224 -0
  11. package/skill/a11y-loop/references/wcag22-quick-ref.md +224 -0
  12. package/src/cli.js +207 -0
  13. package/src/commands/audit.js +125 -0
  14. package/src/commands/contrast.js +141 -0
  15. package/src/commands/diff.js +65 -0
  16. package/src/lib/axe-runner.js +400 -0
  17. package/src/lib/browser-utils.js +221 -0
  18. package/src/lib/checks/dialog.js +341 -0
  19. package/src/lib/checks/div-button.js +87 -0
  20. package/src/lib/checks/focus-visible.js +296 -0
  21. package/src/lib/checks/keyboard.js +235 -0
  22. package/src/lib/checks/link-text.js +83 -0
  23. package/src/lib/checks/reduced-motion.js +139 -0
  24. package/src/lib/checks/reflow.js +101 -0
  25. package/src/lib/checks/target-size.js +128 -0
  26. package/src/lib/contrast-math.js +189 -0
  27. package/src/lib/diff.js +118 -0
  28. package/src/lib/finding.js +164 -0
  29. package/src/lib/fingerprint.js +0 -0
  30. package/src/lib/format/checklist.js +281 -0
  31. package/src/lib/format/human.js +175 -0
  32. package/src/lib/format/json.js +139 -0
  33. package/src/lib/format/sarif.js +111 -0
  34. package/src/lib/serve.js +189 -0
  35. package/src/lib/suggest-color.js +169 -0
  36. package/src/lib/wcag-map.js +271 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chan Meng
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.
22
+
package/README.md ADDED
@@ -0,0 +1,409 @@
1
+ <!-- AGENT-FIRST NOTICE -->
2
+ > [!IMPORTANT]
3
+ > ### ๐Ÿค– Read this with your AI agent โ€” don't read it by hand.
4
+ > This repo is written agent-first. Point Claude Code, GitHub Copilot, Cursor, or any agent at it:
5
+ > *"Read the README and AGENTS.md, then help me run / extend this."*
6
+ > Structure + [`AGENTS.md`](AGENTS.md) are optimized for agent comprehension.
7
+ <!-- /AGENT-FIRST NOTICE -->
8
+
9
+ <div align="center"><a name="readme-top"></a>
10
+
11
+ # ๐Ÿ” a11y-loop
12
+
13
+ ### Write accessible UI by default. Verify it in a real browser. Say exactly what you couldn't check.
14
+
15
+ a11y-loop makes AI coding agents write accessible UI by default, then proves what it can prove
16
+ with a real browser audit across the states it built โ€” and tells you exactly what it could not
17
+ check.
18
+
19
+ [Demo GIF][demo-link] ยท [SKILL.md][docs-link] ยท [Benchmark](evals/benchmark-results.md) ยท [Changelog](CHANGELOG.md) ยท [Report Bug](https://github.com/ChanMeng666/a11y-loop/issues) ยท [Request Feature](https://github.com/ChanMeng666/a11y-loop/issues)
20
+
21
+ <!-- SHIELD GROUP -->
22
+
23
+ [![License](https://img.shields.io/github/license/ChanMeng666/a11y-loop?style=flat-square)](LICENSE)
24
+ [![Contributors](https://img.shields.io/github/contributors/ChanMeng666/a11y-loop?style=flat-square)](https://github.com/ChanMeng666/a11y-loop/graphs/contributors)
25
+ [![Forks](https://img.shields.io/github/forks/ChanMeng666/a11y-loop?style=flat-square)](https://github.com/ChanMeng666/a11y-loop/network/members)
26
+ [![Stars](https://img.shields.io/github/stars/ChanMeng666/a11y-loop?style=flat-square)](https://github.com/ChanMeng666/a11y-loop/stargazers)
27
+ [![Issues](https://img.shields.io/github/issues/ChanMeng666/a11y-loop?style=flat-square)](https://github.com/ChanMeng666/a11y-loop/issues)
28
+ [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-EA4AAA?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/ChanMeng666)
29
+
30
+ ![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=nodedotjs&logoColor=white)
31
+ ![Playwright](https://img.shields.io/badge/Playwright-2EAD33?style=flat-square&logo=playwright&logoColor=white)
32
+ ![axe--core](https://img.shields.io/badge/axe--core-4.12-662D91?style=flat-square)
33
+ ![WCAG 2.2 AA](https://img.shields.io/badge/WCAG-2.2%20AA-1a73e8?style=flat-square)
34
+ ![Agent Skills](https://img.shields.io/badge/Agent%20Skills-open%20standard-000?style=flat-square)
35
+
36
+ </div>
37
+
38
+ <details>
39
+ <summary><kbd>๐Ÿ“‘ Table of Contents</kbd></summary>
40
+
41
+ - [๐ŸŒŸ Introduction](#-introduction)
42
+ - [๐ŸŽฌ Demo](#-demo)
43
+ - [โœจ Key Features](#-key-features)
44
+ - [๐Ÿ“Š Honest Coverage](#-honest-coverage)
45
+ - [๐Ÿ“ˆ Benchmark](#-benchmark)
46
+ - [๐Ÿ› ๏ธ Tech Stack](#-tech-stack)
47
+ - [๐Ÿ—๏ธ Architecture](#-architecture)
48
+ - [๐Ÿš€ Getting Started](#-getting-started)
49
+ - [โš™๏ธ Using it in CI](#-using-it-in-ci)
50
+ - [๐Ÿ“– Usage Guide](#-usage-guide)
51
+ - [โŒจ๏ธ Development](#-development)
52
+ - [๐Ÿค Contributing](#-contributing)
53
+ - [โค๏ธ Sponsor](#-sponsor)
54
+ - [๐Ÿ“„ License](#-license)
55
+ - [๐Ÿ™‹โ€โ™€๏ธ Author](#-author)
56
+
57
+ </details>
58
+
59
+ ## ๐ŸŒŸ Introduction
60
+
61
+ AI coding agents write inaccessible UI by default โ€” 84% of AI-generated web pages carry
62
+ accessibility issues (W4A'24), and telling the model to "be accessible" barely moves that number:
63
+ accessibility-oriented prompts have measured a *slightly higher* violation rate than
64
+ accessibility-agnostic ones (W4A'25, 17.32% vs. 15.93%). Instructions alone are not the fix.
65
+
66
+ a11y-loop is two things working together:
67
+
68
+ 1. **An Agent Skill** โ€” standing generation rules (semantic HTML first, ARIA discipline, APG
69
+ keyboard contracts, labels, focus visibility, AA contrast in light and dark, reduced motion,
70
+ 24ร—24 targets) that apply while the agent is writing UI code.
71
+ 2. **A Node CLI** (`a11y-loop audit` / `contrast --fix` / `diff`) that verifies the result in a
72
+ real browser, feeds failures back to the agent to fix, and re-audits until the loop converges.
73
+
74
+ The skill follows the open [Agent Skills](https://agentskills.io/specification) standard, so the
75
+ same `SKILL.md` is portable across 40+ clients โ€” Claude Code, Cursor, GitHub Copilot, Codex,
76
+ Gemini CLI, and more โ€” not just one vendor's agent. The CLI runs the same checks standalone in CI
77
+ or any other pipeline.
78
+
79
+ It was built for the **My Life My Voice** accessibility challenge, run by a disability
80
+ organization in Aotearoa New Zealand, where the NZ Government Web Accessibility Standard 1.2 has
81
+ mandated WCAG 2.2 AA since 17 March 2025. The idea: give AI coding agents a way to build
82
+ accessibility in from the start, instead of treating it as a compliance afterthought bolted on
83
+ after the fact. a11y-loop has no affiliation with My Life My Voice or the NZ government beyond
84
+ having been built for that challenge.
85
+
86
+ **What this is not.** a11y-loop does not claim compliance, does not guarantee accessibility, and
87
+ does not replace manual testing or testing with assistive technology. A clean report means "no
88
+ automatically detectable failures" โ€” see [Honest Coverage](#-honest-coverage) below for exactly
89
+ what that does and doesn't cover.
90
+
91
+ ## ๐ŸŽฌ Demo
92
+
93
+ ![a11y-loop fixing a seeded-violation demo page across five audit passes until it converges on zero violations](docs/demo.gif)
94
+
95
+ The demo page ([`demo/before/`](demo/before)) is a fictional conference site seeded with
96
+ **163 detectable failures** spanning the WebAIM Million's top six failure classes plus the
97
+ failure modes documented for LLM-generated UI: clickable divs, hidden focus indicators, skipped
98
+ heading levels, broken ARIA references, and ignored `prefers-reduced-motion`. Running the loop
99
+ against it converges on [`demo/after/`](demo/after) โ€” **0 violations** โ€” and
100
+ `a11y-loop diff --before demo/before/report.json --after demo/after/report.json` reports:
101
+
102
+ ```
103
+ Converged: all 163 violations fixed, none introduced
104
+ ```
105
+
106
+ `FIXED` / `NEW` / `REMAINING` status per finding, matched by stable fingerprint (rule + selector +
107
+ WCAG success criterion), is what makes that verdict checkable rather than asserted โ€” see
108
+ [`demo/before/VIOLATIONS.md`](demo/before/VIOLATIONS.md) and
109
+ [`demo/after/FIXES.md`](demo/after/FIXES.md) for the finding-by-finding record.
110
+
111
+ ## โœจ Key Features
112
+
113
+ `1` **Five rendering passes per audit** โ€” default (1280ร—720), dark mode, forced-colors mode,
114
+ reduced-motion, and a 320ร—256 reflow viewport (the WCAG-sanctioned 400% zoom equivalent for
115
+ SC 1.4.10) โ€” because most real failures only show up under a specific rendering condition, not on
116
+ a single default-viewport load.
117
+
118
+ `2` **Checks axe-core can't run** โ€” tab order, focus visibility (including focus-ring contrast),
119
+ dialog focus trap / Escape / focus-return, target size (24ร—24 CSS px, SC 2.5.8), reduced-motion
120
+ effectiveness, ambiguous link text, div-as-button, and positive `tabindex`. These sit alongside
121
+ axe-core, not instead of it.
122
+
123
+ `3` **State coverage, not just page-load** โ€” `--interact` drives the states an agent just built
124
+ (a modal opened, a menu expanded, a form in its error state) through the same five passes, because
125
+ axe running once on page load finds nothing in a dialog that only misbehaves once it's open.
126
+
127
+ `4` **Stable fingerprints power regression detection** โ€” `a11y-loop diff` matches findings across
128
+ two reports by rule + selector + WCAG success criterion and classifies each as FIXED, NEW
129
+ (a regression โ€” this fails the command even if the total count went down), or REMAINING.
130
+
131
+ `5` **Structured, honest output** โ€” JSON is the primary format: every finding carries its WCAG
132
+ success criterion, ACT rule ID where one exists, and a provenance block (axe-core version, browser,
133
+ URL, viewport, timestamp, states exercised). SARIF v2.1 is available as a secondary format with
134
+ [a documented limitation](#-honest-coverage) rather than a silent gap. A generated manual-review
135
+ checklist, scoped to what was actually built, ships with every run.
136
+
137
+ `6` **Exit codes are the loop's contract** โ€” `0` no violations / threshold met / no regression,
138
+ `1` violations found / regression introduced, `2` tool error โ€” so a CI pipeline or an agent's own
139
+ control flow can branch on the result without parsing prose.
140
+
141
+ `7` **`contrast --fix`** โ€” checks a foreground/background pair against WCAG 2.x (1.4.3: 4.5:1
142
+ normal text / 3:1 large text; 1.4.11: 3:1 for UI components) and, on failure, suggests passing
143
+ colors in both directions (lighter and darker) in OKLCh, so a fix stays close to the original hue
144
+ instead of jumping to black or white.
145
+
146
+ `8` **Portable as an Agent Skill** โ€” plain `SKILL.md` + `references/`, no proprietary format, works
147
+ in any client implementing the open Agent Skills standard, not only Claude Code.
148
+
149
+ ## ๐Ÿ“Š Honest Coverage
150
+
151
+ Automated accessibility testing has a real, bounded scope, and a11y-loop says so in every report
152
+ rather than implying otherwise:
153
+
154
+ - Deque's own research puts automated coverage at **~57% of accessibility issues by volume**
155
+ across a 13,000+ page / ~300,000 issue study โ€” but only **~31% of WCAG 2.2 AA success criteria**
156
+ have *any* automated rule at all, and only **~13% are reliably automatable** end-to-end.
157
+ - **A clean a11y-loop report means "no automatically detectable failures were found" โ€” it is
158
+ never a conformance or compliance claim**, and the tool will not tell you your app is
159
+ accessible, compliant, or free of legal risk. No single score is ever produced.
160
+ - Every run emits a **generated manual-review checklist**, scoped to the components actually
161
+ built, naming the criteria that need a human and/or assistive-technology testing (screen reader
162
+ behavior, descriptive quality of alt text and link text, logical reading order, caption/media
163
+ alternative accuracy, cognitive accessibility) โ€” the direct inverse of "no manual testing
164
+ needed."
165
+ - axe-core's own `incomplete` results are surfaced as `needsReview`, not suppressed. See
166
+ `evals/benchmark-results.md` for a live example of two such findings being investigated and
167
+ resolved rather than dismissed.
168
+ - **SARIF caveat, stated honestly:** GitHub Code Scanning only displays SARIF results that carry a
169
+ file-path location. a11y-loop's findings are located by rendered URL + CSS selector, which
170
+ Code Scanning drops on ingestion โ€” a naive upload produces an empty Code Scanning view. SARIF
171
+ output is provided for the Azure DevOps SARIF viewer, the VS Code SARIF extension, and other
172
+ SARIF-consuming tooling; the JSON report remains the primary, complete format.
173
+ - Findings are tagged with the **lowest WCAG version** that contains them (2.0 / 2.1 / 2.2), so you
174
+ can filter to the subset a given jurisdiction actually enforces โ€” e.g. US ADA Title II and
175
+ Section 508 to the 2.0/2.1 AA subset, EU EN 301 549 to 2.1 AA (moving to 2.2 AA around October
176
+ 2026), NZ and UK to the full 2.2 AA set.
177
+
178
+ ## ๐Ÿ“ˆ Benchmark
179
+
180
+ A small, illustrative comparison in [`evals/benchmark-results.md`](evals/benchmark-results.md):
181
+ the same six UI components, built by the same model (Claude Sonnet 5, as a Claude Code subagent),
182
+ once with no accessibility guidance and once following the skill and running the audit loop to
183
+ convergence.
184
+
185
+ - **Baseline (no guidance): 35 violations across 6 components.** With the skill, **1 violation on
186
+ first generation** โ€” before any audit ran.
187
+ - **After the loop: 0 violations**, at an average of **1.67 completed audit iterations** per
188
+ component.
189
+
190
+ Read this with its stated caveats: **N = 6 components, a single run per condition, one model
191
+ family, and the audits are produced by a11y-loop's own engine** (mitigated, not eliminated, by
192
+ every finding being grounded in axe-core, a third-party rules engine) โ€” a small, self-audited
193
+ illustration of the effect's shape, not a controlled study or a precise effect size.
194
+
195
+ ## ๐Ÿ› ๏ธ Tech Stack
196
+
197
+ - **Runtime:** Node.js โ‰ฅ 20, ESM (`"type": "module"`)
198
+ - **Browser automation:** [Playwright](https://playwright.dev/) (Chromium)
199
+ - **Accessibility engine:** [axe-core](https://github.com/dequelabs/axe-core) via
200
+ `@axe-core/playwright` (MPL-2.0 โ€” see [`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md))
201
+ - **Color math:** [culori](https://github.com/Evercoder/culori) (OKLCh contrast fixes)
202
+ - **Focus order:** [tabbable](https://github.com/focus-trap/tabbable)
203
+ - **SARIF conversion:** [axe-sarif-converter](https://github.com/microsoft/axe-sarif-converter)
204
+ - **Agent integration:** the open [Agent Skills](https://agentskills.io/specification) standard โ€”
205
+ `SKILL.md` + `references/`, no client-proprietary format
206
+ - **Tests:** the built-in `node --test` runner, 337+ tests across unit and integration suites,
207
+ including an 18-fixture seeded-violation matrix, a demo end-to-end run, and a forced-colors
208
+ gradient regression test
209
+
210
+ ## ๐Ÿ—๏ธ Architecture
211
+
212
+ <details>
213
+ <summary><kbd>System overview</kbd></summary>
214
+
215
+ ```mermaid
216
+ graph TD
217
+ A["Agent Skill<br/>skill/a11y-loop/SKILL.md + references/"] -->|standing generation rules| B["Agent writes UI code<br/>HTML / JSX / Vue / Svelte / Astro / CSS"]
218
+ B --> C["a11y-loop CLI"]
219
+ C --> D["audit<br/>5 passes: default, dark,<br/>forced-colors, reduced-motion, 320px reflow"]
220
+ C --> E["contrast --fix<br/>WCAG 2.x + OKLCh suggestions"]
221
+ C --> F["diff<br/>FIXED / NEW / REMAINING"]
222
+ D --> G["Playwright + Chromium"]
223
+ G --> H["axe-core"]
224
+ G --> I["a11y-loop's own checks<br/>focus, dialog trap, target size,<br/>reduced motion, link text, div-button"]
225
+ D -->|--interact| J["Drive built states:<br/>modal open, menu expanded, form error"]
226
+ H --> K["JSON report<br/>WCAG SC + ACT IDs + provenance"]
227
+ I --> K
228
+ J --> K
229
+ K --> L["SARIF v2.1<br/>(secondary format)"]
230
+ K --> M["Manual-review checklist"]
231
+ K -->|violations found| B
232
+ F --> K
233
+ ```
234
+
235
+ </details>
236
+
237
+ The loop, in words: the skill sets standing rules while the agent writes UI; `a11y-loop audit`
238
+ verifies the rendered result across five passes plus any built interaction states; violations feed
239
+ back to the agent to fix; `a11y-loop diff` confirms convergence without new regressions; the JSON
240
+ report (and its manual-review checklist) is the artifact of record, with SARIF offered as a
241
+ secondary format for tools that consume it.
242
+
243
+ ## ๐Ÿš€ Getting Started
244
+
245
+ ### Prerequisites
246
+
247
+ - Node.js โ‰ฅ 20
248
+ - A Chromium install for Playwright (installed in the steps below)
249
+
250
+ ### Installation
251
+
252
+ **Not yet published to npm and this repo has no GitHub remote yet** โ€” install from a local clone
253
+ for now:
254
+
255
+ ```bash
256
+ # Clone and install
257
+ git clone https://github.com/ChanMeng666/a11y-loop.git
258
+ cd a11y-loop
259
+ npm install
260
+
261
+ # Install the Chromium build Playwright needs for audits
262
+ npx playwright install chromium
263
+ ```
264
+
265
+ Once published, the intended install is `npx a11y-loop <command>` with no local setup at all โ€”
266
+ that comes after the first npm publish.
267
+
268
+ If you keep browser binaries off the system drive, set `PLAYWRIGHT_BROWSERS_PATH` before running
269
+ `npx playwright install chromium` (and before running the test suite, which launches the same
270
+ browser) โ€” e.g. `PLAYWRIGHT_BROWSERS_PATH=D:\playwright-browsers`.
271
+
272
+ ### Installing the Agent Skill
273
+
274
+ Copy the skill directory into any Agent Skills-compatible client:
275
+
276
+ ```bash
277
+ # Personal, all projects (Claude Code and other clients that read ~/.claude/skills)
278
+ cp -r skill/a11y-loop ~/.claude/skills/a11y-loop
279
+
280
+ # Or project-scoped
281
+ cp -r skill/a11y-loop .claude/skills/a11y-loop
282
+ ```
283
+
284
+ Any client implementing the [Agent Skills specification](https://agentskills.io/specification)
285
+ can load it the same way โ€” Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI, and more.
286
+
287
+ ## โš™๏ธ Using it in CI
288
+
289
+ ```bash
290
+ a11y-loop audit http://localhost:3000 --json --out report.json
291
+ ```
292
+
293
+ exits `1` if any violation is found (`2` on a tool error such as a missing browser), so a build
294
+ step can gate on it directly:
295
+
296
+ ```bash
297
+ a11y-loop audit http://localhost:3000 --json --out report.json || exit 1
298
+ ```
299
+
300
+ `a11y-loop diff --before base.json --after head.json` in a PR check turns that into a regression
301
+ gate: it fails only on genuinely `NEW` violations, so a PR that fixes ten and introduces none
302
+ passes even though the raw count changed.
303
+
304
+ ## ๐Ÿ“– Usage Guide
305
+
306
+ ### Basic Usage
307
+
308
+ ```bash
309
+ # Audit a running page (five passes: default, dark, forced-colors, reduced-motion, reflow)
310
+ a11y-loop audit http://localhost:3000
311
+
312
+ # Audit an HTML file (served locally, never over file://)
313
+ a11y-loop audit --file ./dist/index.html
314
+
315
+ # Audit an HTML fragment directly โ€” the usual entry point for an agent mid-generation
316
+ a11y-loop audit --html "<button class=\"icon-btn\"><svg .../></button>"
317
+
318
+ # Audit an interactive state (e.g. a modal after it opens)
319
+ a11y-loop audit http://localhost:3000 --interact ./states/modal-open.mjs
320
+
321
+ # Check a color pair against WCAG 2.x and get OKLCh fix suggestions
322
+ a11y-loop contrast "#767676" "#ffffff" --fix
323
+
324
+ # Compare two audit reports for regressions
325
+ a11y-loop diff --before base.json --after head.json
326
+ ```
327
+
328
+ ### Advanced Configuration
329
+
330
+ | Flag | Applies to | Effect |
331
+ |---|---|---|
332
+ | `--json` | audit, contrast | machine-readable output on stdout |
333
+ | `--out <path>` | audit | write the JSON report to a file |
334
+ | `--sarif <path>` | audit | also write SARIF v2.1 (see [Honest Coverage](#-honest-coverage)) |
335
+ | `--interact <path.mjs>` | audit | export `const states = { name: async (page) => {} }` to drive built states |
336
+ | `--headed` | audit | run a visible browser, for debugging |
337
+ | `--no-best-practice` | audit | omit axe best-practice rules (never blocking either way) |
338
+ | `--quiet` | audit | one-line summary only |
339
+ | `--large` | contrast | large-scale text thresholds (โ‰ฅ24px, or โ‰ฅ18.5px bold) |
340
+ | `--ui` | contrast | non-text / UI component threshold, 3:1, SC 1.4.11 |
341
+ | `--fix` | contrast | suggest passing colors, lighter and darker, in OKLCh |
342
+
343
+ Run `a11y-loop --help` for the full, current reference.
344
+
345
+ ## โŒจ๏ธ Development
346
+
347
+ ```bash
348
+ npm install
349
+ npx playwright install chromium # once, or after a Playwright version bump
350
+
351
+ npm test # full suite
352
+ npm run test:unit # unit tests only
353
+ npm run test:integration # integration tests only (drives real Chromium)
354
+ ```
355
+
356
+ See [`AGENTS.md`](AGENTS.md) for AI-agent-oriented project conventions, the fixture-manifest
357
+ testing pattern, and the loop discipline expected when touching `demo/` or other UI.
358
+
359
+ ## ๐Ÿค Contributing
360
+
361
+ Contributions make the open-source community an amazing place to learn and create. Please read the
362
+ [Contributing Guide](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md) before you start,
363
+ and use the provided issue / pull-request templates.
364
+
365
+ ## โค๏ธ Sponsor
366
+
367
+ If this project helps you, please consider supporting its development:
368
+
369
+ [![Sponsor on GitHub](https://img.shields.io/badge/Sponsor-GitHub-EA4AAA?style=for-the-badge&logo=githubsponsors)](https://github.com/sponsors/ChanMeng666)
370
+ [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=for-the-badge&logo=buymeacoffee&logoColor=black)](https://buymeacoffee.com/chanmeng66u)
371
+
372
+ For questions and help, see [SUPPORT.md](SUPPORT.md). For security issues, see [SECURITY.md](SECURITY.md).
373
+
374
+ ## ๐Ÿ“„ License
375
+
376
+ This project is released under the [MIT](LICENSE) license. axe-core, a dependency this project
377
+ uses to run its checks, is separately licensed under MPL-2.0 โ€” see
378
+ [`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md) for full attribution.
379
+
380
+ ## ๐Ÿ™‹โ€โ™€๏ธ Author
381
+
382
+ **Chan Meng**
383
+
384
+ [![Email](https://img.shields.io/badge/Email-chanmeng.dev@gmail.com-EA4335?style=flat-square&logo=gmail&logoColor=white)](mailto:chanmeng.dev@gmail.com)
385
+ [![GitHub](https://img.shields.io/badge/GitHub-ChanMeng666-181717?style=flat-square&logo=github&logoColor=white)](https://github.com/ChanMeng666)
386
+
387
+ <div align="right">
388
+
389
+ [![](https://img.shields.io/badge/โฌ†%20Back%20to%20top-555?style=flat-square)](#readme-top)
390
+
391
+ </div>
392
+
393
+ [demo-link]: docs/demo.gif
394
+ [docs-link]: skill/a11y-loop/SKILL.md
395
+
396
+ ---
397
+
398
+ <!-- CHAN MENG PERSONAL BRAND -->
399
+ <div align="center">
400
+ <a href="https://github.com/ChanMeng666" target="_blank">
401
+ <img src="./.github/brand/chan-meng-logo.svg" alt="Chan Meng" width="160" />
402
+ </a>
403
+
404
+ <p><strong>Chan Meng</strong><br/>Need a custom app like this one? I build them โ€” let's talk.</p>
405
+
406
+ <a href="mailto:chanmeng.dev@gmail.com"><img src="https://img.shields.io/badge/Email-chanmeng.dev@gmail.com-EA4335?style=flat-square&logo=gmail&logoColor=white" alt="Email Chan Meng"/></a>
407
+ <a href="https://github.com/ChanMeng666"><img src="https://img.shields.io/badge/GitHub-ChanMeng666-181717?style=flat-square&logo=github&logoColor=white" alt="Chan Meng on GitHub"/></a>
408
+ </div>
409
+ <!-- /CHAN MENG PERSONAL BRAND -->
@@ -0,0 +1,32 @@
1
+ # Third-party notices
2
+
3
+ a11y-loop is MIT-licensed. It depends on and gratefully acknowledges the following third-party software:
4
+
5
+ ## axe-core (and @axe-core/playwright)
6
+
7
+ - Copyright Deque Systems, Inc.
8
+ - License: **Mozilla Public License 2.0 (MPL-2.0)**
9
+ - Source: https://github.com/dequelabs/axe-core
10
+ - axe-core is the rules engine behind `a11y-loop audit`. When a11y-loop runs, `@axe-core/playwright` injects the axe-core script into the audited page. axe-core is used as an unmodified npm dependency; its source is available at the URL above. Per MPL-2.0, the axe-core files remain under MPL-2.0; this notice tells you where to obtain them.
11
+
12
+ ## Playwright
13
+
14
+ - Copyright Microsoft Corporation
15
+ - License: Apache-2.0
16
+ - Source: https://github.com/microsoft/playwright
17
+
18
+ ## culori
19
+
20
+ - License: MIT
21
+ - Source: https://github.com/Evercoder/culori
22
+
23
+ ## tabbable
24
+
25
+ - License: MIT
26
+ - Source: https://github.com/focus-trap/tabbable
27
+
28
+ ## axe-sarif-converter
29
+
30
+ - Copyright Microsoft Corporation
31
+ - License: MIT
32
+ - Source: https://github.com/microsoft/axe-sarif-converter
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "a11y-loop",
3
+ "version": "0.1.0",
4
+ "description": "Makes AI coding agents write accessible UI by default, then proves what it can prove with a real browser audit across the states they built โ€” and tells you exactly what it could not check.",
5
+ "type": "module",
6
+ "bin": {
7
+ "a11y-loop": "src/cli.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=20"
11
+ },
12
+ "scripts": {
13
+ "test": "node --test",
14
+ "test:unit": "node --test \"test/unit/*.test.js\"",
15
+ "test:integration": "node --test \"test/integration/*.test.js\""
16
+ },
17
+ "keywords": [
18
+ "accessibility",
19
+ "a11y",
20
+ "wcag",
21
+ "axe-core",
22
+ "playwright",
23
+ "ai-agents",
24
+ "agent-skills",
25
+ "claude-code",
26
+ "audit",
27
+ "contrast"
28
+ ],
29
+ "license": "MIT",
30
+ "author": "Chan Meng <chanmeng.dev@gmail.com> (https://github.com/ChanMeng666)",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/ChanMeng666/a11y-loop.git"
34
+ },
35
+ "homepage": "https://github.com/ChanMeng666/a11y-loop#readme",
36
+ "bugs": {
37
+ "url": "https://github.com/ChanMeng666/a11y-loop/issues"
38
+ },
39
+ "files": [
40
+ "src/",
41
+ "skill/",
42
+ "THIRD-PARTY-NOTICES.md"
43
+ ],
44
+ "dependencies": {
45
+ "@axe-core/playwright": "^4.12.1",
46
+ "axe-sarif-converter": "^3.1.0",
47
+ "culori": "^4.0.2",
48
+ "playwright": "^1.62.0",
49
+ "tabbable": "^6.5.0"
50
+ }
51
+ }