Mend is a self-verifying repair loop for web accessibility. Point it at any repo and each round it:
- Scans the rendered page with axe-core (Playwright).
- Maps each violation's DOM node back to the exact
file:linein source. - Patches the source — never the runtime. No injected scripts, no DOM mutation, no overlay behavior. That's the villain we replace.
- 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, emptyalton 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).
- 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.
- 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.mdrecords 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-whitespacealt, deleted elements that dodged detection, Gate-4 baselines goingNaN). 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 0cap, 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-srcannotations 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
- akash
- anthropic
- aws-bedrock
- axe-core
- bash
- bootstrap
- claude
- claude-code
- css
- deepseek
- express.js
- git
- html
- ibm-equal-access
- javascript
- node.js
- pixelmatch
- playwright
- pngjs
- pomerium
- qwen
- websocket
- zero
Log in or sign up for Devpost to join the conversation.