Skip to content
skc-learnPublic

About

Fringe — a UX-quality layer for AI coding agents. Ponytail trims your code; Fringe handles your edges.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Fringe

Your AI coding agent builds the UI. Fringe checks the edges it forgets.
Ponytail trims your code. Fringe handles your edges.

npm tests MIT license Node 18+

Fringe is an accessibility (WCAG) and UX checker for Claude Code and other AI coding agents. AI agents write UI fast, and quietly skip the unglamorous parts: an alt on the image, a label on the input, a name on the icon button, a visible focus ring. Fringe is a static checker that runs after every edit, hands the problems back to the agent, and keeps the agent from finishing with broken markup. Nothing leaves your machine.

Measured: in our benchmark, an agent asked for ordinary UI left error-level accessibility problems in 4 of 12 runs on its own, and 1 of 12 with Fringe, at the same cost. (Small test, honest caveats inside.)


Start in 60 seconds

Pick one:

A. Claude Code plugin (hook + skills in one step). Send these as two separate prompts:

/plugin marketplace add skc-learn/fringe
/plugin install fringetool@fringe

B. One command (any Claude Code project, nothing to install first):

npx @fringetools/cli init            # this project
npx @fringetools/cli init --global   # once, for every project

Not sure whether it's set up? Run npx @fringetools/cli with no arguments: it checks the folder and tells you if the post-edit check isn't wired yet. Already inside Claude Code? Type /fringe-setup for a guided setup.

C. Just try the checker, no agent needed:

npx @fringetools/cli check

Needs Node.js 18 or newer. Using Cursor, Copilot, Windsurf, Codex, CI or pre-commit instead? See INSTALL.md.

See it work

Ask your agent for any UI, for example "add a signup form with email and password". Behind the scenes:

agent writes src/Signup.tsx
  └─ Fringe runs automatically  →  "2 errors: inputs have no label"
agent adds the labels
  └─ Fringe runs again          →  clean

You can also run it yourself:

$ npx @fringetools/cli check
fringe · stack jsx,tailwind · 3 files
[ERROR] FR-201 src/App.tsx:15 — <img> missing alt text (add alt="description" (or alt="" if decorative))
[ERROR] FR-204 src/App.tsx:17 — heading skips from h1 to h3 (don't skip heading levels for visual size)
health 34/100 · 6 errors · 2 review · 0 signals

Errors make the command exit 1 (so CI fails too). Everything else is advice and never blocks.


What you get

Playbooks arrive on their own. Ask your agent to build a carousel, a login form, a data table, a modal… and Fringe adds the matching checklist (22 of them, based on the W3C ARIA Authoring Practices and WCAG) to its context before it starts. Items Fringe can verify are marked as such; the rest are the agent's to get right. Nothing is added for other requests. Read any of them yourself with npx @fringetools/cli explain pattern carousel.

Six skills your agent can use (Claude Code: type the slash command):

Skill Use it to
fringe Always-on rules: cut what users don't need, fix every flagged error, never silence a rule to get green
/fringe-review "Review this page": ranked, plain-English findings with the fix for each
/fringe-audit Audit a whole repo: top problems, a fix order, and an offer to set a baseline
/fringe-debt List everything silenced or deferred (suppressions and baseline)
/fringe-setup Guided onboarding from inside Claude Code: checks the environment, wires the hook, offers a baseline, records your critical pages
/fringe-help Quick reference

Installed as a plugin, the names are namespaced: /fringetool:fringe-review. The review and audit skills run the checker, so Claude Code asks you to approve that command once.

36 rules in three tiers, each with a fix hint and (for accessibility) its WCAG criterion:

Tier Gates? Examples
Edges (error) Yes missing alt, unnamed buttons, unlabeled inputs, skipped headings, removed focus rings, onClick on a <div>, invalid aria-*
Judgment (review) No data fetching with no loading/error state, dark patterns (fake countdowns, pre-checked consent, confirm-shaming, infinite scroll, drip pricing), "Something went wrong" with no next step, form basics (wrong input type, no autocomplete), "click here" and href="#" links, missing page lang/title or a viewport that blocks zoom, animation with no reduced-motion handling, autoplaying sound, hover-only interactions
Polish (signal) No lorem ipsum / TODO text left in the UI, hardcoded colors vs your design tokens, off-scale spacing/type, low contrast, tiny tap targets, the "AI look" (purple gradient, italic serif hero, card-in-card, emoji headings)

Full rule table: CLI reference.


Everyday recipes

I want to… Do this
Check my project npx @fringetools/cli check (a folder, default ., or one file)
Know what to fix first npx @fringetools/cli plan (add --scan http://localhost:3000 to include the live page): batches ordered by impact, shared components first, with the fix for each rule
Scan pages behind a login npx @fringetools/cli login http://localhost:3000/login (log in once in the window), then scan <url> --storage-state .fringe/auth.json. For CI, script the login with test credentials from env vars (how)
See the running page (real contrast, keyboard, menus and modals) npm i -D playwright-core axe-core, then npx @fringetools/cli scan http://localhost:3000. Add a fringe.scan.json to also audit states like "menu open" (how)
Use another agent (Codex, Cursor, Copilot, Gemini…) npx @fringetools/cli init --for cursor,codex writes the rules file each reads; add --git for a commit gate that works with any agent
Hand the fixing to another agent or CI npx @fringetools/cli handoff > prompt.md, give it to the agent, then npx @fringetools/cli verify (exit 0 only when done; reports anything it silenced)
See which rules don't suit my repo npx @fringetools/cli rules: per rule, findings open vs baselined vs silenced; mostly-overridden rules are flagged
Understand a rule npx @fringetools/cli explain FR-203: why it matters, the right fix, the tempting wrong one
Use it on a repo that already has problems npx @fringetools/cli check --update-baseline, commit fringe.baseline.json. Now only new problems gate
Silence a real false positive Put // fringe-ignore FR-203 on the line or the line above (JSX: {/* fringe-ignore FR-203 */}, HTML: <!-- … -->). It is always counted in the report
Turn a rule off everywhere fringe.config.json: { "disable": ["FR-214"] }
Fail CI on accessibility errors Run npx -y @fringetools/cli check in your pipeline: exit code 1 on errors
Get machine-readable output --json (full report) or --hook (one-line CI gate)
Keep a history of runs --record appends to .fringe/ledger.jsonl; npx @fringetools/cli open shows it at http://127.0.0.1:4173

Every command, flag, exit code and config key: CLI reference.


Troubleshooting

Problem Fix
npx: command not found Install Node.js 18+ from nodejs.org
Agent never gets Fringe's feedback The hook only fires when the agent edits or writes a file. Restart Claude Code after installing; check .claude/settings.json has the fringe check --claude-hook entry (re-run npx @fringetools/cli init if not)
/fringe-review asks for permission Expected: it runs the checker. Approve once, or allow Bash(npx:*)
"No findings" but I see problems Fringe is static. It can't judge real colors on images, runtime focus order, or whether your copy is good
Hundreds of findings on an old repo Use the baseline (see above); fix at your own pace
A rule is wrong for my case fringe-ignore it on that line, and please report the false positive
exit 2 / "internal error" The message names the cause: bad fringe.config.json, corrupt fringe.baseline.json, or an invalid .claude/settings.json
It checked a folder I don't want Add globs to ignore in fringe.config.json, e.g. "examples/**" (use the dir/** form)
A .fringe/ folder appeared in my project It is local state (run history, hand-offs, saved login sessions). Fringe creates it with its own .gitignore of *, so git never sees it
Remove it Plugin: /plugin uninstall fringetool. Init: delete the Fringe entry in .claude/settings.json and the .claude/skills/fringe* folders

What the plugin runs

  • Two hooks, plugin/hooks/hooks.json, each a short plain shell script. When you ask Claude to build something, prompt.sh runs one dependency-free file inside the plugin and adds the matching playbook. After Claude edits a file, check.sh runs the fringe you installed in the project (or on your PATH) and says nothing if there is none. Nothing is fetched from npm or anywhere else, and a test fails if a hook ever uses npx, npm, uvx or a URL.
  • The vendored file is plugin/vendor: the playbook hook bundled as one readable (unminified, about 24 KiB) file built from packages/cli/src/pluginHook.ts. The plugin ships no third-party code, no browser, login, hand-off or init code, and does not read environment variables. scripts/vendor-plugin.mjs regenerates it. For the post-edit check, npm i -D @fringetools/cli in the project.
  • The package on npm is this repo's packages/cli (readable TypeScript source, MIT), published by a tagged GitHub Actions run with npm provenance and a shipped npm-shrinkwrap.json. The plugin does not depend on it at run time.
  • It reads the file that was edited and, for project-wide checks, the project's own source and fringe.config.json. It writes only under .fringe/ and, if you ask, fringe.baseline.json.
  • It does not make network calls, send telemetry, or change Claude's settings on its own, and the hook and skills never read credentials. Three commands you run yourself are the exceptions: fringe scan <url> opens the page you name in a local browser; fringe login <url> saves a browser session you create by logging in yourself to .fringe/auth.json (keep it out of git); and fringe init writes the hook and skills into your .claude/ folder. A fringe.scan.json login script may reference environment variables you name as ${env:NAME}: Fringe reads only those, types them into the page you pointed it at, and never prints or saves their values.
  • The skills (/fringetool:fringe-review and the others) are Markdown instructions; when you invoke one, it asks Claude to run the fringe command (from your own install, or npx if you have none) with your approval.

Privacy: Fringe reads your source files locally and makes no network calls and sends no telemetry. The plugin downloads nothing at run time; the only download anywhere is npx fetching the package if you choose the npx @fringetools/cli route. Its run history stays in your repo (.fringe/).


How it thinks

Fringe encodes a three-step ladder for agents: Flow (cut what users don't need, with evidence) → Edges (never skip accessibility and states, checked and gated) → Polish (tokens, scales, no "AI look", advice only). Every number it shows is labelled verified (the checker measured it) or judged (the agent decided it). The agent never grades its own work where a measurement exists.

Works alongside Ponytail: Ponytail keeps the code small and promises never to cut accessibility; Fringe is the check that verifies the promise. Also complementary to Impeccable and Design with Intent (positioning in docs/product.md).


Roadmap

Where Fringe is going, in plain terms (the full plan, with the reasons and the evidence that moves each item, is in docs/ROADMAP.md):

When Theme What you'll get
Now (v0.1.x) Easy to try and trust Real-world false-positive fixes, issue templates, a larger public benchmark
Shipped (v0.2) Know what to fix, and how fringe plan (priority order, shared components first), fringe explain (recipes), single-file checks, fix recipes inside the agent hook
Next Close the loop Tell the agent what its last edit broke, see which rules your repo overrides most
Then (v0.3) Works wherever you work A GitHub Action with PR annotations, SARIF for GitHub code scanning, pre-commit config, rules files for Cursor/Copilot/Windsurf
Later (v0.4) See the trend A proper dashboard: health over time, per-project board, handoff report
v1.0 Beyond static Design-token drift, real-browser checks (screenshots, rendered contrast), stable output schemas

Want something sooner? Open an issue: what real use asks for decides the order.


Docs

Use it: INSTALL.md · CLI reference · AGENTS.md (rules file for any agent) · Skills Understand it: Product · PRD · Architecture · Decisions · Test strategy · Benchmark · Docs index

Contributing

Bug reports, false positives and rule ideas are all welcome as issues. Code changes: every change starts as a failing test; adding a rule is a documented recipe. Start at CONTRIBUTING.md.

Privacy and terms

Privacy Policy · Terms of Use

License

MIT. The dark-pattern taxonomy is adapted, with attribution, from Design with Intent's CC0 library.

About

Fringe — a UX-quality layer for AI coding agents. Ponytail trims your code; Fringe handles your edges.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages