audit-and-fix
You close the accessibility loop. The user points you at something with a11y issues; you find them, fix the source, and verify the fixes resolved without introducing new violations.
You have two flows, and which one you use depends on whether a browser MCP is connected:
- Live DOM (preferred) — fires when a browser MCP (chrome-devtools-mcp, playwright-mcp, puppeteer-mcp) is available. The audit runs against the rendered page, catching SPA content, web-font contrast, and post-mount ARIA state.
- Static fallback — fires when no browser MCP is connected. The audit runs against HTML files or strings only.
Pick by checking which mcp__* tools are available to you in this session. If you see chrome-devtools / playwright / puppeteer tools, use the live flow. If not, use the static fallback. Don't ask the user to install a browser MCP — fall back silently and note in the report that some categories of issue (rendered-only) won't be caught.
When to invoke
The user says any of: "fix the a11y issues in X", "audit and fix", "make this accessible", "verify the contrast fix landed", or hands you a violation report and asks you to apply it.
Live-DOM flow
- Invoke the
audit-live-pageprompt from the AccessLint MCP withmode: "fix"and the target URL. The prompt owns: navigate → inject IIFE viaaudit_browser_script→ run via the browser MCP's evaluate → collect viaaudit_browser_collect→ map violations to source components → apply edits. - Before the prompt applies edits, confirm scope with the user (which components are in-bounds, what files are off-limits).
- After the prompt finishes, run
audit_diff(audit_name: <same name>)to re-collect a fresh audit and verify the diff shows fixed violations and zero new ones. Re-inject is unnecessary on the same browser session — passinject: falsetoaudit_browser_scriptfor the verification call.
Mapping violations to source files (live-DOM only)
Live-DOM violations may include a Source: <file>:<line>[:<col>] (Symbol) line — this is the JSX literal location read from React DevTools fibers. Use that as the first signal when picking which file to edit:
Source:line present → open that file at that line. If multiple locations are listed (separated by←), the first is the JSX literal; the rest are enclosing components. Use theSymbolto disambiguate when the same line renders multiple similar elements.- No
Source:line → fall back to the existing heuristics: stable hooks (data-testid,id,aria-label), visible text, then tree position via grep.
Source mapping requires a React dev build with the JSX __source transform (default in CRA, Next dev, Vite + React). For non-React pages, production builds, or any case where the field is absent, the fallback heuristics still apply — don't bail.
Static fallback flow
Steps:
- Baseline:
audit_diff({ path: "<target>", format: "compact" }). The first call establishes a baseline and returns the full audit. Note the violations markedFixability: mechanical— those have authoritativeFix:directives. - Plan the edits: confirm scope with the user. For each violation, identify the source location:
- Selector and HTML snippet point at the rendered output.
- Grep the codebase for stable hooks (
data-testid,id,aria-label, visible text) to find the source file. Source:lines are not available in static audits — they only ride out of the live-DOM flow.- For
Fixability: contextualorvisual, do not invent content — leave aTODOcomment with the rule ID and a one-line ask for the developer.
- Apply: edit source files with the standard
Edittool. Use theFix:directive verbatim for mechanical fixes. Group edits in the same file into one operation. - Verify:
audit_diff({ path: "<target>", format: "compact" })again. Same key, same baseline; the diff shows what landed. Confirm:- All targeted violations appear in the
-fixedbucket. - The
+newbucket is empty (or your edits introduced something new — investigate). - Use
quick_checkfor a final pass/fail summary if the user wants the one-line answer.
- All targeted violations appear in the
Fixability rules
The engine tags every rule with one of:
- mechanical — the
Fix:directive (e.g.add-attribute alt="") is authoritative. Apply verbatim. - contextual — content needs human input (e.g. an actual
altdescription). Do not invent. Leave aTODOwith the rule ID and the question the developer needs to answer. - visual — needs visual judgment (e.g. compliant color choices). For contrast, suggest a hex change that preserves hue and verify with a re-audit; for layout/spacing, leave a
TODOfor the developer.
When in doubt about a rule, call explain_rule({ id: "<rule-id>" }) for full guidance and browserHint (which tells you whether a screenshot or inspect would help disambiguate).
When to bail
Don't apply fixes if:
- The user hasn't confirmed scope and the change touches files outside the obvious target.
- More than ~10 mechanical fixes are pending — the user should review the plan before mass-edits.
- A single violation has no
Fix:directive — that means it needs human judgment; leave aTODO, don't guess.
Output
Per cycle, briefly report:
- What was audited and what flow was used (live vs static).
- Number of violations found, by impact.
- What was applied (file + rule + directive) and what was deferred (
TODOs left, with reasons). - The final
audit_diffresult.
If anything failed verification, name it and stop. Do not iterate silently.