a11y-loop 0.1.2 โ†’ 0.2.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.
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
+ "name": "a11y-loop",
4
+ "displayName": "a11y-loop",
5
+ "version": "0.2.0",
6
+ "description": "Hard-gates plan mode: a plan that changes UI has to say what it decided about accessibility before it can be approved. Ships the a11y-loop skill and a /a11y-plan command alongside it.",
7
+ "author": {
8
+ "name": "Chan Meng",
9
+ "email": "chanmeng.dev@gmail.com",
10
+ "url": "https://github.com/ChanMeng666"
11
+ },
12
+ "homepage": "https://github.com/ChanMeng666/a11y-loop#readme",
13
+ "repository": "https://github.com/ChanMeng666/a11y-loop",
14
+ "license": "MIT",
15
+ "keywords": [
16
+ "accessibility",
17
+ "a11y",
18
+ "wcag",
19
+ "axe-core",
20
+ "plan-mode",
21
+ "hooks",
22
+ "agent-skills"
23
+ ],
24
+ "skills": "./skill/",
25
+ "commands": "./commands/",
26
+ "hooks": "./hooks/hooks.json"
27
+ }
package/README.md CHANGED
@@ -8,7 +8,12 @@
8
8
 
9
9
  <div align="center"><a name="readme-top"></a>
10
10
 
11
- # ๐Ÿ” a11y-loop
11
+ <picture>
12
+ <source media="(prefers-color-scheme: dark)" srcset="./.github/brand/a11y-loop-logo-dark.svg">
13
+ <img src="./.github/brand/a11y-loop-logo-light.svg" alt="a11y-loop logo" width="88" height="88">
14
+ </picture>
15
+
16
+ # a11y-loop
12
17
 
13
18
  ### Write accessible UI by default. Verify it in a real browser. Say exactly what you couldn't check.
14
19
 
@@ -16,7 +21,7 @@ a11y-loop makes AI coding agents write accessible UI by default, then proves wha
16
21
  with a real browser audit across the states it built โ€” and tells you exactly what it could not
17
22
  check.
18
23
 
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)
24
+ [Demo GIF][demo-link] ยท [Documentation][docs-site-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
25
 
21
26
  <!-- SHIELD GROUP -->
22
27
 
@@ -41,6 +46,7 @@ check.
41
46
 
42
47
  - [๐ŸŒŸ Introduction](#-introduction)
43
48
  - [๐ŸŽฌ Demo](#-demo)
49
+ - [๐ŸŽฅ Promo Video](#-promo-video)
44
50
  - [โœจ Key Features](#-key-features)
45
51
  - [๐Ÿ“Š Honest Coverage](#-honest-coverage)
46
52
  - [๐Ÿ“ˆ Benchmark](#-benchmark)
@@ -66,7 +72,9 @@ accessibility-agnostic ones (W4A'25, 17.32% vs. 15.93%). Instructions alone are
66
72
 
67
73
  a11y-loop is two things working together:
68
74
 
69
- 1. **An Agent Skill** โ€” standing generation rules (semantic HTML first, ARIA discipline, APG
75
+ 1. **An Agent Skill** โ€” plan rules that apply while the work is still being scoped (conformance
76
+ target, per-component criteria, the product decisions that foreclose accessibility, color tokens
77
+ before components), then standing generation rules (semantic HTML first, ARIA discipline, APG
70
78
  keyboard contracts, labels, focus visibility, AA contrast in light and dark, reduced motion,
71
79
  24ร—24 targets) that apply while the agent is writing UI code.
72
80
  2. **A Node CLI** (`a11y-loop audit` / `contrast --fix` / `diff`) that verifies the result in a
@@ -85,11 +93,21 @@ built and nobody wants to touch it. The goal here is to move it earlier: make ac
85
93
  default of the development workflow rather than an audit at the end โ€” which matters more now that
86
94
  so much UI code is written by AI agents in the first place.
87
95
 
96
+ "Earlier" now reaches back past the first line of code. Some of the decisions that settle whether
97
+ an interface can be made accessible โ€” reordering that only works by dragging, a menu that only opens
98
+ on hover, data that only exists as canvas pixels โ€” are made while the work is being scoped, and they
99
+ are nearly free to change there and a rewrite afterwards. ยง0 of the skill puts those decisions in
100
+ the plan, where they are still cheap.
101
+
88
102
  **What this is not.** a11y-loop does not claim compliance, does not guarantee accessibility, and
89
103
  does not replace manual testing or testing with assistive technology. A clean report means "no
90
104
  automatically detectable failures" โ€” see [Honest Coverage](#-honest-coverage) below for exactly
91
105
  what that does and doesn't cover.
92
106
 
107
+ ## ๐ŸŽฅ Promo Video
108
+
109
+ https://github.com/user-attachments/assets/33ff8672-7690-4581-9ceb-d95476883c54
110
+
93
111
  ## ๐ŸŽฌ Demo
94
112
 
95
113
  ![a11y-loop fixing a seeded-violation demo page across five audit passes until it converges on zero violations](docs/demo.gif)
@@ -117,6 +135,20 @@ reduced-motion, and a 320ร—256 reflow viewport (the WCAG-sanctioned 400% zoom eq
117
135
  SC 1.4.10) โ€” because most real failures only show up under a specific rendering condition, not on
118
136
  a single default-viewport load.
119
137
 
138
+ <details>
139
+ <summary><kbd>Diagram: the five passes feeding one report</kbd></summary>
140
+
141
+ ```mermaid
142
+ graph LR
143
+ P1["Default<br/>1280ร—720"] --> R["One JSON report<br/>per audited page/state"]
144
+ P2["Dark mode"] --> R
145
+ P3["Forced-colors mode"] --> R
146
+ P4["Reduced motion"] --> R
147
+ P5["320ร—256 reflow<br/>(400% zoom equiv., SC 1.4.10)"] --> R
148
+ ```
149
+
150
+ </details>
151
+
120
152
  `2` **Checks axe-core can't run** โ€” tab order, focus visibility (including focus-ring contrast),
121
153
  dialog focus trap / Escape / focus-return, target size (24ร—24 CSS px, SC 2.5.8), reduced-motion
122
154
  effectiveness, ambiguous link text, div-as-button, and positive `tabindex`. These sit alongside
@@ -148,6 +180,16 @@ instead of jumping to black or white.
148
180
  `8` **Portable as an Agent Skill** โ€” plain `SKILL.md` + `references/`, no proprietary format, works
149
181
  in any client implementing the open Agent Skills standard, not only Claude Code.
150
182
 
183
+ `9` **Accessibility enters at the plan, not the pull request** โ€” ยง0 gives the agent the decisions to
184
+ settle while the work is still being scoped: the conformance target for the relevant jurisdiction,
185
+ per-component acceptance criteria, the color tokens (verified with `contrast --fix`, which needs no
186
+ browser and no code), the structure, and the interaction states that will need auditing. It also
187
+ names the product choices that foreclose accessibility โ€” drag-only reordering (SC 2.5.7), hover-only
188
+ menus (SC 1.4.13), canvas-rendered data (SC 1.1.1), time limits (SC 2.2.1), CAPTCHA (SC 3.3.8) โ€”
189
+ each with the alternative, while changing them is still a sentence rather than a rewrite. In Claude
190
+ Code, the [optional plugin layer](#optional-the-claude-code-plugin-layer) enforces it at plan
191
+ approval.
192
+
151
193
  ## ๐Ÿ“Š Honest Coverage
152
194
 
153
195
  Automated accessibility testing has a real, bounded scope, and a11y-loop says so in every report
@@ -156,6 +198,22 @@ rather than implying otherwise:
156
198
  - Deque's own research puts automated coverage at **~57% of accessibility issues by volume**
157
199
  across a 13,000+ page / ~300,000 issue study โ€” but only **~31% of WCAG 2.2 AA success criteria**
158
200
  have *any* automated rule at all, and only **~13% are reliably automatable** end-to-end.
201
+
202
+ <details>
203
+ <summary><kbd>Diagram: WCAG 2.2 AA success criteria, by automation reach</kbd></summary>
204
+
205
+ ```mermaid
206
+ pie showData title WCAG 2.2 AA success criteria โ€” automation reach (Deque research)
207
+ "Reliably automatable end-to-end (~13%)" : 13
208
+ "Have some automated rule, not fully reliable (~18%)" : 18
209
+ "No automated rule โ€” needs manual/AT review (~69%)" : 69
210
+ ```
211
+
212
+ Illustrates the same figures cited above, not a new metric โ€” a clean report never implies coverage
213
+ of the other ~87%.
214
+
215
+ </details>
216
+
159
217
  - **A clean a11y-loop report means "no automatically detectable failures were found" โ€” it is
160
218
  never a conformance or compliance claim**, and the tool will not tell you your app is
161
219
  accessible, compliant, or free of legal risk. No single score is ever produced.
@@ -216,7 +274,10 @@ illustration of the effect's shape, not a controlled study or a precise effect s
216
274
 
217
275
  ```mermaid
218
276
  graph TD
219
- 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"]
277
+ A["Agent Skill<br/>skill/a11y-loop/SKILL.md + references/"] -->|"ยง0 plan rules"| P["Agent plans the UI work<br/>conformance target, per-component criteria,<br/>foreclosing decisions, color tokens, structure"]
278
+ P -->|"contrast --fix, no browser needed"| E
279
+ P --> B
280
+ A -->|"ยง1 standing generation rules"| B["Agent writes UI code<br/>HTML / JSX / Vue / Svelte / Astro / CSS"]
220
281
  B --> C["a11y-loop CLI"]
221
282
  C --> D["audit<br/>5 passes: default, dark,<br/>forced-colors, reduced-motion, 320px reflow"]
222
283
  C --> E["contrast --fix<br/>WCAG 2.x + OKLCh suggestions"]
@@ -236,6 +297,31 @@ graph TD
236
297
 
237
298
  </details>
238
299
 
300
+ <details>
301
+ <summary><kbd>Sequence: one audit-fix-reaudit cycle</kbd></summary>
302
+
303
+ ```mermaid
304
+ sequenceDiagram
305
+ participant Agent
306
+ participant CLI as a11y-loop CLI
307
+ participant Browser as Playwright + Chromium
308
+ participant Axe as axe-core + a11y-loop's own checks
309
+ Agent->>CLI: a11y-loop audit (after writing UI code)
310
+ CLI->>Browser: render page across 5 passes<br/>(+ --interact states, if any)
311
+ Browser->>Axe: run checks against each rendered pass
312
+ Axe-->>CLI: findings (WCAG SC, ACT ID, provenance)
313
+ CLI-->>Agent: JSON report + manual-review checklist
314
+ alt violations found
315
+ Agent->>Agent: fix code
316
+ Agent->>CLI: a11y-loop audit (re-run)
317
+ else no violations
318
+ Agent->>CLI: a11y-loop diff --before --after
319
+ CLI-->>Agent: Converged โ€” FIXED/NEW/REMAINING summary
320
+ end
321
+ ```
322
+
323
+ </details>
324
+
239
325
  The loop, in words: the skill sets standing rules while the agent writes UI; `a11y-loop audit`
240
326
  verifies the rendered result across five passes plus any built interaction states; violations feed
241
327
  back to the agent to fix; `a11y-loop diff` confirms convergence without new regressions; the JSON
@@ -251,22 +337,26 @@ secondary format for tools that consume it.
251
337
 
252
338
  ### Installation
253
339
 
254
- **Not yet published to npm and this repo has no GitHub remote yet** โ€” install from a local clone
255
- for now:
340
+ ```bash
341
+ # Run it directly, no install
342
+ npx a11y-loop <command>
343
+
344
+ # Or install the CLI globally
345
+ npm i -g a11y-loop
346
+
347
+ # Either way, install the Chromium build Playwright needs for audits
348
+ npx playwright install chromium
349
+ ```
350
+
351
+ Prefer working from source (e.g. to contribute)? Clone and install instead:
256
352
 
257
353
  ```bash
258
- # Clone and install
259
354
  git clone https://github.com/ChanMeng666/a11y-loop.git
260
355
  cd a11y-loop
261
356
  npm install
262
-
263
- # Install the Chromium build Playwright needs for audits
264
357
  npx playwright install chromium
265
358
  ```
266
359
 
267
- Once published, the intended install is `npx a11y-loop <command>` with no local setup at all โ€”
268
- that comes after the first npm publish.
269
-
270
360
  If you keep browser binaries off the system drive, set `PLAYWRIGHT_BROWSERS_PATH` before running
271
361
  `npx playwright install chromium` (and before running the test suite, which launches the same
272
362
  browser) โ€” e.g. `PLAYWRIGHT_BROWSERS_PATH=D:\playwright-browsers`.
@@ -286,6 +376,38 @@ cp -r skill/a11y-loop .claude/skills/a11y-loop
286
376
  Any client implementing the [Agent Skills specification](https://agentskills.io/specification)
287
377
  can load it the same way โ€” Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI, and more.
288
378
 
379
+ ### Optional: the Claude Code plugin layer
380
+
381
+ The skill above is the whole product and it is portable. This repository also ships a thin
382
+ Claude-Code-only layer that adds one thing the portable skill cannot do โ€” enforcement during
383
+ plan mode:
384
+
385
+ ```bash
386
+ # From a checkout, in Claude Code
387
+ /plugin install .
388
+ ```
389
+
390
+ It contributes:
391
+
392
+ - a `PreToolUse` hook matched to `ExitPlanMode`. When a plan changes UI work and says nothing about
393
+ accessibility, the plan is declined once and the `### Accessibility` section is handed back to fill
394
+ in. It names any decision already in the plan that is hard to walk back later โ€” drag-only
395
+ reordering, hover-only menus, infinite scroll, canvas-rendered data, time limits, CAPTCHA, autoplay.
396
+ - `/a11y-plan`, to ask for that section directly.
397
+
398
+ Deliberate limits: it **defers** rather than allows on every non-deny path, so it never suppresses
399
+ your own plan approval; it declines a given plan **at most once**, so it cannot loop; a plan with no
400
+ UI in it is passed silently; and `A11Y_LOOP_PLAN_GATE=off` disables it. The gate checks that the
401
+ question was asked โ€” it cannot check that the answer is any good. That is still `a11y-loop audit`
402
+ and a human.
403
+
404
+ | | Portable skill | Plugin layer |
405
+ |---|---|---|
406
+ | Install | copy `skill/a11y-loop` | `/plugin install .` |
407
+ | Works in | 40+ Agent Skills clients | Claude Code only |
408
+ | Gives you | ยง0 planning, ยง1 generation, ยง2 the loop, ยง3 honest reporting | plan-mode enforcement, `/a11y-plan` |
409
+ | Required? | yes | no |
410
+
289
411
  ## โš™๏ธ Using it in CI
290
412
 
291
413
  ```bash
@@ -355,8 +477,17 @@ npm run test:unit # unit tests only
355
477
  npm run test:integration # integration tests only (drives real Chromium)
356
478
  ```
357
479
 
480
+ The optional plugin layer is plain Node with no dependencies. Exercise the plan gate directly:
481
+
482
+ ```bash
483
+ echo '{"session_id":"s1","tool_name":"ExitPlanMode","tool_input":{"plan":"Build a React modal with Tailwind CSS."}}' \
484
+ | node hooks/plan-gate.mjs
485
+ claude plugin validate . --strict
486
+ ```
487
+
358
488
  See [`AGENTS.md`](AGENTS.md) for AI-agent-oriented project conventions, the fixture-manifest
359
- testing pattern, and the loop discipline expected when touching `demo/` or other UI.
489
+ testing pattern, the loop discipline expected when touching `demo/` or other UI, and the rule that
490
+ keeps `skill/` free of any Claude-Code-specific mechanism.
360
491
 
361
492
  ## ๐Ÿค Contributing
362
493
 
@@ -394,6 +525,7 @@ uses to run its checks, is separately licensed under MPL-2.0 โ€” see
394
525
 
395
526
  [demo-link]: docs/demo.gif
396
527
  [docs-link]: skill/a11y-loop/SKILL.md
528
+ [docs-site-link]: https://ChanMeng666.github.io/a11y-loop/
397
529
 
398
530
  ---
399
531
 
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: a11y-plan
3
+ description: Produce the plan-phase Accessibility section for a feature โ€” conformance target, per-component criteria, decisions that foreclose accessibility, color tokens, structure, verification, manual budget.
4
+ argument-hint: "[feature description, or nothing to use the current plan]"
5
+ disable-model-invocation: true
6
+ allowed-tools: Read Glob Grep Bash(a11y-loop contrast *) Bash(npx a11y-loop contrast *)
7
+ ---
8
+
9
+ Write the **Accessibility** section for this plan-phase work:
10
+
11
+ $ARGUMENTS
12
+
13
+ If that is empty, use the plan currently under discussion in this conversation. If there is no plan
14
+ either, ask what is being built before writing anything โ€” a section written against a guess is worse
15
+ than no section.
16
+
17
+ ## How
18
+
19
+ Load the `a11y-loop` skill and follow its plan rules (ยง0) and
20
+ `references/plan-phase.md`. Everything about which criteria apply, which product decisions foreclose
21
+ accessibility, and how to pick color tokens lives there. Do not restate WCAG from memory here; read
22
+ `references/wcag22-quick-ref.md` for exact SC numbers and thresholds, and
23
+ `references/apg-patterns.md` for the keyboard contract of any widget the plan names.
24
+
25
+ Where the plan names concrete colors, verify the pairs with `a11y-loop contrast --fix` in both light
26
+ and dark rather than asserting a ratio.
27
+
28
+ ## Output
29
+
30
+ One section, in this shape, every line answered from what is actually being built โ€” no placeholders
31
+ left in:
32
+
33
+ ```markdown
34
+ ### Accessibility
35
+ - **Target:** WCAG 2.2 Level AA โ€” <rationale / jurisdiction>
36
+ - **Per-component criteria:** <component> โ†’ <SC list> + <keyboard contract source>
37
+ - **Foreclosing decisions:** <none reviewed | list + alternatives>
38
+ - **Color tokens:** <pairs verified with contrast --fix, light + dark>
39
+ - **Structure:** <heading outline / landmarks / focus order>
40
+ - **Verification:** <states needing --interact | where the audit gate sits>
41
+ - **Manual budget:** <what automation cannot judge here>
42
+ ```
43
+
44
+ Then say, in one line, which components in this plan you could not write criteria for and why.
45
+
46
+ The skill's honesty rules (ยง3) apply to this section as much as to audit output: it is a set of
47
+ decisions and acceptance criteria, not a claim that the result will be accessible or conformant.
@@ -0,0 +1,17 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "ExitPlanMode",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node",
10
+ "args": ["${CLAUDE_PLUGIN_ROOT}/hooks/plan-gate.mjs"],
11
+ "timeout": 15
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }