{"slug": "show-hn-jev-lint-semantic-linter-with-plain-english-rules", "title": "Show HN: Jev-lint – semantic linter with plain English rules", "summary": "Developer zdenham released jev-lint, an open-source semantic linter that checks JavaScript and TypeScript code against project conventions written in plain English, using Jev models through Vercel AI Gateway. The tool requires Node.js 22.22+ and Git, defaults to a 20-finding and 16 KiB output limit, and is an early release whose findings should be reviewed before being made to block CI. Rules are defined in jev.config.json or referenced from Markdown files, and live checks consume the user's Vercel AI Gateway credits via an AI_GATEWAY_API_KEY.", "body_md": "Check JavaScript and TypeScript code against project conventions written in plain English. Write a rule or point to a Markdown file with examples; [Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev) evaluates the relevant code and reports possible violations.\n\nBuilt for coding agents, with compact output by default and optional pretty or JSON output. Early release; review findings before making them block CI.\n\nDefine your conventions in `jev.config.json`. Each rule has a name and a plain-English instruction, with optional file patterns:\n\n```\n{\n  \"files\": [\"src/**/*.{ts,tsx}\"],\n  \"ignore\": [\"src/generated/**\"],\n  \"rules\": {\n    \"preserve-error-cause\": {\n      \"instruction\": \"When rethrowing an unexpected error, preserve the original error as its cause.\",\n      \"severity\": \"error\"\n    },\n    \"user-facing-errors\": {\n      \"files\": [\"src/ui/**\"],\n      \"instruction\": { \"file\": \"docs/conventions.md#user-facing-errors\" }\n    }\n  }\n}\n```\n\nPaths 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.\n\nFor Markdown rules, include the convention, examples, and exceptions:\n\n```\n## User-facing errors\n\nExplain what went wrong and what the user can do next.\n\nGood: \"We couldn't save your changes. Check your connection and try again.\"\nBad: \"Mutation failed: ERR_UPSTREAM_502.\"\n\nThis applies to messages shown to users, not internal logs.\n```\n\nA `#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.\n\nRequires Node.js **22.22+** and Git. Clone the repo, build it, and register the global command:\n\n```\ngit clone https://github.com/zdenham/jev-lint.git\ncd jev-lint\nnpm ci\nnpm run build\nnpm link\njev-lint --help\n```\n\nYou 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).\n\nTo update, run `git pull`, `npm ci`, and `npm run build` inside the checkout. To remove the global command, run `npm uninstall --global jev-lint`.\n\n```\ncd /path/to/your-project\njev-lint init\n```\n\nThis 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.\n\nFor live checks, get a [Vercel AI Gateway API key](https://vercel.com/docs/ai-gateway/authentication-and-byok). Set it in the environment, or put it in `.env.local` beside `jev.config.json`:\n\n```\nexport AI_GATEWAY_API_KEY=\"your-key\"\n```\n\nSelected 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`:\n\n```\n.env.local\n.jev/reports/\njev-lint --dry-run          # Preview files and rules; no API calls\njev-lint                   # Check configured files\njev-lint src/ui            # Narrow to a file or directory\njev-lint --changed main    # Check whole tracked files changed from main's merge-base\njev-lint --format pretty   # Human-readable code frames\njev-lint --format json     # Programmatic output\n```\n\nAgent 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.\n\n```\n[f_1] ERROR preserve-error-cause\nsrc/save.ts:1:1\n  Possible violation of preserve-error-cause; compare the code with the rule and its examples.\n  ...\nRule: jev.config.json#/rules/preserve-error-cause/instruction\nReport: /your-project/.jev/reports/<run-id>.json\n```\n\nInspect a saved report without another API call:\n\n```\njev-lint report /path/to/report.json --finding f_1\njev-lint report /path/to/report.json --offset 20 --limit 20\n```\n\nUse `--summary` for counts only, or `--max-output-bytes` to set the output budget. Run `jev-lint --help` for all options.\n\nEvery run prints input/output token counts and Gateway's billed and market costs. Illustrative output:\n\n```\nUsage: 3 requests | 5000 input tokens | 500 output tokens\nCost: $0.00021000 billed | $0.00021000 market\n```\n\nAt $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.\n\nThe 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`:\n\n```\n\"limits\": {\n  \"maxCostUsd\": 1,\n  \"maxFiles\": 10,\n  \"maxRequests\": 10,\n  \"maxInputBytes\": 100000\n}\n```\n\nOmitted limits use the defaults. Override individual limits for one run:\n\n```\njev-lint --dry-run                 # Offline estimate; no API calls\njev-lint --max-cost-usd 0.25        # Override the config's dollar budget\njev-lint --max-files 30 --max-requests 30\n```\n\nLive runs check [current Gateway pricing](https://vercel.com/docs/ai-gateway/models-and-providers#dynamic-model-discovery) 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.\n\n**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.\n\nFindings 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.\n\nExit codes: **0** within finding limits, **1** error findings or excess warnings, **2** configuration or execution failure. To make warnings fail CI:\n\n```\njev-lint --max-warnings 0\nnpm run check   # Type checking, offline tests, and build\njev-lint --config examples/jev.config.json\n```\n\nExport `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/](https://github.com/zdenham/jev-lint/blob/main/plan/README.md).", "url": "https://wpnews.pro/news/show-hn-jev-lint-semantic-linter-with-plain-english-rules", "canonical_source": "https://github.com/zdenham/jev-lint", "published_at": "2026-09-19 23:52:12+00:00", "updated_at": "2026-09-20 00:23:55.092593+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents", "large-language-models"], "entities": ["jev-lint", "Jev", "zdenham", "Vercel AI Gateway", "Node.js", "GitHub", "TypeScript", "JavaScript"], "alternates": {"html": "https://wpnews.pro/news/show-hn-jev-lint-semantic-linter-with-plain-english-rules", "markdown": "https://wpnews.pro/news/show-hn-jev-lint-semantic-linter-with-plain-english-rules.md", "text": "https://wpnews.pro/news/show-hn-jev-lint-semantic-linter-with-plain-english-rules.txt", "jsonld": "https://wpnews.pro/news/show-hn-jev-lint-semantic-linter-with-plain-english-rules.jsonld"}}