Core · Complexity
Functions you can no longer reason about.
renderDashboard: cyclomatic 34, cognitive 52, max nesting 6.
Cyclomatic + cognitive complexity, Halstead volume, maintainability index.
CLI
Twenty-five analyses across JS, TS, React, and Next.js. Cyclomatic and cognitive complexity, stale-closure detection, dead code, Next.js boundary mistakes. One command, no account, no telemetry.
Where it fits
ESLint, tsc, and Knip catch what they're built to catch. Vipr sits next to them and scores every file on complexity, maintainability, and the React anti-patterns nobody else flags.
ESLint
ESLint catches style violations and a handful of bugs in your editor. Vipr scores the file underneath them: complexity, churn, hotspots.
tsc
tsc tells you the types are wrong. Vipr tells you the file is unmaintainable even when the types are right.
Knip
Knip finds unused exports. Vipr finds those plus the components quietly bloating into hotspots: Halstead volume, maintainability index, trend.
Under the hood
Vipr ships four analyzer plugins. Each one runs locally against your AST and surfaces findings your linter doesn't have an opinion on.
Core · Complexity
renderDashboard: cyclomatic 34, cognitive 52, max nesting 6.
Cyclomatic + cognitive complexity, Halstead volume, maintainability index.
Core · Dead code
3 exports in src/utils/format.ts have zero internal references.
Dead-code detection + unused-export analysis.
React · Hooks
useEffect on Dashboard.tsx:88 closes over userId, missing from the dep array.
Hook integrity + dataflow analysis (cyclical-dep detection).
React · Performance
<UserList items={[…]} /> passes an inline array literal. That forces a re-render every parent tick.
Performance analysis + referential-stability checks.
Next.js · Boundaries
checkout/page.tsx is 'use client' but its only fetch is a server-only no-store.
Rendering analysis + server/client + data-fetching analysis.
TypeScript · Type safety
.ts extension that ships JavaScript. 14 as assertions, 3 any returns from public exports, 1 unjustified @ts-ignore.
Type-safety coverage + declaration-shape analysis.
And nineteen more: security, accessibility, route structure, hook ordering, declaration shape. See the full catalog.
Configure
Drop a .vipr.config.json at your repo root. Every vipr analyze invocation (yours, your teammate's, CI's) uses the same thresholds, the same ignores, the same severity rules.
Three presets set sane defaults: strict, balanced, lenient. Override
only what you care about: tighten cyclomatic to 10 for src/core/**, ignore src/legacy/** until you get to it, demote a React
rule from error to warn while you migrate.
The config is the contract between local dev and CI. When the build fails, it fails for the same reason it failed on your laptop.
Bootstrap
Full schema: vipr.config.json reference.
{
"$schema": "https://vipr.dev/schema/config.json",
"preset": "strict",
"include": ["src/**/*.{ts,tsx}"],
"exclude": ["src/legacy/**", "**/*.test.ts"],
"thresholds": {
"cyclomatic": 10,
"cognitive": 15,
"maintainabilityIndex": 65
},
"rules": {
"react/exhaustive-deps": "error",
"react/inline-object-prop": "warn",
"next/client-server-boundary": "error"
},
"ci": { "failOnCritical": true, "failThreshold": 70 }
} Continuous integration
--fail-on-critical exits non-zero on any critical finding. --fail-threshold 70 fails the build below a numeric floor. --format markdown -o report.md writes a PR-ready summary you can post as a comment. Same flags, any runner.
# .github/workflows/quality.yml
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx @vipr/cli analyze src/ --fail-on-critical \
--format markdown -o vipr.md
- uses: marocchino/sticky-pull-request-comment@v2
with: { path: vipr.md } Runs on every PR. Posts a sticky markdown comment with the report.
# .gitlab-ci.yml
vipr:
image: node:22
script:
- npx @vipr/cli analyze src/ \
--fail-threshold 70 \
--format json -o vipr.json
artifacts:
paths: [vipr.json]
when: always JSON dropped as a job artifact. Pipe it into MR widgets or downstream jobs.
Output
Same analysis. Three readers: your terminal, your PR reviewer, your agent. Pick the format based on who is reading it.
CLI
--format cli Color-coded summary table with complexity scores and severity breakdown. Default.
Markdown
--format markdown
Drops into PR comments, docs, or Slack. Pipe to a file with -o.
JSON
--format json Structured output for CI, dashboards, and agent consumption.
JSON, on a critical finding
{
"format": "json",
"data": {
"filePath": "src/components/Dashboard.tsx",
"score": 48,
"complexity": {
"cyclomatic": 34,
"cognitive": { "complexity": 52, "maxNesting": 6 },
"maintainability": { "index": 48, "rating": "C" }
},
"insights": { "critical": 1, "warning": 4, "info": 2 },
"criticalInsights": [
{
"severity": "critical",
"category": "react",
"message": "Prop drilling four levels deep",
"line": 126
}
]
}
} Want richer queries? The Vipr Desktop app exposes an MCP server with 15 tools your agent can call directly. Read more.
Install
Try without installing
No install. No commitment.
Install globally
Once it earns its keep.
Private Alpha
They are in private alpha. Drop your email and you'll get an invite when each one opens up.