sniff Svelte Themes

Sniff

AI-powered QA testing tool. 5 checks in one command: source scanning, accessibility (axe-core), visual regression (pixelmatch), performance (Lighthouse), and AI exploration. Works with React, Next.js, Vue, Svelte, Angular. Zero config. Native MCP integration.

Sniff

npm License CI Node Stars

Scan your source code, your live site, or both. Finds bugs before your users do.

Get started · What it finds · Commands · Stacks · Demo videos

Sniff flow: source -> radar scanner -> findings

The 30-second pitch

You ship a feature. A user finds the bug before you do. Sniff is the opposite of that.

Sniff is a tiny CLI that reads your source, opens your app in a headless browser, and hunts down bugs across eight dimensions — functional, visual, accessibility, performance, dead links, API endpoints, broken imports, and optional AI-assisted exploration. No API key required. No manual Playwright setup. No config.

npx sniff-qa

That's the whole setup. The rest of this README is detail.

Why developers love it

  • One command. npx sniff-qa auto-detects your framework, your dev server, your test scenarios. If npm run dev is running, sniff finds it.
  • Zero API keys by default. Deterministic local QA is the default. Codex, Claude, Gemini, Ollama, Anthropic, and OpenAI providers are optional enhancements.
  • Eight checks, every time. Accessibility + visual regression + performance + dead links + API contracts + source scanning + broken imports + browser runtime hooks — out of the box.
  • Talks to your editor. Ships as an MCP server. Just say "scan this project" in Claude / Cursor / Copilot / Continue / Windsurf / Codex / Gemini.
  • CI-ready. sniff --ci emits JUnit, tracks flakes, and fails on severity thresholds you set. sniff ci generates the GitHub Actions workflow.
  • Actually explains the fix. Every finding cites the rule, the file, the line — and /sniff-fix generates the patch.

Get started

Use from the terminal

cd ~/projects/my-app    # go to your project
npx sniff-qa            # that's it

Sniff auto-detects everything: your framework, your dev server port, and your running app. If npm run dev is running, sniff finds it and runs browser checks too. No flags needed.

You can also be explicit:

npx sniff-qa --url http://localhost:3000    # specific local URL
npx sniff-qa --url https://myapp.com        # production URL

No API keys. No manual Playwright install. No config files. Everything works out of the box. Browser checks auto-install the configured Playwright browser projects on first CLI run.

Use from your AI editor

Sniff ships as an MCP server. Add it to your editor, then ask your AI to scan.

Claude Code plugin marketplace (one-command install)
claude plugin marketplace add Aboudjem/10x
claude plugin install sniff@10x

This installs sniff as a Claude Code plugin from the 10x marketplace. Skills, commands, and the MCP server are wired up automatically.

Claude Code (MCP server only)
claude mcp add sniff-qa npx sniff-qa --mcp
Cursor

Add to ~/.cursor/mcp.json:

{ "mcpServers": { "sniff-qa": { "type": "stdio", "command": "npx", "args": ["sniff-qa", "--mcp"] } } }
VS Code + Copilot

Add to .vscode/mcp.json:

{ "servers": { "sniff-qa": { "type": "stdio", "command": "npx", "args": ["-y", "sniff-qa", "--mcp"] } } }
Codex CLI
codex mcp add sniff-qa -- npx -y sniff-qa --mcp
Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{ "mcpServers": { "sniff-qa": { "command": "npx", "args": ["sniff-qa", "--mcp"] } } }
Gemini CLI

Add to ~/.gemini/mcp_config.json:

{ "mcpServers": { "sniff-qa": { "command": "npx", "args": ["sniff-qa", "--mcp"] } } }
Continue.dev

Add to .continue/mcpServers/sniff-qa.yaml:

mcpServers:
  sniff-qa: { command: npx, args: [sniff-qa, --mcp], type: stdio }
OpenClaw
clawhub install sniff-qa

Then ask: "Scan this project for issues" or "Check accessibility on localhost:3000" or "Discover and run E2E tests"

MCP tools: sniff({ mode: "scan" | "run" | "discover" | "report" }) — unified entry point. Plus sniff_install when Playwright browser binaries are missing. MCP returns a structured needsSetup payload instead of doing a long install inside stdio; call sniff_install or run the shown npx playwright install ... command, then retry. The legacy per-mode tools (sniff_scan, sniff_run, sniff_discover, sniff_report) remain available but are deprecated in v0.5 and will be removed in v0.7.

Install as a dev dependency

npm install -D sniff-qa
{
  "scripts": {
    "qa": "sniff"
  }
}

That's all you need. Sniff auto-detects your dev server when it's running.

Requires Node.js 22+. Playwright installs automatically on first CLI browser scan; MCP asks you to run sniff_install when setup is missing.


Usage

npx sniff-qa                                        # scan source + auto-detect dev server
npx sniff-qa --url https://myapp.com                # scan source + specific URL
npx sniff-qa ./path/to/project                      # scan a specific directory
npx sniff-qa --ci                                   # CI mode (JUnit output, no AI explorer)
npx sniff-qa --url http://localhost:3000 --explore  # opt-in AI exploration
npx sniff-qa --verbose                              # show classifier top 3 + matched signals
npx sniff-qa discover --dry-run                     # preview generated scenarios, no browser
npx sniff-qa discover --force-app-type saas         # skip classification, treat as SaaS

Sniff auto-detects your dev server by reading package.json scripts plus vite.config, nuxt.config, astro.config, and angular.json, then probing the framework's default port and the next 20 after it (to catch auto-increment when the default is taken). If a port responds with framework markers (Next.js, Vite, Nuxt, Astro, Remix, SvelteKit, Angular), browser checks run automatically. Ghost-process ports like macOS AirPlay on :5000 no longer collide.


What it finds

Sniff checks: source bugs, dead links, API endpoints, broken imports, accessibility, visual regression, performance, optional AI explorer

Source checks run on every scan. Browser checks run automatically when sniff detects a running dev server, or when you pass --url.


Example output

Sniff terminal output

Commands

Slash commands (AI editors)

Command What it does
/sniff Scan the project. Auto-detects dev server, runs source + browser checks
/sniff-fix Scan and auto-fix safe issues (debugger, console.log, etc.)
/sniff-report Show results from the last scan

CLI

sniff                              Scan source + auto-detect dev server
sniff --url <url>                  Scan source + test specific URL
sniff --url <url> --ci             Full audit for CI pipelines
sniff <path>                       Scan a specific directory
sniff discover                     Autonomous E2E discovery (scenarios + edge cases)
sniff discover --regenerate-only   Write sniff-scenarios/ tree without running
sniff fix                          Auto-fix safe issues (debugger, console.log)
sniff fix --check                  Dry run: show what would be fixed
sniff init                         Create sniff.config.ts
sniff ci                           Generate GitHub Actions workflow
sniff report                       Show last scan results
sniff update-baselines             Accept current visual baselines
sniff doctor                       Check your environment (Node, Playwright, config, dev server)
sniff --help                       Show all commands and flags
sniff --version                    Show version
All flags
Flag What it does
--url <url> Enable browser checks (accessibility, visual, performance, AI)
--ci CI mode: skip AI explorer, add JUnit output, track flaky tests
--explore Opt into AI-assisted exploration after browser checks
--no-explore Compatibility flag; exploration is off by default
--no-browser Source only even if --url is set
--max-steps <n> Limit AI explorer steps (default: 50)
--no-headless Show the browser window
--headed Alias for --no-headless
--format html,json,junit Choose report formats
--fail-on critical,high Severities that cause non-zero exit
--track-flakes Track test flakiness across runs
--json JSON output for scripts
--verbose Print classifier top-3 guesses and matched signals per dimension
--dry-run Discover: generate scenarios without launching browser or writing reports
--force-app-type <type> Discover: bypass the classifier (e.g. saas, ecommerce, booking)
--app-type <types> Discover: filter classifier guesses to these app types (comma-separated)

Works with any stack

Sniff auto-detects your framework. No config needed.

React
JSX / TSX
Next.js
App + Pages
Vue
SFC
Svelte
Components
Angular
Templates
Express
Routes
Vanilla
HTML / CSS

API discovery also supports Fastify, Hono, tRPC, and GraphQL.


Configuration

Sniff works with zero config. Only create a config file if you want to customize.

npx sniff-qa init           # auto-detects: .ts if TypeScript, .mjs if ESM, .js otherwise
npx sniff-qa init --ts      # force TypeScript config
npx sniff-qa init --js      # force JavaScript config (respects package.json "type")
sniff.config.ts reference
import { defineConfig } from 'sniff-qa';

export default defineConfig({
  // Save your URL so you can just run `sniff`
  browser: {
    baseUrl: 'http://localhost:3000',
    projects: ['chromium'], // also supports 'firefox' and 'webkit'
  },

  // Viewports to test
  viewports: [
    { name: 'mobile', width: 375, height: 667 },
    { name: 'desktop', width: 1280, height: 720 },
  ],

  // Toggle scanner groups
  scanners: ['source', 'repo-analyzer', 'e2e', 'accessibility', 'visual', 'performance'],
  accessibility: { enabled: true, standard: 'wcag21aa' },
  visual: { enabled: true, threshold: 0.1 },
  performance: { enabled: true, budgets: { lcp: 2500, fcp: 1800, tti: 3800 } },

  // Optional AI providers. Default is deterministic local QA with provider: 'none'.
  ai: {
    provider: 'none', // codex-cli, claude-code, anthropic-api, openai-api, gemini-cli, ollama
    model: undefined,
    command: undefined,
    baseUrl: undefined,
  },

  // Optional AI explorer, run only with --explore
  exploration: { enabled: true, maxSteps: 50 },

  // Dead link checker
  deadLinks: {
    scanCode: false,         // docs/HTML by default; opt into JSX/TSX/JS/TS to reduce noise
    checkExternal: true,
    timeout: 5000,
    retries: 2,
    ignorePatterns: [],
    maxConcurrent: 10,
  },

  // API endpoint discovery
  apiEndpoints: {
    checkErrorHandling: true,
    checkValidation: true,
    checkAuth: true,
    checkSecrets: true,
    frameworks: [],          // empty = auto-detect all
  },

  // Turn off specific rules
  rules: {
    'debug-console-log': 'off',
  },
});

Provider selection can also come from environment: SNIFF_AI_PROVIDER, SNIFF_AI_MODEL, SNIFF_AI_COMMAND, and SNIFF_AI_BASE_URL. API-backed providers use their normal keys: ANTHROPIC_API_KEY or OPENAI_API_KEY. If the selected provider is missing, Sniff skips AI generation and keeps the deterministic QA run moving.

All rule IDs
Rule Severity What it checks
debug-console-log medium console.log/debug/info
debug-debugger high debugger statements
placeholder-lorem high Lorem ipsum text
placeholder-todo medium TODO comments
placeholder-fixme high FIXME comments
placeholder-tbd medium TBD markers
hardcoded-localhost medium localhost URLs
hardcoded-127 medium 127.0.0.1 URLs
broken-import medium Unresolved imports
dead-link-internal high Broken file links
dead-link-external medium 404 external URLs
dead-link-anchor medium Missing anchors
api-no-error-handling medium Routes without try/catch
api-no-validation medium POST/PUT without validation
api-no-auth low Routes without auth
api-hardcoded-secret critical Hardcoded API keys

Set any to 'off' to disable.


CI integration

Run Sniff directly in CI:

npx sniff-qa --ci --format html,json,junit

Generate a GitHub Actions workflow:

npx sniff-qa ci

This writes .github/workflows/sniff.yml with Playwright caching, JUnit output, and report artifacts.

Flakiness quarantine: Tests that fail 3 of 5 runs get quarantined. They still run, still report, but won't block your pipeline.


Autonomous discovery

sniff discover                     # run against the detected dev server
sniff discover --regenerate-only   # write sniff-scenarios/ and exit (no run)

sniff discover reads your source (Prisma, Drizzle, TypeORM, Zod, GraphQL, OpenAPI, TS types), classifies what the app is (ecommerce, booking, saas, social, content, crm, auth-only, marketing, admin) with route tokens in English, French, Spanish, German, Portuguese, and Italian (a French SaaS on /fr/tableau-de-bord classifies correctly), generates happy-path journeys with real personas, enumerates edge variants (invalid email, XSS, payment declined, empty cart, offline, and more), and drives everything through Playwright.

Pass --verbose to see the top-3 candidates and every matched signal — useful for understanding why a classification happened. Pass --force-app-type <type> to skip classification entirely. Pass --dry-run to preview scenarios without launching a browser or writing reports.

Multilingual projects supported. The classifier matches French, Spanish, German, Portuguese (BR/PT), and Italian equivalents for every signature token, so a French SaaS on /fr/tableau-de-bord classifies the same as an English one on /dashboard.

What you get:

  • sniff-scenarios/_generated/<app-type>/<journey>.<variant>.scenario.md — reviewable scenarios with JSON frontmatter. Track them in git. Hand-edit them — sniff detects the change and asks before regenerating.
  • sniff-reports/discovery/ — HTML, JSON, and JUnit reports per run.
  • Flakiness quarantine for scenarios that fail 3 of the last 5 runs.

Flags:

Flag What it does
--url <url> Target URL (default: auto-detect dev server)
--max-scenarios <n> Cap total scenarios (default: 50)
--max-variants-per-scenario <n> Cap edge variants per scenario (default: 3)
--max-variants-per-run <n> Cap edge variants per run (default: 40)
--realism <profile> robot, careful-user, casual-user (default), frustrated-user, power-user
--seed <n> Replay a specific random seed
--only <filter> Filter scenarios by id substring or app type
--app-type <types> Filter classifier guesses to these app types (comma-separated, kept for back-compat)
--force-app-type <type> Bypass the classifier entirely — treat the app as this type
--verbose Print classifier breakdown (top 3 guesses + matched signals per dimension)
--dry-run Generate scenarios without launching the browser or writing reports
--regenerate Regenerate sniff-scenarios/ before running
--regenerate-only Regenerate and exit (no browser)
--force-regenerate Overwrite hand-edits without prompting
--non-interactive Skip prompts and the production-URL countdown
--verbose Print classification breakdown (top 3 guesses + matched signals per dimension)
--no-llm Skip Claude Code CLI polish (deterministic only)

Production-URL safety: when the target is not a local address, sniff prints a 5-second countdown banner before running. Hit Ctrl+C to cancel. No --allow-destructive flag.

LLM polish (optional): discovery can use the claude CLI to break close-call app-type classifications. Responses are cached under .sniff/discover/cache/. Pass --no-llm to skip.


How it works

Sniff pipeline
Architecture Sniff architecture

Privacy

No telemetry. No signup. No data collection. No API keys required. Your code stays on your machine unless you explicitly configure an API-backed AI provider.

[!NOTE] All deterministic checks work without any API key. Optional AI providers are off by default and must be selected through config or environment. Dead link checking validates external URLs but never sends your code.


Contributing

Add a source rule: each rule is a regex + severity in src/scanners/source/rules/. See CONTRIBUTING.md.


Built on Playwright · axe-core · Lighthouse · pixelmatch · Zod · MCP SDK · Anthropic SDK

LinkedIn X Website

Built by Adam Boudjemaa · Apache 2.0

Top categories

Loading Svelte Themes