AI agents write code fast — but they repeat the same anti-patterns everywhere. God components, fat controllers, hardcoded secrets, prop drilling. Left unchecked, these compound into a codebase no one can maintain. You either stay dependent on AI tools to untangle it, or pay a developer to rewrite everything from scratch.
Type aps to scan, aps -i for interactive mode, or help to see all commands.
INTERACTIVE DEMO
Try "aps" to scan, "aps -i" for interactive mode, or "help" for all commands.
$
HOW IT WORKS
Three commands. Zero config.
01
Install
npm i -D anti-pattern-sniffer
One package. Zero dependencies. Works with Node.js 20+.
02
Scan
npx aps
Auto-detects your framework from package.json. Scans all source files in parallel.
03
Fix
npx aps -i
Browse issues in the interactive TUI. Copy fixes as AI prompts. Ignore false positives.
FRAMEWORK SUPPORT
14 sniffers. 3 frameworks.
Each sniffer targets a specific architectural anti-pattern with regex-based heuristics. No AST parsing, no dependencies — just fast, accurate detection.
React
3 SNIFFERS
prop-explosion
god-hook
prop-drilling
Express
6 SNIFFERS
god-routes
fat-controllers
missing-error-handling
no-input-validation
callback-hell
hardcoded-secrets
NestJS
5 SNIFFERS
god-service
missing-dtos
business-logic-in-controllers
missing-guards
magic-strings
SEE IT IN ACTION
Before and after
Every detection comes with a concrete suggestion. Here are three sniffers catching real problems.
prop-explosion
Components with too many props are doing too much. Group related props into objects and split into sub-components.
Browse issues with keyboard navigation. Expand details, filter by framework, copy fixes as AI prompts for ChatGPT or Claude.
{..}
Plugin System
Write custom sniffers in ~20 lines. 5-stage validation for security. Register in .snifferrc.json and run alongside built-in rules.
>>
CI/CD Ready
Exit codes for pass/fail. JSON output for parsing. Husky pre-commit hooks. GitHub Actions workflow included.
▦
Monorepo Support
Auto-detects npm, pnpm, Nx, Turborepo, and Lerna workspaces. Per-package config inheritance. Just run aps — it figures out the rest.
∅
Zero Dependencies
Built entirely on Node.js built-ins. No AST parsers, no transitive deps, no supply chain risk. Fast installs, small footprint.
⚙
Fully Configurable
Tune every threshold in .snifferrc.json. Disable sniffers, change severity levels, set per-framework rules. Setup wizard included.
FAQ
Common questions
How is this different from ESLint?
ESLint checks code style and syntax. APS checks architecture — are your components too big? Are your services doing too much? Are your route handlers too fat? These are structural problems that ESLint doesn't target.
Why regex instead of AST parsing?
Zero dependencies. Regex-based heuristics are fast, portable, and good enough for architectural pattern detection. APS isn't checking syntax — it's checking structure.
Does it work with TypeScript?
Yes. APS scans .ts, .tsx, .js, and .jsx files. Since it uses regex heuristics rather than a parser, TypeScript syntax is handled naturally.
Can I write my own sniffers?
Yes. The plugin system lets you write custom sniffers in ~20 lines of JavaScript. They go through 5-stage validation for security and run alongside built-in rules.
Will it slow down my CI?
No. APS scans files in parallel and uses only regex matching — no AST parsing overhead. A typical project scans in under 2 seconds.
CHANGELOG
What's new
v0.6.0V5 False Positive Reduction2026-03-28
Skip typeof comparisons in magic-strings (e.g. typeof x === 'string')
Detect specialization wrappers, list containers, and render-slot injection in prop-drilling
Tree/recursive node bonus (+4) and SVG/positioning bonus (+3) for prop-explosion
371 tests passing
v0.5.0V4 False Positive Reduction2026-03-28
Multi-child composition detection for prop-drilling — distinguishes drilling from distribution
Skip method-call return comparisons in magic-strings (e.g. .getIsSorted() === 'asc')
Extended union type extraction for interface properties and function parameters
Reverted prop-explosion threshold from 10 back to 7