Skip to main content

CLI

Static analysis for JS/TS,
free in your terminal.

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.

$ npx @vipr/cli analyze src/
Free, no account Read the CLI docs → MIT licensed No telemetry Node 22+

Where it fits

Your linter checks rules. Vipr scores the file.

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.

Analyses
25+ Across Core, React, Next.js, and TypeScript.
Bytes uploaded
0 Local engine. No account, no cloud, no telemetry.
Per file
< 3 sec Cold-start npx to colored summary table.

Under the hood

Twenty-five analyses. Here's what they actually catch.

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

Functions you can no longer reason about.

renderDashboard: cyclomatic 34, cognitive 52, max nesting 6.

Cyclomatic + cognitive complexity, Halstead volume, maintainability index.

Core · Dead code

Exports nothing imports.

3 exports in src/utils/format.ts have zero internal references.

Dead-code detection + unused-export analysis.

React · Hooks

Stale closures your linter missed.

useEffect on Dashboard.tsx:88 closes over userId, missing from the dep array.

Hook integrity + dataflow analysis (cyclical-dep detection).

React · Performance

Re-renders nobody asked for.

<UserList items={[…]} /> passes an inline array literal. That forces a re-render every parent tick.

Performance analysis + referential-stability checks.

Next.js · Boundaries

'use client' meets server-only data.

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

A .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

One file. Every run. Every machine.

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

$ vipr init --preset strict

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

Quality gates that fail loud, not late.

--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 Actions PR comment
# .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 Job artifact
# .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.

GitHub Actions guide · GitLab CI guide

Output

Three formats from one analysis pass.

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

Two ways in.

Try without installing

npx @vipr/cli analyze src/

No install. No commitment.

Install globally

npm install -g @vipr/cli

Once it earns its keep.

View @vipr/cli on npm.

Private Alpha

Want the IDE extension and Desktop app too?

They are in private alpha. Drop your email and you'll get an invite when each one opens up.