npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eslint-plugin-llm-core

v0.11.1

Published

ESLint rules that catch the patterns LLM agents get wrong — and teach them to self-correct

Downloads

1,885

Readme

eslint-plugin-llm-core

ESLint rules that catch the patterns LLM agents get wrong — and teach them to self-correct through structured error messages. DeepWiki

LLMs generate code that works but drifts: arrow functions everywhere, magic numbers, deep nesting, string-interpolated logs, oversized files. These aren't style nitpicks — they compound into codebases that are harder to debug, review, and maintain.

This plugin catches those patterns at lint time and provides error messages designed for LLM comprehension: what's wrong, why it matters, and a concrete fix. The result is AI-generated code that reads like it was written by a senior engineer.

Demo

Why this plugin?

  • Targeted rules — Every rule addresses a real pattern LLMs consistently get wrong, from export const fn = () => {} to logger.error(\Failed for ${userId}`)`
  • Teaching error messages — Structured feedback that LLMs parse and apply correctly on the first attempt
  • Works for humans too — These are solid code quality rules regardless of who wrote the code
  • Zero config — The recommended preset is ready out of the box
  • Suggestions, not auto-fixes — Transformations that could change semantics are offered as suggestions, keeping you in control

How It Works

This plugin is designed around three principles that make it effective for LLM-assisted development:

Deterministic Feedback

Every rule produces the exact same error message for the same mistake, every time. There is no randomness, no varying phrasing, no context-dependent rewording. This consistency means LLMs receive unambiguous signals about what to fix and how.

Instructional Error Messages

Every error message follows a structured teaching format:

  1. What's wrong — the specific violation
  2. Why it matters — the rationale behind the rule
  3. How to fix — a concrete, copy-pasteable transformation using the actual code context (function names, parameter lists, etc.)
Exported function 'fetchData' must use a function declaration, not a function expression or arrow function.

Why: Function declarations are hoisted, produce better stack traces, and signal clear intent.
Arrow functions are best reserved for callbacks and inline expressions, not top-level exports.

How to fix:
  Replace: export const fetchData = async () => { ... }
  With:    export async function fetchData() { ... }

This structure gives LLMs everything they need in one pass — the violation, the reasoning, and a concrete transformation. In practice, this reduces the back-and-forth iterations needed to resolve violations compared to standard ESLint messages.

Strict Mode by Default

Both the recommended and all configs set every rule to error, not warn. Warnings are easy to ignore — for both humans and LLMs. Errors force the issue to be resolved before the code is accepted. Combined with the no-inline-disable rule (which prevents // eslint-disable escape hatches), this creates a feedback loop where the LLM must fix violations rather than suppress them.

Installation

npm install eslint-plugin-llm-core --save-dev

Quick Start

Option 1: Recommended (All-in-one)

All recommended rules are active and ready out of the box.

// eslint.config.mjs
import llmCore from "eslint-plugin-llm-core";

export default [...llmCore.configs.recommended];

Option 2: Mix & Match

Select only the specific categories that fit your project.

// eslint.config.mjs
import llmCore from "eslint-plugin-llm-core";

export default [
  ...llmCore.configs.complexity,
  ...llmCore.configs.typescript,
  ...llmCore.configs.hygiene,
];

Available Configs

| Config | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | recommended | Safe defaults — rules most codebases should use | | all | Every rule at error — for strict codebases | | complexity | Enforce structural limits to prevent oversized files and functions | | typescript | Rules focused on type safety and clarity to avoid common 'any' traps (TS/TSX files only) | | best-practices | Core logic and reliability rules that catch common bugs and anti-patterns (also available as bestPractices for dot-notation access) | | style | Focuses on consistent naming and structure for predictability | | hygiene | Rules addressing development 'litter' and shortcuts like LLM artifacts and inline disables |

Manual Rule Configuration

// eslint.config.mjs
import llmCore from "eslint-plugin-llm-core";

export default [
  {
    plugins: {
      "llm-core": llmCore,
    },
    rules: {
      "llm-core/no-exported-function-expressions": "error",
      "llm-core/structured-logging": "error",
    },
  },
];

Rules

💼 Configurations enabled in.
🌐 Set in the all configuration.
🏆 Set in the best-practices configuration.
🧮 Set in the complexity configuration.
🧹 Set in the hygiene configuration.
✅ Set in the recommended configuration.
🎨 Set in the style configuration.
⌨️ Set in the typescript configuration.
💡 Manually fixable by editor suggestions.

| Name                             | Description | 💼 | 💡 | | :--------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | :------- | :-- | | consistent-catch-param-name | Enforce consistent naming for catch clause parameters across the codebase | 🌐 ✅ 🎨 | 💡 | | explicit-export-types | Require explicit parameter and return type annotations on exported functions | 🌐 ✅ ⌨️ | | | filename-match-export | Enforce that filenames match their single exported function, class, or component name | 🌐 ✅ 🎨 | | | max-file-length | Enforce a maximum number of lines per file to encourage proper module separation | 🌐 🧮 ✅ | | | max-function-length | Enforce a maximum number of lines per function to encourage decomposition | 🌐 🧮 ✅ | | | max-nesting-depth | Enforce a maximum nesting depth for control flow statements to reduce cognitive complexity | 🌐 🧮 ✅ | | | max-params | Enforce a maximum number of function parameters to encourage object parameter patterns | 🌐 🧮 ✅ | | | naming-conventions | Enforce naming conventions: Base prefix for abstract classes, Error suffix for error classes | 🌐 ✅ 🎨 | | | no-any-in-generic | Disallow any as a generic type argument in type references, arrays, and other parameterized types | 🌐 ✅ ⌨️ | | | no-async-array-callbacks | Disallow async callbacks passed to array methods where Promises are silently discarded or misused | 🌐 🏆 ✅ | | | no-commented-out-code | Disallow commented-out code to keep the codebase clean and reduce noise | 🌐 🧹 ✅ | | | no-empty-catch | Disallow catch blocks with no meaningful error handling (empty or comment-only blocks) | 🌐 🏆 ✅ | | | no-exported-function-expressions | Enforce that exported functions use function declarations instead of function expressions or arrow functions | 🌐 ✅ 🎨 | 💡 | | no-inline-disable | Disallow eslint-disable comments that suppress lint errors instead of fixing them | 🌐 🧹 ✅ | | | no-llm-artifacts | Disallow common LLM placeholder comments and incomplete code markers that indicate skipped implementation | 🌐 🧹 ✅ | | | no-magic-numbers | Disallow magic numbers and enforce named constants for clarity | 🌐 🏆 ✅ | | | no-redundant-logic | Disallow redundant boolean logic and unnecessary control flow patterns | 🌐 ✅ 🎨 | 💡 | | no-type-assertion-any | Disallow type assertions to any that bypass TypeScript's type safety | 🌐 ✅ ⌨️ | | | prefer-early-return | Enforce guard clauses (early returns) instead of wrapping function bodies in a single if statement | 🌐 ✅ 🎨 | | | prefer-unknown-in-catch | Disallow any type annotation on catch clause parameters; prefer unknown | 🌐 ✅ ⌨️ | | | structured-logging | Enforce structured logging with static messages and dynamic values as separate metadata | 🌐 🏆 ✅ | | | throw-error-objects | Disallow throwing non-Error values such as strings, template literals, plain objects, or arrays | 🌐 🏆 ✅ | |

Research & Evidence

The rules in this plugin are based on research data from academic research on LLM coding errors. I review research to identify patterns that LLMs consistently get wrong.

Key papers that have built out the rulesets:

Complementary Rules

These ESLint core rules address common LLM patterns and pair well with this plugin:

| Rule | What it catches | ESLint version | | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------- | | no-nested-ternary | LLMs nest ternaries for "conciseness" — enforce if/else instead | All | | preserve-caught-error | LLMs discard original errors when re-throwing — require { cause: error } | 9.35+ | | no-useless-assignment | LLMs create redundant intermediate variables — catch dead stores | 9.0+ | | complexity | LLMs generate high cyclomatic complexity — enforce decomposition | All |

Add these to your config alongside llm-core:

// eslint.config.mjs
import llmCore from "eslint-plugin-llm-core";

export default [
  ...llmCore.configs.recommended,
  {
    rules: {
      "no-nested-ternary": "error",
      "preserve-caught-error": "error",
      "no-useless-assignment": "error",
      complexity: ["error", 10],
    },
  },
];

Agent Skills

Beyond ESLint rules, this plugin ships agent skills — markdown instruction files that LLM agents can load when performing specific tasks. Skills complement the lint rules by catching patterns that require judgment rather than pattern matching.

Available Skills

| Skill | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | test-reviewer | Detects tests that duplicate production logic, use shallow assertions, skip edge cases, or assert on mocks instead of behavior |

Usage

Copy the skill file into your agent's skill directory:

# Claude Code
cp node_modules/eslint-plugin-llm-core/skills/test-reviewer.md .claude/skills/

# Cursor
cp node_modules/eslint-plugin-llm-core/skills/test-reviewer.md .cursor/skills/

# Or wherever your agent tool looks for skills

The skill is a standalone markdown file with no dependencies. Adapt it to your project's testing conventions as needed.

Contributing

npm install
npm run build
npm run test
npm run lint

See CLAUDE.md for architecture details and how to add new rules.

Roadmap

This plugin evolves as I learn more about how LLM agents behave in real codebases. The current ruleset is based on observed patterns — code that compiles and runs but drifts from production standards.

What I'm watching:

  • Which rules catch the most violations in practice
  • Whether structured messages reduce fix iterations (I believe they do, but want data)
  • New patterns that emerge as LLM capabilities change
  • Edge cases where rules create more noise than value

How you can help:

If you're using this plugin with LLM agents, I'd love to hear what's working and what isn't. Open an issue with:

  • Rules that catch real problems in your codebase
  • Rules that generate false positives or friction
  • Patterns your LLM consistently gets wrong that aren't covered

The goal is a tight, high-signal ruleset — not comprehensive coverage. Every rule should earn its place.

License

MIT