What If Your A11y Linter Could Actually Fix the Bugs It Found?
Source: Dev.to
GitHub Copilot CLI Challenge submission
What if your linter could actually fix the problems it found?
a11y‑pilot is a CLI that scans your frontend code for accessibility violations, then spawns GitHub Copilot CLI to fix each one.
It doesn’t just suggest a change – it invokes copilot --prompt with a crafted fix instruction and lets the AI refactor your code in place.
Quick links
- npm:
- GitHub:
How it works
Scan → Detect → Prompt Engineer → Copilot CLI Fixes → Done
| Step | What happens |
|---|---|
| Scan | Point the tool at any directory or file. It walks the project and parses JSX, TSX, HTML, Vue, Svelte, and Astro files using Babel AST (for JSX/TSX) and htmlparser2 (for HTML‑like templates). |
| Detect | 15 accessibility rules run against every parsed element, checking for WCAG violations across 5 categories. |
| Auto‑fix | For each issue, a11y‑pilot builds a precise, context‑rich prompt and runs copilot --prompt --allow-all-tools. Copilot reads the file, understands the surrounding code, and applies the minimum diff needed – no blind find‑and‑replace. |
Under‑the‑hood diagram
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ a11y‑pilot │────▶│ Issue detected │────▶│ Build prompt │
│ scanner │ │ (rule engine) │ │ (context‑rich) │
└─────────────────┘ └──────────────────┘ └────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ File fixed! │◀────│ Copilot applies │◀────│ copilot CLI │
│ ✔ Report │ │ the fix │ │ invoked │
└─────────────────┘ └──────────────────┘ └─────────────────┘
Example prompt (no-div-button rule)
In file
src/Hero.tsxat line 20, fix this accessibility issue:
has a click handler but is missing `role` and `tabIndex`. **Fix:** Replace theelement with a native “ element, move theonClickhandler to the button, and remove anycursor: pointerstyling (buttons have it by default).
Only modify the minimum code necessary.
Copilot CLI reads the full file context, understands the surrounding JSX structure, and makes an intelligent refactor – not a simple string replace.
Terminal dashboard (after a scan)
✖ Found 46 issues (35 errors, 11 warnings) in 4 files (5 scanned)
📊 Issue Breakdown
──────────────────────────────────────────────────
♿ Accessibility ████████░░░░░░░░░░░░ 19 (41%) 19E
🏗️ Semantic HTML █████░░░░░░░░░░░░░░░ 11 (24%) 4E 7W
⌨️ Keyboard ███░░░░░░░░░░░░░░░░░ 7 (15%) 5E 2W
🏷️ ARIA ██░░░░░░░░░░░░░░░░░░ 5 (11%) 5E
👆 Interaction ██░░░░░░░░░░░░░░░░░░ 4 (9%) 2E 2W
──────────────────────────────────────────────────
14 rules triggered: img‑alt, form‑label, no‑div‑button, …
The dashboard gives an instant snapshot of where your accessibility debt lives – ARIA misuse, keyboard traps, missing semantics, etc. – so you know exactly where to focus.
Copilot CLI – the execution engine
-
--auto-fix– When triggered,a11y‑pilotspawnscopilot --prompt "" --allow-all-toolsfor each detected issue.
--promptenables non‑interactive mode, and--allow-all-toolsauto‑approves tool use, making programmatic invocation possible. -
Quality of fixes –
alert('clicked')}>→ converted to “ with the handler moved and className preserved.- Empty
[](/profile)→ addedaria-label="Profile"(label inferred from URL).
-
Prompt engineering per rule – Each of the 15 rules carries a
copilotPromptfield: a concise instruction that gives Copilot enough context to understand the problem and the expected fix pattern, while still allowing adaptation to surrounding code. This is what turnsa11y‑pilotfrom a “linter” into a “linter + AI‑powered fixer”.
Development workflow with Copilot CLI
| Area | How Copilot helped |
|---|---|
| Parser logic | Iterated on Babel AST traversal for JSX elements, handling spread props, expression containers, and member expressions. Copilot clarified the @babel/traverse ESM default‑export quirk (`_traverse.default |
| Rule implementation | Referenced WCAG criteria, ensured edge‑case handling (e.g., not flagging “ without href in the aria-hidden-focus rule, skipping input[type="hidden"] in form‑label). |
| Debugging | Quickly reproduced and fixed parsing bugs, generated test fixtures, and wrote unit tests for each rule. |
| Prompt refinement | Re‑crafted prompts until the AI produced minimal, correct diffs for a wide variety of codebases. |
Real‑world result
I pointed
a11y‑pilotat a file with 12 accessibility issues and rana11y‑pilot fix.
Every single issue was resolved –became, empty “ got meaningfulalttext inferred from the filename, unlabeled inputs received properaria-label.
Re‑scanning the file: 0 issues. No manual edits required.
Try it yourself
# Install globally (or as a dev dependency)
npm i -g a11y-pilot
# Scan a project
a11y-pilot scan ./src
# Auto‑fix everything
a11y-pilot fix ./src
Enjoy an accessibility‑first workflow powered by GitHub Copilot CLI!
When the copilot‑bridge initially used
shell: trueit triggered the Node.js DEP0190 deprecation warning.
Copilot CLI helped me switch to direct binary resolution with:
execFileSync('which', ['copilot'])
and use a proper spawn() call without a shell.
What impressed me
The thing that stood out most was Copilot CLI’s ability to handle file‑level context.
When I pointed it at a file with 12 accessibility issues and said:
“Fix the “ on line 20”
it didn’t break the other 11 problematic lines. It made surgical, minimal edits.
That property made the auto‑fix feature viable—I could confidently fix issues one‑by‑one or in batches without worrying about cascading breakage.
Install
npm install -g a11y-pilot
Repository
Try it now
npx a11y-pilot scan ./src