zdenham/jev-lint

Lint JavaScript and TypeScript against plain-English project conventions with Jev.

TypeScript

1

6 commits

updated Sep 19, 2026

See the code

See what people are saying (1)

README

jev-lint

Check JavaScript and TypeScript code against project conventions written in plain English. Write a rule or point to a Markdown file with examples; Jev evaluates the relevant code and reports possible violations.

Built for coding agents, with compact output by default and optional pretty or JSON output. Early release; review findings before making them block CI.

Write rules

Define your conventions in jev.config.json. Each rule has a name and a plain-English instruction, with optional file patterns:

{
  "files": ["src/**/*.{ts,tsx}"],
  "ignore": ["src/generated/**"],
  "rules": {
    "preserve-error-cause": {
      "instruction": "When rethrowing an unexpected error, preserve the original error as its cause.",
      "severity": "error"
    },
    "user-facing-errors": {
      "files": ["src/ui/**"],
      "instruction": { "file": "docs/conventions.md#user-facing-errors" }
    }
  }
}

Paths are relative to the config file. Rule-specific patterns narrow the top-level files selection. Severity defaults to warning; use error to fail the check.

For Markdown rules, include the convention, examples, and exceptions:

## User-facing errors

Explain what went wrong and what the user can do next.

Good: "We couldn't save your changes. Check your connection and try again."
Bad: "Mutation failed: ERR_UPSTREAM_502."

This applies to messages shown to users, not internal logs.

A #heading reference includes its subsections and code examples. Omit the fragment to use the whole file as one rule. Markdown files must be inside the config directory or its descendants. Examples guide the judgment; they are never executed.

Install

Requires Node.js 22.22+ and Git. Clone the repo, build it, and register the global command:

git clone https://github.com/zdenham/jev-lint.git
cd jev-lint
npm ci
npm run build
npm link
jev-lint --help

You can now run jev-lint from any project directory. Keep this checkout in place: the global command links to it. If your shell cannot find the command, ensure npm's global executable directory is on your PATH ($(npm prefix --global)/bin on macOS/Linux).

To update, run git pull, npm ci, and npm run build inside the checkout. To remove the global command, run npm uninstall --global jev-lint.

Set up your project

cd /path/to/your-project
jev-lint init

This creates jev.config.json without installing anything in your project. Edit its rules, then run jev-lint --dry-run to preview the scope and jev-lint to check it.

For live checks, get a Vercel AI Gateway API key. Set it in the environment, or put it in .env.local beside jev.config.json:

export AI_GATEWAY_API_KEY="your-key"

Selected source code and rules are sent to Jev through Vercel AI Gateway, using your account's credits. No Vercel deployment is needed. Add these to your project's .gitignore:

.env.local
.jev/reports/

Run

jev-lint --dry-run          # Preview files and rules; no API calls
jev-lint                   # Check configured files
jev-lint src/ui            # Narrow to a file or directory
jev-lint --changed main    # Check whole tracked files changed from main's merge-base
jev-lint --format pretty   # Human-readable code frames
jev-lint --format json     # Programmatic output

Agent output includes file locations, rule references, usage, and a saved report. Large results are truncated explicitly; defaults are 20 findings and 16 KiB of output.

[f_1] ERROR preserve-error-cause
src/save.ts:1:1
  Possible violation of preserve-error-cause; compare the code with the rule and its examples.
  ...
Rule: jev.config.json#/rules/preserve-error-cause/instruction
Report: /your-project/.jev/reports/<run-id>.json

Inspect a saved report without another API call:

jev-lint report /path/to/report.json --finding f_1
jev-lint report /path/to/report.json --offset 20 --limit 20

Use --summary for counts only, or --max-output-bytes to set the output budget. Run jev-lint --help for all options.

Cost and run limits

Every run prints input/output token counts and Gateway's billed and market costs. Illustrative output:

Usage: 3 requests | 5000 input tokens | 500 output tokens
Cost: $0.00021000 billed | $0.00021000 market

At $0.042 per million input tokens, 5,000 input tokens cost $0.00021. These are example numbers, not a benchmark. Actual cost depends on source size, rules, and current pricing. Missing usage or cost data is marked as incomplete or unavailable.

The default run budget is $1, with caps of 10 files, 10 requests, and 100,000 total input bytes. Set these in the top-level limits object of jev.config.json:

"limits": {
  "maxCostUsd": 1,
  "maxFiles": 10,
  "maxRequests": 10,
  "maxInputBytes": 100000
}

Omitted limits use the defaults. Override individual limits for one run:

jev-lint --dry-run                 # Offline estimate; no API calls
jev-lint --max-cost-usd 0.25        # Override the config's dollar budget
jev-lint --max-files 30 --max-requests 30

Live runs check current Gateway pricing before evaluation. An over-budget estimate prevents evaluation; reported costs are checked between requests, using market value even when credits reduce the bill. Dry-run estimates use a dated local pricing snapshot.

The dollar budget is a client-side guardrail, not a guaranteed billing cap: an in-flight request can cost more than estimated. Budget stops exit 2 and save partial results. A zero dollar budget blocks evaluation. Each selected file uses at most one evaluation request; fresh runs are not cached.

Limits and CI

Findings identify top-level declarations or class members. The initial version uses the selected file as context and does not resolve imports. Uncertain checks are counted separately, not treated as proof of compliance. The tool does not edit code.

Exit codes: 0 within finding limits, 1 error findings or excess warnings, 2 configuration or execution failure. To make warnings fail CI:

jev-lint --max-warnings 0

Development

npm run check   # Type checking, offline tests, and build
jev-lint --config examples/jev.config.json

Export AI_GATEWAY_API_KEY before running the example (or put it in examples/.env.local). The example intentionally reports one violation and exits 1. Source modules stay under 250 lines. Implementation notes and evaluation guidance live in plan/.

Contributors

zdenham

6 commits

zdenham/jev-lint

Lint JavaScript and TypeScript against plain-English project conventions with Jev.

TypeScript

1

6 commits

updated Sep 19, 2026

See the code

See what people are saying (1)

README

jev-lint

Check JavaScript and TypeScript code against project conventions written in plain English. Write a rule or point to a Markdown file with examples; Jev evaluates the relevant code and reports possible violations.

Built for coding agents, with compact output by default and optional pretty or JSON output. Early release; review findings before making them block CI.

Write rules

Define your conventions in jev.config.json. Each rule has a name and a plain-English instruction, with optional file patterns:

{
  "files": ["src/**/*.{ts,tsx}"],
  "ignore": ["src/generated/**"],
  "rules": {
    "preserve-error-cause": {
      "instruction": "When rethrowing an unexpected error, preserve the original error as its cause.",
      "severity": "error"
    },
    "user-facing-errors": {
      "files": ["src/ui/**"],
      "instruction": { "file": "docs/conventions.md#user-facing-errors" }
    }
  }
}

Paths are relative to the config file. Rule-specific patterns narrow the top-level files selection. Severity defaults to warning; use error to fail the check.

For Markdown rules, include the convention, examples, and exceptions:

## User-facing errors

Explain what went wrong and what the user can do next.

Good: "We couldn't save your changes. Check your connection and try again."
Bad: "Mutation failed: ERR_UPSTREAM_502."

This applies to messages shown to users, not internal logs.

A #heading reference includes its subsections and code examples. Omit the fragment to use the whole file as one rule. Markdown files must be inside the config directory or its descendants. Examples guide the judgment; they are never executed.

Install

Requires Node.js 22.22+ and Git. Clone the repo, build it, and register the global command:

git clone https://github.com/zdenham/jev-lint.git
cd jev-lint
npm ci
npm run build
npm link
jev-lint --help

You can now run jev-lint from any project directory. Keep this checkout in place: the global command links to it. If your shell cannot find the command, ensure npm's global executable directory is on your PATH ($(npm prefix --global)/bin on macOS/Linux).

To update, run git pull, npm ci, and npm run build inside the checkout. To remove the global command, run npm uninstall --global jev-lint.

Set up your project

cd /path/to/your-project
jev-lint init

This creates jev.config.json without installing anything in your project. Edit its rules, then run jev-lint --dry-run to preview the scope and jev-lint to check it.

For live checks, get a Vercel AI Gateway API key. Set it in the environment, or put it in .env.local beside jev.config.json:

export AI_GATEWAY_API_KEY="your-key"

Selected source code and rules are sent to Jev through Vercel AI Gateway, using your account's credits. No Vercel deployment is needed. Add these to your project's .gitignore:

.env.local
.jev/reports/

Run

jev-lint --dry-run          # Preview files and rules; no API calls
jev-lint                   # Check configured files
jev-lint src/ui            # Narrow to a file or directory
jev-lint --changed main    # Check whole tracked files changed from main's merge-base
jev-lint --format pretty   # Human-readable code frames
jev-lint --format json     # Programmatic output

Agent output includes file locations, rule references, usage, and a saved report. Large results are truncated explicitly; defaults are 20 findings and 16 KiB of output.

[f_1] ERROR preserve-error-cause
src/save.ts:1:1
  Possible violation of preserve-error-cause; compare the code with the rule and its examples.
  ...
Rule: jev.config.json#/rules/preserve-error-cause/instruction
Report: /your-project/.jev/reports/<run-id>.json

Inspect a saved report without another API call:

jev-lint report /path/to/report.json --finding f_1
jev-lint report /path/to/report.json --offset 20 --limit 20

Use --summary for counts only, or --max-output-bytes to set the output budget. Run jev-lint --help for all options.

Cost and run limits

Every run prints input/output token counts and Gateway's billed and market costs. Illustrative output:

Usage: 3 requests | 5000 input tokens | 500 output tokens
Cost: $0.00021000 billed | $0.00021000 market

At $0.042 per million input tokens, 5,000 input tokens cost $0.00021. These are example numbers, not a benchmark. Actual cost depends on source size, rules, and current pricing. Missing usage or cost data is marked as incomplete or unavailable.

The default run budget is $1, with caps of 10 files, 10 requests, and 100,000 total input bytes. Set these in the top-level limits object of jev.config.json:

"limits": {
  "maxCostUsd": 1,
  "maxFiles": 10,
  "maxRequests": 10,
  "maxInputBytes": 100000
}

Omitted limits use the defaults. Override individual limits for one run:

jev-lint --dry-run                 # Offline estimate; no API calls
jev-lint --max-cost-usd 0.25        # Override the config's dollar budget
jev-lint --max-files 30 --max-requests 30

Live runs check current Gateway pricing before evaluation. An over-budget estimate prevents evaluation; reported costs are checked between requests, using market value even when credits reduce the bill. Dry-run estimates use a dated local pricing snapshot.

The dollar budget is a client-side guardrail, not a guaranteed billing cap: an in-flight request can cost more than estimated. Budget stops exit 2 and save partial results. A zero dollar budget blocks evaluation. Each selected file uses at most one evaluation request; fresh runs are not cached.

Limits and CI

Findings identify top-level declarations or class members. The initial version uses the selected file as context and does not resolve imports. Uncertain checks are counted separately, not treated as proof of compliance. The tool does not edit code.

Exit codes: 0 within finding limits, 1 error findings or excess warnings, 2 configuration or execution failure. To make warnings fail CI:

jev-lint --max-warnings 0

Development

npm run check   # Type checking, offline tests, and build
jev-lint --config examples/jev.config.json

Export AI_GATEWAY_API_KEY before running the example (or put it in examples/.env.local). The example intentionally reports one violation and exits 1. Source modules stay under 250 lines. Implementation notes and evaluation guidance live in plan/.

Contributors

zdenham

6 commits

Languages

TypeScript

100.0%