Inspiration

Over a billion people live with a disability, and a large share of the web still blocks them: images with no alt text, forms with no labels, buttons a keyboard can't reach. Most small teams never fix this. Audits are expensive, and existing tools only flag problems. They don't fix them, and nobody checks that a fix works.

We wanted a tool that goes all the way: find the issue, write the fix, prove it works, and hand the team a pull request.

What it does

CodeGuard is a coding agent for accessibility. You give it a repo URL and it runs this pipeline:

  1. Scans frontend files with a free rule-based pre-check, then a fast Nemotron model for subtler issues.
  2. Classifies each violation by category and severity.
  3. Grounds the fix in current guidance by looking up W3C, MDN and WebAIM pages with Tavily.
  4. Diagnoses the root cause and writes a minimal patch with Nemotron.
  5. Verifies every patch in an isolated Nebius sandbox: it applies the fix, runs axe-core in a real browser, and runs the project's own tests.
  6. Repairs failed fixes. The agent reads the real sandbox output and tries again, up to [3] attempts.
  7. Reports the before and after compliance score, with a diff, an explanation and the sources for every fix, and can open a real GitHub pull request.

A separate GitHub Action blocks pull requests that introduce new accessibility violations.

How we built it

Nebius Token Factory serves every model call through its OpenAI-compatible API. We use tiered models to keep cost low:

  • [Nemotron 3.5 Lightning] handles high-volume work: scanning, explanations and summaries.
  • [Nemotron 3 Ultra] handles root-cause diagnosis and patch writing, behind a per-scan call limit and a dollar budget.

Nebius sandboxes are the verification engine. A fix only counts as verified if axe-core no longer reports the violation and the project's tests still pass. This is what separates CodeGuard from a tool that only suggests text.

Tavily supplies up-to-date accessibility guidance, so patches are based on current standards instead of model memory.

Stack: FastAPI (Python) backend, React + TypeScript + Tailwind frontend, WebSockets for live progress, Playwright + axe-core for testing, GitHub Actions for CI and the PR check, deployed on Nebius AI Cloud as a serverless endpoint.

Challenges

  • Wrong sandbox API. Our first sandbox client used guessed endpoints and failed with a 404. We went back to the real Nebius sandbox docs and rewrote the client.
  • Model output we couldn't trust. Early on, most generated patches were rejected by our validator because the code the model quoted didn't match the file exactly. Strict validation plus the repair loop fixed most of it.
  • Cost control. Ultra is about 16x the price of the fast model, so we added per-scan call and budget guardrails. A full scan costs about $[0.04].
  • Honest verification. Some issues, like heading order, depend on page-wide structure. We report these as "not verified" instead of claiming a fix.

Accomplishments

  • On our demo site, the compliance score went from [X]% to [Y]%, with [N] of [M] violations fixed and verified.
  • [K] fixes passed only after the agent read a failure and repaired its own patch.
  • Every fix in the report comes with a diff, a plain-English explanation, sources, and verification evidence.

What we learned

Separating "find", "reason" and "verify" matters. Cheap models are good enough for most scanning, and the expensive model earns its cost only on diagnosis and patch writing. Running real tests in a sandbox changes what you can trust the model to do.

What's next

  • Persistent storage and team dashboards to track compliance over time
  • Auto-fix in CI (today CI only detects)
  • Checks for captions, i18n screen-reader announcements and reduced motion
  • Support for more frameworks

Known limitations

State is held in memory (scan history is lost on restart), the PR feature only works on repos the token can write to, and some page-structure issues need manual review.

Built With

Share this project:

Updates

Submission history