Mend is a self-verifying repair loop for web accessibility. Point it at any repo and each round it:

  1. Scans the rendered page with axe-core (Playwright).
  2. Maps each violation's DOM node back to the exact file:line in source.
  3. Patches the source — never the runtime. No injected scripts, no DOM mutation, no overlay behavior. That's the villain we replace.
  4. Proves the fix through four hard gates before it counts:
    • Gate 1 — axe re-scan: the violation is gone and nothing new regressed.
    • Gate 2 — masked pixel diff: the page looks pixel-identical (frozen animations, masked charts).
    • Gate 3 — banned patterns: the diff contains no aria-hidden, display:none, empty alt on informative images, or element deletion — no suppression, checked before anyone sees the fix.
    • Gate 4 — IBM Equal Access: a genuinely independent second rule engine has to agree (not Lighthouse — Lighthouse runs axe under the hood).
  5. Judges semantic truth with an isolated critic running on a different model family and provider (DeepSeek V4 + Qwen vision on Akash, not the Claude fixer). Axe checks that alt text exists; the critic looks at the image and checks whether it's true.
  6. Writes a receipt — before/after, the patch, every gate result, the critic verdict — on accept AND revert. A caught, auto-reverted failure is first-class evidence that the harness works.

A live dashboard tails the whole thing over WebSocket, and at the end the agent deploys the healed site to a shareable link itself via Zero. We fix what we can verify and hand you receipts. We never say "compliant."

Sponsor stack — one per loop stage

  • Claude (via Claude Code) — the fixer: writes the source patches and reasons over the repo.
  • AWS Bedrock — the Bedrock-ready brain (one-flag opt-in; we ran on subscription auth this weekend).
  • Akash — the independent critic: open models (DeepSeek V4 + Qwen vision) judge semantic truth on decentralized compute, so the judge never shares the fixer's weights.
  • Pomerium — the identity-aware access layer: the agent reaches a site through least-privilege policy, never raw credentials, and the access log joins the evidence trail.
  • Zero — the self-deploy final act: the agent ships the healed site to a live link itself, no keys, --max-pay 0, $0.
  • Nexla — the roadmap governance layer (see What's next).
  • BrightData — sourced the market evidence (the r/smallbusiness thread, overlay-lawsuit and WebAIM numbers) live.

How we built it

  • Node 20 + Playwright (chromium) for rendering and screenshots.
  • @axe-core/playwright as the primary scanner; IBM Equal Access (accessibility-checker) as the independent second engine — 561 axe nodes vs 508 Equal Access violations on our target, proving they're genuinely different rulesets.
  • pixelmatch + pngjs for visual regression, made deterministic with injected freeze-CSS, fonts.ready, networkidle, fixed viewport/locale/timezone, and masked Chart.js canvases — acceptance was three consecutive runs at 0 changed pixels.
  • A source mapper (DOM node → file:line) with four strategies (stable-attribute, structural/document-tag, literal-text, structural scoring). When it isn't confident, it BLOCKS instead of guessing.
  • The fixer is Claude (via Claude Code); the critic is an independent open model on Akash. Two axes of independence, on purpose: engine independence (Gate 4) and model independence (the critic) — the judge can't share the coder's weights any more than the second scanner can share axe's rules.
  • express + ws for a build-step-free live dashboard; Pomerium as the identity-aware access layer; Zero as the self-deploy final act.
  • The loop itself is a Ralph-style runner: all state lives in files and git, every round ends in a commit (accept or revert), and JOURNAL.md records what happened and why.

Challenges we ran into

  • The source mapper was the riskiest part, so we built it first behind a hard Saturday-noon gate: if acceptance wasn't passing by noon, swap targets. It passed at 96% (24/25) — the single miss being a genuinely ambiguous repeated table cell that the mapper correctly refused to guess.
  • Bedrock streaming was blocked account-wide behind an Anthropic use-case form. Rather than stall, we ran the fixer on subscription auth and moved the critic to Akash — which turned a blocker into a stronger independence story and cost fractions of a cent all weekend.
  • The gates had to survive our own adversarial audit. A subagent audit found seven false-PASS bugs — ways a suppression could slip through (bare alt, entity-whitespace alt, deleted elements that dodged detection, Gate-4 baselines going NaN). We hardened the harness against itself, because a gate you can fool isn't a gate.
  • We caught ourselves overclaiming. Early receipts had hardcoded Bedrock model IDs for calls that never actually ran. We fixed the receipts to state exactly what executed. Honesty is load-bearing here — overclaiming is literally what got accessiBe fined.
  • Keeping spend at ~$0 while still shipping live: Zero deploys with a hard --max-pay 0 cap, and total weekend spend was ~$0.001.

Accomplishments that we're proud of

  • A fix that gets caught and auto-reverted, live, on screen — receipt #003. That revert is the product.
  • A working loop across two pages (login 8→4 violations, forgot-password 7→4) with six honest receipts, including the caught failure.
  • Two independent verification axes (independent engine + independent model/provider) that together make "the fixer graded its own homework" impossible.
  • The whole harness — scanners, differ, four gates, isolated critic, receipts, dashboard, self-deploy — built for fractions of a cent, with the healed site live via Zero at $0.
  • We never crossed a prime directive to get unstuck. Everything Mend emits says "fixed and verified" or "reverted, caught by ."

What we learned

  • The model was never the bottleneck — the measurement was. A cautionary tale we kept in mind: "I let an AI agent optimize our database queries for 48 hours, then latency spiked 400%." The model wasn't missing; the proof was. Claude can write the fix. Only the harness can prove it.
  • Automated rules only cover ~30–40% of accessibility issues (Deque). That's why existence checks aren't enough and a vision-capable critic that judges truth is the way to climb past the ceiling — honestly labeled as roadmap.
  • One-time audits don't stick — ~1,427 of 2025's lawsuits hit companies that had already been sued. Verification belongs in a loop (and eventually in CI), not in a one-off scan.
  • Verification is the product. The scorers, the banned-pattern gate, the isolated critic, the receipts — that's the difference between a demo and evidence.

What's next for Mend

  • A GitHub Action: every PR gets a comment with verified fix commits and receipts, formatted for the person who actually buys this — the owner with a demand letter on his desk, and his lawyer.
  • Beyond static HTML: build-time data-mend-src annotations to map through React/Vue/framework builds where the served file isn't the source.
  • Climbing past the 30–40% scanner ceiling by leaning harder on the vision critic for the issues rules can't detect.
  • A governance layer (Nexla) that normalizes axe and IBM Equal Access's different violation schemas into one queryable violations-and-evidence data product — so a fleet of sites in CI emits receipts you can actually audit.
  • Receipt hand-off: bundle the before/after evidence and email it to the owner — a hand-off, never a compliance guarantee.

Built With

Share this project:

Updates