Source profileQuality 91/100

kensaurus/cursor-kenji/skills/audit-accessibility/SKILL.md

audit-accessibility

Automated WCAG 2.2 accessibility audit using playwright-cli to crawl every page, inject axe-core via eval, test keyboard navigation, check color contrast, ARIA labels, and heading order. Use when "audit accessibility", "check a11y", "WCAG audit", "check keyboard nav", or "test screen reader".

Source repository stars
9
Declared platforms
0
Static risk flags
1
Last source update
2026-08-21
Source checked
2026-08-25

Decision brief

What it does: where it fits

Degree of freedom: MIXED — Phases 0–1, 5 [HIGH freedom]; Phases 2–3 playwright/axe/Tab sequences [LOW freedom — run exactly]. Read protocol-browser-anti-stall before any browser step.

Best for

  • Use when "audit accessibility", "check a11y", "WCAG audit", "check keyboard nav", or "test screen reader".

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/audit-accessibility"
Safe inspection promptEditorial

Inspect the Agent Skill "audit-accessibility" from https://github.com/kensaurus/cursor-kenji/blob/28a0bd8403c950f58ed063d47a858ee3493b0038/skills/audit-accessibility/SKILL.md at commit 28a0bd8403c950f58ed063d47a858ee3493b0038. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    How to reason

    1. Observe — quote axe rule+selector, heading list, or Tab snapshot 2. Interpret — can a keyboard or AT user complete the task? 3. Classify — WCAG fail / axe-false-positive / manual-only / correct-as-is 4. Severity — Level A = P0; Level AA = P1; best-practice = P2

    Observe — quote axe rule+selector, heading list, or Tab snapshotInterpret — can a keyboard or AT user complete the task?Classify — WCAG fail / axe-false-positive / manual-only / correct-as-is
  2. 02

    Phase 0: Auto-Detect Pages and Components

    If no production URL, default to http://localhost:3000 (or detected dev server port).

    If no production URL, default to http://localhost:3000 (or detected dev server port).Record: APPURL, PAGES, CSSFRAMEWORK, COMPONENTLIB, EXISTINGA11YTOOLS, ARIAUSAGECOUNT.
  3. 03

    Phase 1: Research Current WCAG Guidelines

    Scrape 2–3 authoritative results:

    Scrape 2–3 authoritative results:
  4. 04

    Phase 2: Automated Scanning (axe-core via Playwright)

    For each page discovered in Phase 0a:

    Rule ID (e.g., color-contrast, image-alt, label)Impact (critical, serious, moderate, minor)WCAG criteria mapped from the rule
  5. 05

    Phase 3: Keyboard Navigation Testing

    For each page, test that all interactive elements are reachable via Tab key:

    [ ] Focus is visible (there is a focus indicator on the active element)[ ] Focus order is logical (follows visual reading order)[ ] No focus trap (Tab eventually cycles back to the beginning or reaches the end)

Permission review

Static risk signals and limitations

Network access

medium · line 143

The documentation includes network, browsing, or remote request actions.

$PW -s=a11y run-code 'async (page) => { await page.addScriptTag({ url: "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js" }); return await page.evaluate(async () => { const r = await axe.run(); return { violations: r.violat

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score91/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars9SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
kensaurus/cursor-kenji
Skill path
skills/audit-accessibility/SKILL.md
Commit
28a0bd8403c950f58ed063d47a858ee3493b0038
License
MIT
Collected
2026-08-25
Default branch
main
View the original SKILL.md

Accessibility Audit

Degree of freedom: MIXED — Phases 0–1, 5 [HIGH freedom]; Phases 2–3 playwright/axe/Tab sequences [LOW freedom — run exactly]. Read protocol-browser-anti-stall before any browser step.

How to reason

  1. Observe — quote axe rule+selector, heading list, or Tab snapshot
  2. Interpret — can a keyboard or AT user complete the task?
  3. Classify — WCAG fail / axe-false-positive / manual-only / correct-as-is
  4. Severity — Level A = P0; Level AA = P1; best-practice = P2

Worked example

Observe: axe label on /signup; <input name="email"> has no id/aria-label. Interpret: AT users cannot tell what to type (1.3.1 / 4.1.2). Classify: WCAG fail (not an axe false positive). Severity: P0 — Level A, blocks signup. Finding: /signup | 1.3.1+4.1.2 | P0 | unlabeled email | <label for>.

Self-critique before reporting [LOW freedom — do not skip]

  1. WCAG SC + numbers — not "contrast is bad"; quote ratio or selector
  2. Keyboard, not axe-only — 2.1.1 fails even if axe is clean
  3. Every reachable page — obscure routes still count
  4. Severity justified — Level A = P0
  5. Axe is ~30–40% — heading/focus/link-text/reading-order always manual

Phase 0: Auto-Detect Pages and Components

0a. Discover Route Structure

Glob("**/app/**/page.{tsx,jsx,ts,js}")
Glob("**/pages/**/*.{tsx,jsx,ts,js}")
Glob("**/src/routes/**/*.{tsx,jsx,svelte,vue}")

0b. Find the App URL

Grep(pattern: "NEXT_PUBLIC_APP_URL|NEXT_PUBLIC_BASE_URL|VITE_APP_URL|APP_URL|localhost", glob: ".env*")

If no production URL, default to http://localhost:3000 (or detected dev server port).

0c. Detect CSS Framework and Component Library

Grep(pattern: "tailwindcss|@chakra-ui|@mui|@radix-ui|shadcn|bootstrap|bulma", glob: "package.json")

0d. Detect Existing a11y Tooling

Grep(pattern: "axe-core|@axe-core|eslint-plugin-jsx-a11y|pa11y|lighthouse|@testing-library", glob: "package.json")
Grep(pattern: "aria-|role=|tabIndex|sr-only|visually-hidden", glob: "*.{tsx,jsx,vue,svelte}", output_mode: "count")

Record: APP_URL, PAGES, CSS_FRAMEWORK, COMPONENT_LIB, EXISTING_A11Y_TOOLS, ARIA_USAGE_COUNT.


Phase 1: Research Current WCAG Guidelines

1a. Firecrawl Research

firecrawl:firecrawl_search
{
 "query": "WCAG 2.2 success criteria checklist web accessibility 2026",
 "limit": 5
}
firecrawl:firecrawl_search
{
 "query": "axe-core automated accessibility testing best practices common false positives",
 "limit": 5
}
firecrawl:firecrawl_search
{
 "query": "<CSS_FRAMEWORK> <COMPONENT_LIB> accessibility best practices common issues",
 "limit": 5
}

Scrape 2–3 authoritative results:

firecrawl:firecrawl_scrape
{
 "url": "<BEST_RESULT_URL>",
 "formats": ["markdown"],
 "onlyMainContent": true
}

1b. Framework-Specific a11y Docs (Context7)

context7:resolve-library-id
{
 "libraryName": "<COMPONENT_LIB e.g. radix-ui or chakra-ui>"
}
context7:query-docs
{
 "libraryId": "<RESOLVED_ID>",
 "query": "accessibility ARIA keyboard navigation focus management"
}

Phase 2: Automated Scanning (axe-core via Playwright)

2a. Navigate to Each Page

For each page discovered in Phase 0a:

PW="npx --yes @playwright/cli@latest"
$PW -s=a11y open --headed "<APP_URL><ROUTE>"    # first page; use `goto` for subsequent ones

Apply the protocol-browser-anti-stall protocol: wait 2s, snapshot, verify page loaded.

2b. Inject and Run axe-core

Use run-code to inject axe-core from CDN and run a full scan:

$PW -s=a11y run-code 'async (page) => { await page.addScriptTag({ url: "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js" }); return await page.evaluate(async () => { const r = await axe.run(); return { violations: r.violations.map(v => ({ id: v.id, impact: v.impact, description: v.description, help: v.help, helpUrl: v.helpUrl, nodes: v.nodes.length, targets: v.nodes.slice(0, 3).map(n => n.target[0]) })), passes: r.passes.length, incomplete: r.incomplete.length, inapplicable: r.inapplicable.length }; }); }'

For each violation returned, record:

  • Rule ID (e.g., color-contrast, image-alt, label)
  • Impact (critical, serious, moderate, minor)
  • WCAG criteria mapped from the rule
  • Affected elements (CSS selectors)
  • Count of affected nodes

2c. Check Specific WCAG Categories Manually

Heading Hierarchy (WCAG 1.3.1):

$PW -s=a11y eval '() => Array.from(document.querySelectorAll("h1,h2,h3,h4,h5,h6")).map(h => ({ tag: h.tagName, text: h.textContent.trim().substring(0, 50) }))'

Verify: only one h1, headings don't skip levels (h1 -> h3 without h2).

Image Alt Text (WCAG 1.1.1):

$PW -s=a11y eval '() => Array.from(document.querySelectorAll("img")).map(img => ({ src: img.src.split("/").pop(), alt: img.alt, hasAlt: img.hasAttribute("alt"), decorative: img.getAttribute("role") === "presentation" || img.alt === "" }))'

Verify: all informative images have descriptive alt text, decorative images have alt="" or role="presentation".

Link Text (WCAG 2.4.4):

$PW -s=a11y eval '() => Array.from(document.querySelectorAll("a")).filter(a => ["click here", "here", "read more", "learn more", "", "link"].includes((a.textContent || "").trim().toLowerCase())).map(a => ({ href: a.href, text: (a.textContent || "").trim(), ariaLabel: a.getAttribute("aria-label") }))'

Flag generic link text ("click here", "read more", empty links without aria-label).

Form Labels (WCAG 1.3.1, 4.1.2):

$PW -s=a11y eval '() => Array.from(document.querySelectorAll("input,select,textarea")).map(el => ({ type: el.type, name: el.name, id: el.id, hasLabel: !!el.id && !!document.querySelector(`label[for="${el.id}"]`), ariaLabel: el.getAttribute("aria-label"), ariaLabelledBy: el.getAttribute("aria-labelledby"), placeholder: el.placeholder }))'

Verify: every form control has an associated <label>, aria-label, or aria-labelledby.

Language Attribute (WCAG 3.1.1):

$PW -s=a11y eval '() => ({ htmlLang: document.documentElement.lang, htmlDir: document.documentElement.dir })'

Verify: <html> has a valid lang attribute.

2d. Take Evidence Screenshots

For each page, capture a screenshot as visual evidence:

$PW -s=a11y screenshot --filename ".playwright-mcp/a11y-<route>.png"

Phase 3: Keyboard Navigation Testing

3a. Tab Order Test

For each page, test that all interactive elements are reachable via Tab key:

PW="npx --yes @playwright/cli@latest"
$PW -s=a11y open --headed "<APP_URL><ROUTE>"    # first page; use `goto` for subsequent ones

Press Tab repeatedly and snapshot after each press to track focus movement:

$PW -s=a11y press Tab
$PW -s=a11y snapshot

After each Tab, check:

  • Focus is visible (there is a focus indicator on the active element)
  • Focus order is logical (follows visual reading order)
  • No focus trap (Tab eventually cycles back to the beginning or reaches the end)
  • Skip links exist (if there is a large navigation area)

Repeat Tab at least 10-15 times per page to cover the main interactive elements.

3b. Interactive Element Testing

For each interactive component (dropdowns, modals, tabs, accordions):

Enter/Space activation (WCAG 2.1.1):

  • Tab to the element
  • Press Enter or Space
  • Verify the action fires (snapshot to confirm state change)

Escape to close (WCAG 2.1.1 for modals/dialogs):

$PW -s=a11y press Escape

Verify: modals/dropdowns close, focus returns to the trigger element.

Arrow key navigation (for tab panels, menus, listboxes):

$PW -s=a11y press ArrowDown

3c. Focus Management After State Changes

Test that focus is managed correctly after dynamic updates:

  • After opening a modal: focus should move into the modal
  • After closing a modal: focus should return to the trigger
  • After deleting an item from a list: focus should move to the next item or a logical location
  • After form submission: focus should move to a success/error message

Phase 4: Cross-Check with Sentry

4a. Search for Assistive Technology Errors

sentry:search_issues
{
 "organizationSlug": "<ORG_SLUG>",
 "projectSlug": "<PROJECT_SLUG>",
 "query": "is:unresolved aria OR screenreader OR voiceover OR talkback OR nvda OR jaws OR focus OR tabindex OR keyboard"
}

4b. Check for JavaScript Errors on Keyboard Interaction

sentry:search_issues
{
 "organizationSlug": "<ORG_SLUG>",
 "projectSlug": "<PROJECT_SLUG>",
 "query": "is:unresolved keydown OR keyup OR keypress OR focusin OR focusout"
}

4c. Browser/Device Breakdown

If errors cluster on AT-favored browsers:

sentry:get_issue_tag_values
{
 "organizationSlug": "<ORG_SLUG>",
 "issueId": "<ISSUE_ID>",
 "tagKey": "browser"
}

Phase 5: Static Code Analysis

5a. Missing ARIA Attributes

Grep(pattern: "onClick(?!.*role=)(?!.*tabIndex)", glob: "*.{tsx,jsx}")

Flag div or span elements with click handlers but no role or tabIndex — these are invisible to keyboard and screen reader users.

5b. Inaccessible Custom Components

SemanticSearch(query: "Where are custom interactive components defined (dropdowns, modals, tabs, accordions) that don't use a component library?", target_directories: [])

Check each custom interactive for:

  • Proper ARIA roles (role="dialog", role="tabpanel", etc.)
  • Keyboard event handlers (onKeyDown)
  • Focus management (useRef + .focus())
  • ARIA states (aria-expanded, aria-selected, aria-hidden)

5c. Color Contrast in CSS/Tailwind

Grep(pattern: "text-gray-[345]|text-slate-[345]|text-zinc-[345]|text-neutral-[345]|color:\\s*#[789abc]", glob: "*.{tsx,jsx,css,scss}")

Light gray text on white background is the most common contrast failure. Flag files using light gray text colors for manual contrast checking.


Phase 6: Report

═══════════════════════════════════════════════════════
 WCAG 2.2 ACCESSIBILITY AUDIT REPORT
 Project: <PROJECT_NAME>
 Date: <DATE>
 Standard: WCAG 2.2 Level AA
 Pages Tested: <COUNT>
═══════════════════════════════════════════════════════

## 1. EXECUTIVE SUMMARY

| Metric | Result |
|---------------------------|-----------------|
| Pages tested | X |
| Total violations | N |
| Critical violations | N |
| Serious violations | N |
| axe-core rules passed | N |
| Keyboard navigable pages | X/Y |
| Overall compliance | X% (estimated) |

## 2. AXE-CORE SCAN RESULTS (per page)

| Page | Critical | Serious | Moderate | Minor | Pass | Score |
|------|----------|---------|----------|-------|------|-------|
| / | ... | ... | ... | ... | ... | A-F |
| /about | ... | ... | ... | ... | ... | A-F |

## 3. VIOLATIONS BY WCAG CRITERION

| WCAG SC | Name | Level | Pages Affected | Elements | Impact | Status |
|---------|------|-------|----------------|----------|--------|--------|
| 1.1.1 | Non-text Content | A | ... | ... | ... | PASS/FAIL |
| 1.3.1 | Info and Relationships | A | ... | ... | ... | PASS/FAIL |
| 1.4.3 | Contrast (Minimum) | AA | ... | ... | ... | PASS/FAIL |
| 2.1.1 | Keyboard | A | ... | ... | ... | PASS/FAIL |
| 2.4.3 | Focus Order | A | ... | ... | ... | PASS/FAIL |
| 2.4.4 | Link Purpose | A | ... | ... | ... | PASS/FAIL |
| 2.4.7 | Focus Visible | AA | ... | ... | ... | PASS/FAIL |
| 3.1.1 | Language of Page | A | ... | ... | ... | PASS/FAIL |
| 4.1.2 | Name, Role, Value | A | ... | ... | ... | PASS/FAIL |

## 4. KEYBOARD NAVIGATION

| Page | Tab Order Logical | Focus Visible | No Focus Trap | Skip Link | Score |
|------|-------------------|---------------|---------------|-----------|-------|
| / | ... | ... | ... | ... | A-F |

## 5. INTERACTIVE COMPONENTS

| Component | Location | ARIA Roles | Keyboard Operable | Focus Managed | Score |
|-----------|----------|------------|-------------------|---------------|-------|
| Modal | ... | ... | ... | ... | A-F |
| Dropdown | ... | ... | ... | ... | A-F |

## 6. SENTRY ASSISTIVE TECHNOLOGY ERRORS

| Issue | Error Type | Events | Browser/AT | Fix Needed |
|-------|------------|--------|------------|------------|
| ... | ... | ... | ... | ... |

## 7. STATIC CODE FINDINGS

| Pattern | Files | Count | Risk |
|---------|-------|-------|------|
| onClick without role/tabIndex | ... | N | High |
| Custom interactive without ARIA | ... | N | High |
| Low-contrast text classes | ... | N | Medium |

## 8. CRITICAL FINDINGS (Action Required)

P0 — Level A violations (legal risk):
1. [finding with WCAG SC, element, page, evidence]

P1 — Level AA violations (compliance gap):
1. [finding with WCAG SC, element, page, evidence]

P2 — Best practice improvements:
1. [finding with rationale]

## 9. RECOMMENDATIONS

| # | WCAG SC | Current | Recommended | Effort | Files to Change |
|---|---------|---------|-------------|--------|-----------------|
| 1 | ... | ... | ... | S/M/L | ... |

═══════════════════════════════════════════════════════

Frequently asked questions

What to verify before installation and use

What does the audit-accessibility source document cover?

Degree of freedom: MIXED — Phases 0–1, 5 [HIGH freedom]; Phases 2–3 playwright/axe/Tab sequences [LOW freedom — run exactly]. Read protocol-browser-anti-stall before any browser step.

How do I install audit-accessibility?

The source record exposes this install command: npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/audit-accessibility". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged network in the source; the page lists the matching lines and excerpts.

Alternatives

Compare before choosing

Computed 976

mgiovani/cc-arsenal

team-review

Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r

Computed 9616

th3vib3coder/vibe-science

vibe-science

Scientific research engine for hypothesis testing, literature gap analysis, experimental validation, and data-driven discovery. Enforces adversarial review (Reviewer 2), 32 quality gates, tree search over hypotheses, confounder harness for quantitative claims, and serendipity detection. TRIGGER when: user asks to analyze scientific data, test hypotheses, validate findings, search for research gaps, design experiments, or investigate results. DO NOT TRIGGER when: pure code review, documentation w

Computed 9420

upex-galaxy/agentic-qa-boilerplate

test-documentation

Analyze, prioritize, and document test cases in TMS (Jira/Xray), or repair an existing Story-ATS-ATP-ATR-TC cascade through a sealed explicit mode. Use for Test/ATP/ATR artifacts, ROI and automation verdicts, maintaining traceability, fix-traceability, or broken TMS links. The repair-traceability mode audits, plans, waits for explicit approval, applies, and verifies without launching the general documentation workflow. Do NOT use for writing test code (test-automation) or running suites (regress

Computed 90236

ArabelaTso/Skills-4-SE

code-change-summarizer

Generates clear and structured pull request descriptions from code changes. Use when Claude needs to: (1) Create PR descriptions from git diffs or code changes, (2) Summarize what changed and why, (3) Document breaking changes with migration guides, (4) Add technical details and design decisions, (5) Provide testing instructions, (6) Enhance descriptions with security, performance, and architecture notes, (7) Document dependency changes. Takes code changes as input, outputs comprehensive PR desc