◉ Pulse
SukkaW avatar
#31 today

SukkaW/eslint-plugin-vibe-proof

TypeScript AI

An ESLint plugin that tries its best to prevent your coding agents from pooping your bed.

Created Jul 26, 2026
Stars
7
Today
+7
Forks
0
Quality
90/100
Momentum
19

README

Fetched from GitHub on Oct 30, 2026, 10:17 PM UTC · README.md

View original on GitHub

Third-party content — Open Source Pulse is not the owner of this repository.

This README belongs to SukkaW/eslint-plugin-vibe-proof and its contributors. We fetch it directly from the project’s public GitHub repository and display it for reference only. All text, code, images and trademarks remain the property of their respective authors. See the repository for its license terms. Copyright / takedown policy.

eslint-plugin-vibe-proof

You just can't really teach coding agents how to write the correct code using agent skills. The more agent skills you install, the faster models fill up the context window, and the faster your coding agents become stupid.

LLM when the context window usage hit 60%: wojak trying to put a square block into a round hole meme

And LLM is very good at forgetting things. Given a long last coding session and enough conversation compaction, your coding agents can and will eventually forget the important things like agent skills you installed, and even your AGENTS.md.

What you really need is a deterministic and unforgiving feedback loop for your coding agents. Unit tests and static analysis are exactly that. When your coding agents poop your bed, linter will not forgive, linter will not forget, linter will not yield, linter will not be constrained by the context window, linter will always detect and spit out the errors.

That's what eslint-plugin-vibe-proof is trying to accomplish here. It will detect the most common coding agents' mistakes and bad patterns, enforce LLM to write the correct code.

Installation

pnpm add eslint-plugin-vibe-proof
yarn add eslint-plugin-vibe-proof
npm install eslint-plugin-vibe-proof

Usage

You can begin by importing presets in your ESLint flat configuration. All presets are non-overlapping, so you can and should mix and use multiple of them.

import { eslint_plugin_vibe_proof } from 'eslint-plugin-vibe-proof';

/* basic presets that does not require typed linting */
eslint_plugin_vibe_proof.configs.common;
/* extra rules that require typescript-eslint typed linting */
eslint_plugin_vibe_proof.configs.common_type_checked;
/* react-specific rules */
eslint_plugin_vibe_proof.configs.react;
/* extra react-specific rules that require typescript-eslint typed linting */
eslint_plugin_vibe_proof.configs.react_type_checked;

You can also register the plugin and enable rules in your ESLint flat configuration yourself:

import { eslint_plugin_vibe_proof } from 'eslint-plugin-vibe-proof';

export default [
  {
    plugins: {
      'vibe-proof': eslint_plugin_vibe_proof
    },
    rules: {
      /* --- included in `configs.common` --- */

      // Ban `eslint-disable` comment directives that coding agents may use to
      // "workaround" linting errors, forcing them to write a description instead
      'vibe-proof/ban-eslint-disable': 'error',
      // Prefer `.reduce` over chaining `.filter` and `.map`
      'vibe-proof/no-chain-array-higher-order-functions': 'error',
      // Disallow `.includes()` on constant arrays — use a `Set` with `.has()`
      'vibe-proof/no-constant-array-includes': 'error',
      // Test cheap synchronous operands before an `await` that they can
      // short-circuit, so the async work only happens when it is needed.
      'vibe-proof/no-eager-await-in-condition': 'error',
      // Prefer `array.at(-1)` over `array[array.length - 1]` for the last item
      'vibe-proof/prefer-array-at-for-last-item': 'error',
      // Prefer `Array.from(iterable, mapper)` over materializing an iterable
      // and then calling `.map()`
      'vibe-proof/prefer-array-from-mapper': 'error',
      // Avoid passing entry arrays from `.flatMap()` / `.map()` / `.reduce()`
      // / `.reduceRight()` to `Object.fromEntries`
      'vibe-proof/prefer-array-reduce-to-object': 'error',
      // Prefer `.some()` over `.find()` / `.filter().length` when checking
      // whether an element exists
      'vibe-proof/prefer-array-some': 'error',
      // Prefer `export const { a, b } = value` over exporting elements one by one
      'vibe-proof/prefer-export-destructuring': 'error',
      // Hoist literal regexes to module level to avoid re-creation on every call
      'vibe-proof/prefer-hoisted-regex': 'error',
      // Hoist an `Intl.Collator` instance instead of calling `localeCompare`
      // inside a sort callback
      'vibe-proof/prefer-static-collator': 'error',
      // Prefer the fastest Unicode-safe code-unit / code-point operation for
      // statically known values
      'vibe-proof/prefer-string-code-point-operations': 'error',
      // Prefer `{ throwIfNoEntry: false }` over relying on a thrown error for
      // missing fs entries in sync stat calls
      'vibe-proof/prefer-throw-if-no-entry': 'error',
      // Pass the callback and its arguments directly to `setTimeout` /
      // `setInterval` instead of wrapping them in an arrow function or `bind`
      'vibe-proof/prefer-timer-args': 'error',

      /* --- included in `configs.common_type_checked` (requires typed linting) --- */

      // Prefer optimized alternatives (`.startsWith()`, direct index access)
      // over `indexOf()` equality checks
      'vibe-proof/no-indexof-equality': 'error',
      // Enforce indexed `for` loops with a cached length over `for...of` on arrays
      'vibe-proof/prefer-indexed-array-loop': 'error',

      /* --- included in `configs.react` --- */

      // Disallow duplicate JSX props — only the last one takes effect
      'vibe-proof/jsx-no-duplicate-props': 'error',
      // Disallow spreading object literals in JSX
      'vibe-proof/jsx-no-explicit-spread-props': 'error',
      // Disallow `location.href =` / `location.assign()` for relative-URL
      // navigation — use the framework's navigation API
      'vibe-proof/no-location-assign-relative-destination': 'error',
      // Disallow mirroring props, state, or hook returns into a ref to peek at later
      'vibe-proof/react-ban-peak-via-ref': 'error',
      // Detect unguarded state updates after async work inside an effect
      'vibe-proof/react-detect-potential-race-condition': 'error',
      // Detect circular dependencies in React effects
      'vibe-proof/react-no-circular-effect': 'error',
      // Disallow manual cancellation flags in `useEffect` for race condition cleanup
      'vibe-proof/react-no-manual-use-effect-race-condition-prevention': 'error',
      // Disallow mixing controlled and uncontrolled props on the same element
      'vibe-proof/react-no-mixing-controlled-and-uncontrolled-props': 'error',
      // Disallow `Array.prototype.find` in render, `useMemo`, or `useCallback`
      'vibe-proof/react-no-performance-impacting-array-find': 'error',
      // Disallow props that accept render functions returning JSX
      'vibe-proof/react-no-render-function-prop': 'error',
      // Disallow unnecessary `useCallback` calls
      'vibe-proof/react-no-unnecessary-use-callback': 'error',
      // Disallow unnecessary `useMemo` calls
      'vibe-proof/react-no-unnecessary-use-memo': 'error',
      // Disallow calling a `useState` setter synchronously in an effect
      'vibe-proof/react-no-use-effect-watching': 'error',
      // Disallow `useState` without its setter — use `useRef` or `foxact/use-singleton`
      'vibe-proof/react-no-use-state-as-ref': 'error',
      // Disallow local, prop-less components rendering constant JSX — use a constant JSX variable
      'vibe-proof/react-no-useless-components': 'error',
      // Prefer `React.PropsWithChildren` over manually declaring `{ children: ReactNode }`
      'vibe-proof/react-prefer-props-with-children': 'error',
      // Prefer the state updater function form when updating state
      'vibe-proof/react-prefer-state-updater-function': 'error',

      // Prefer `ComposeContextProvider` when many providers are nested together
      'vibe-proof/react-prefer-foxact-compose-context-provider': 'error',
      // Disallow `localStorage` / `sessionStorage` in React code
      'vibe-proof/react-prefer-foxact-persistent': 'error',
      // Prefer an abortable effect for EventTarget subscriptions with manual cleanup
      'vibe-proof/react-prefer-foxact-use-abortable-effect': 'warn',
      // Disallow copy-related Web APIs in React code
      'vibe-proof/react-prefer-foxact-use-clipboard': 'error',
      // Disallow direct `matchMedia` usage in React code
      'vibe-proof/react-prefer-foxact-use-media-query': 'error'
    }
  }
];

License

MIT


eslint-plugin-vibe-proof © Sukka, Released under the MIT License. Authored and maintained by Sukka with help from contributors (list).

Personal Website · Blog · GitHub @SukkaW · Telegram Channel @SukkaChannel · Mastodon @sukka@acg.mn · Twitter @isukkaw · BlueSky @skk.moe

Rendered by GitHub from the repository’s README. Scroll to read the full file.
First trending

Jul 27, 2026

first spotted on the list

Best rank

#31

highest position reached

Appearances

1

times on the trending list

Quality score

90

out of 100

Momentum

19

trend strength indicator

Star velocity

0.07

stars per day since creation

Activity — last 60 days

daily counts, collected every 6 hours
  • Stars
  • Forks
  • Merged PRs
  • Issues
  • Closed issues

Collecting activity data since launch — check back in a few days.

Star history

total stars per snapshot

Not enough snapshots yet — check back soon.

Rank history

position on trending · lower is better

Not enough snapshots yet — check back soon.

3D card for your website

Live HTML card with a glass surface and pointer tilt. Paste the iframe on any website.

<iframe src="https://www.notionpulse.cc/embed/SukkaW/eslint-plugin-vibe-proof" width="420" height="240" style="border:0;max-width:100%;background:transparent" loading="lazy" title="SukkaW/eslint-plugin-vibe-proof — trending on Open Source Pulse"></iframe>

Stars badge

Show current stars in your README or profile. Auto-updates every 6 hours.

SukkaW/eslint-plugin-vibe-proof stars badge
Markdown
[![SukkaW/eslint-plugin-vibe-proof](https://www.notionpulse.cc/api/badge/SukkaW/eslint-plugin-vibe-proof.svg)](https://www.notionpulse.cc/repo/SukkaW/eslint-plugin-vibe-proof)
HTML
<a href="https://www.notionpulse.cc/repo/SukkaW/eslint-plugin-vibe-proof"><img src="https://www.notionpulse.cc/api/badge/SukkaW/eslint-plugin-vibe-proof.svg" alt="SukkaW/eslint-plugin-vibe-proof stars badge" /></a>

Repository of the Day

#31 Repository of the Day

Repository of the Week

#31 Repository of the Week

Repository of the Month

#31 Repository of the Month