All rules
One row per rule, every package, generated from each plugin’s exported metadata. Each rule links to its page,
which has the options it takes and the Incorrect and Correct examples that run in that package’s test suite.
Use the site search (⌘ K) or your browser’s find on this page. The same index is
served as JSON at /eslint-plugins/rules.json for tools and agents; the
shape is documented below.
113 rules across 11 ESLint plugins and 1 lint-meta catalog. Of the 85 ESLint rules, 66 are switched on by a recommended preset, 9 ship registered but off, and 10 are left out of every preset and enabled one by one. The 28 lint-meta rules run under @noctcore/harness, not ESLint. 2 rules read type information: noctcore-contracts/translation-key-exists (optional), noctcore-prisma/mutation-entry-must-reach-audit (required).
| Rule | What it reports | Preset | Fix | Types |
|---|---|---|---|---|
noctcore-react/component-props-naming | A function component's first-param props type must be named <Component>Props. Autofixes by renaming the in-file type declaration and its references when that is safe. | error | 🔧 | |
noctcore-react/context-value-must-be-memoized | A context Provider value must not be an inline object literal — a fresh reference each render re-renders every consumer. Memoize it with useMemo and pass the stable reference. | error | ||
noctcore-react/max-hook-return-surface | An exported use* hook in a hook file may return object literals (top-level or nested one level) of at most max (default 20) members. Wider returns are god-controllers in the making. | error | ||
noctcore-react/max-hooks-per-file | A hook/query/mutation file (default *.hooks.ts / *.queries.ts / *.mutations.ts) may export at most max (default 4) use* hooks. Split larger files. | error | ||
noctcore-react/max-props-per-component | A *Props interface/type-literal may declare at most max (default 12) local members. extends clauses are not counted. | error | ||
noctcore-react/no-effect-derived-state | An effect whose entire body is setState calls with values derived purely from its dependencies is the "you might not need an effect" anti-pattern — compute the value during render (or with useMemo) instead. | error | ||
noctcore-react/no-jsx-computation | Disallow array methods, arithmetic, and chained logical expressions directly inside JSX {...}. Lift them to a const above the return or into the hook. | error | ||
noctcore-react/no-jsx-in-hooks | A use*-named function must not return JSX — that is a component wearing a hook costume. Rename it to a PascalCase component, or return values instead of elements. | error | ||
noctcore-react/no-prop-drilling | A bundle of maxForwarded+ (default 4) props each forwarded unchanged (name={name}) from the *Props param to the same child component is prop drilling. Compose instead. | error | ||
noctcore-react/no-state-in-component-body | State/effect/query hooks must live in the colocated hook file (<Name>.hooks.ts), not in the component .tsx body. The component is a thin shell. | error | ||
noctcore-react/no-unguarded-web-storage | A localStorage / sessionStorage call must sit inside a try block: the access itself throws when storage is disabled, partitioned or full. | error | 💡 | |
noctcore-react/prefer-lazy-state-init | A useState initializer that is an expensive call (default JSON.parse / localStorage.getItem / sessionStorage.getItem, or a configured builder) must be wrapped in a function so it runs once on mount, not every render. | error | 🔧 | |
noctcore-react/props-must-be-visual | Component props must be visual. Auth/business-identity and credential prop names (userId, currentUser, *token*, *jwt*, *secret*, apiKey, ...) are disallowed. A live password input is a legitimate visual concern and is intentionally allowed. | error | ||
noctcore-react/require-effect-cancellation | A setState/dispatch that runs after an await or .then() inside a useEffect must be guarded against a unmounted/re-run effect (AbortController, a cancelled flag, or a cleanup return). | error | ||
noctcore-architecture/barrel-purity | A barrel (index.ts / index.tsx) must contain only re-exports — never local declarations, side effects, or default-exported values. | error | ||
noctcore-architecture/colocated-test-required | A source file matching an include glob must have a colocated *.test.* / *.spec.* sibling on disk. | off | ||
noctcore-architecture/component-folder-structure | A component <Name>/<Name>.tsx under <componentRoot>/<feature>/... must have its sibling set (.hooks.ts, .types.ts, .stories.tsx, .test.tsx, index.ts) present on disk. | error | ||
noctcore-architecture/filename-matches-export | A file's basename must match its primary export (a default export, or the sole named export). | error | 💡 | |
noctcore-architecture/index-must-reexport-default | A component folder's index.ts must re-export the component default (export { default as <Name> } from './<Name>'). | error | ||
noctcore-architecture/max-import-depth | A relative import may not climb more than max parent levels (default 3). Autofixed to a path alias when one is configured. | error | 🔧 | |
noctcore-architecture/no-cross-feature-imports | A file in one feature may not import runtime code from another feature. Move shared code to a shared module or a shared feature. | error | ||
noctcore-architecture/single-semantic-module | Require each module to export only one semantic concern (types, constants, functions, classes, components, hooks, schemas or enums). | off | ||
noctcore-monorepo/no-deep-package-imports | Workspace packages in the configured scopes must be consumed through their package barrel only — never via a deep subpath into package internals. | off | ||
noctcore-monorepo/no-unexported-subpath-import | Importing a @scope/pkg/<subpath> that the target workspace package's exports map does not expose. Reads the target package.json from disk. | off | ||
noctcore-contracts/env-var-schema-parity | Require every process.env.FOO / import.meta.env.FOO key to be declared in a schema file (.env.example or a zod-env module), so config access and config declaration cannot drift apart. | off | ||
noctcore-contracts/fetch-must-check-ok | Require a fetch response to be checked with .ok or a status comparison before .json() parses its body. | error | ||
noctcore-contracts/money-must-be-decimal | Disallow monetary values typed as the JS primitive number. Money-named fields explicitly typed : number lose precision to float rounding; use a Decimal money type instead. | error | ||
noctcore-contracts/no-direct-process-env | Disallow direct process.env access. Force every consumer through a typed, validated config accessor so a missing variable fails at boot, not at use. | error | ||
noctcore-contracts/no-error-stringify | Disallow stringifying an error with bare ${error} interpolation, error.toString(), or error + "". These drop the cause chain. Use error instanceof Error ? error.message : String(error) instead. | error | ||
noctcore-contracts/require-error-cause | Require re-thrown errors inside a catch to forward the caught error as { cause }. A throw new SomeError(...) that omits the cause severs the chain to the original failure. | error | 🔧 | |
noctcore-contracts/require-registered-keys | Require the key/name argument of configured sink APIs (storage, event channels, cache keys) to be an imported constant from a registry module, not a raw string literal. | off | ||
noctcore-contracts/require-schema-parse-at-boundary | Disallow asserting external boundary data with as T instead of parsing it at runtime. Flags casts of JSON.parse, res.json(), web storage, URL search params, message-event data and LLM tool input, directly or through a const; use a zod/valibot parse. | off | ||
noctcore-contracts/restrict-throw-to-taxonomy | Restrict throw to an approved error taxonomy. Flags throwing a non-allowlisted error class and throwing a non-Error value (string, object, number, ...). | error | ||
noctcore-contracts/schema-enum-field-consistency | Disallow a zod field that is an enum in one object schema of a module from being z.string() in another, which widens the wire type every consumer then narrows by hand. | error | ||
noctcore-contracts/translation-key-exists | Require every static i18next / react-i18next translation key (t(...), i18n.t(...), <Trans i18nKey>) to exist in the catalog of the namespace in scope. | off | optional | |
noctcore-contracts/wire-message-naming | A message-schema const ending in a role suffix (default Event/Command/Query) whose zod object declares type: z.literal(...) must set that literal to kebab-case(const name minus its role suffix). | error | 🔧 | |
noctcore-contracts/zod-schema-naming | Every exported zod schema is a PascalCase const suffixed Schema, paired with a same-named inferred type (export type Foo = z.infer<typeof FooSchema>). | error | ||
noctcore-code-quality/fake-timers-must-be-restored | A test file that calls useFakeTimers() must also call useRealTimers(), so fake timers do not leak into later tests. | error | ||
noctcore-code-quality/interface-prefix-i | Interface names must be prefixed with I followed by an uppercase letter. Module/global augmentations are exempt. | not listed | ||
noctcore-code-quality/no-bare-date-now | Disallow bare Date.now() / new Date() in business logic. Read wall-clock time through a shared clock util (nowMs() / now()) so time is mockable. | error | ||
noctcore-code-quality/no-conditional-expect | Disallow expect() inside a branch, catch or loop that may not run: a skipped assertion lets a broken test pass. | error | ||
noctcore-code-quality/no-elided-code-comments | Disallow comments that stand in for elided code ('// ... existing code ...', '// rest of the function unchanged', '// your code here'). They are what an agent leaves when it rewrites a file from an abbreviated draft, and the code they replaced has usually been deleted. | error | ||
noctcore-code-quality/no-focused-tests | Ban focused tests (it.only / describe.only / test.only, fdescribe / fit / ddescribe) so a focused test never silently lands in CI. | error | ||
noctcore-code-quality/no-historical-comments | Disallow comments that frame code relative to what it used to do or to a past incident ('before the fix', 'after the refactor', 'we used to', 'no longer'). Source comments describe the current invariant; history belongs in the commit message or PR description, where it does not rot when the code changes again. | error | ||
noctcore-code-quality/no-narration-comments | Disallow narrative comments like 'Here we...', 'Now we...', 'First, we...'. These read as step-by-step prose and add no information a future reader cannot get from the code itself. Often a tell that the comment was generated by an agent describing its own changes. | error | ||
noctcore-code-quality/no-pr-reference-comments | Disallow PR/issue references in comments. They belong in commit messages and PR descriptions, where they do not rot when the repo moves, the issue tracker migrates, or the numbering changes. | error | ||
noctcore-code-quality/no-process-exit | Disallow process.exit() outside bootstrap/shutdown paths and standalone CLIs. Application and service code must throw or reject so the lifecycle can shut down gracefully. | error | ||
noctcore-code-quality/no-real-network-in-unit-tests | Unit tests must not perform real network I/O: mock the HTTP client, or move the test to an integration suite. | error | ||
noctcore-code-quality/no-swallowed-assertion | Disallow assertions inside a try whose catch neither rethrows nor asserts, and .catch() handlers that swallow an expect(...).rejects/.resolves failure: the assertion fails, the error is dropped, and the test passes. | error | ||
noctcore-code-quality/no-template-trim-empty-ternary | Disallow inline <template>.trim() === '' ? fallback : <template>.trim() patterns. Extract to a named utility so the expression is built once and is unit-testable in one place. | not listed | ||
noctcore-code-quality/no-vacuous-expect | Disallow vacuous expects (typeof checks, literal tautologies, a sole toBeDefined/toBeTruthy): a test must assert behaviour that a real regression would break. | error | ||
noctcore-code-quality/prefer-early-return | Prefer guard clauses (early return) over wrapping the whole function body in a multi-statement if without an else. | error | ||
noctcore-code-quality/skipped-tests-need-tracking | Skipped tests (.skip / .fixme / xit / xdescribe) must carry a tracking marker (an issue URL or TODO(@owner)) on or above the line, so the debt has an owner instead of rotting silently. | error | ||
noctcore-async-safety/forward-abort-signal | A function that accepts an AbortSignal (param named signal or typed AbortSignal) but awaits a call without ever forwarding it leaves that work uncancellable. | error | ||
noctcore-async-safety/no-concurrent-shared-mutation | A read-modify-write of an outer-scope binding inside a concurrent Promise.all(arr.map(async …)) callback can lose updates. | error | ||
noctcore-async-safety/no-leaky-race-timeout | A setTimeout timeout raced with Promise.race must be cleared — otherwise the timer outlives the race whenever the other promise wins. | error | ||
noctcore-async-safety/no-shared-mutable-module-state | A module-scoped mutable binding written inside an exported async/handler function is shared across concurrent requests. Opt in per file via include. | error | ||
noctcore-async-safety/prefer-parallel-awaits | Consecutive independent const x = await read() statements can run concurrently via await Promise.all([...]). | off | 💡 | |
noctcore-async-safety/require-client-timeout | A configured network client must be constructed with a timeout option; an unbounded client can hang forever. | error | ||
noctcore-async-safety/require-fetch-timeout | A fetch (or configured wrapper) call must carry a signal/timeout in its options — an unbounded request can hang forever. | error | 💡 | |
noctcore-observability/audit-pii-declared | A PII-shaped key written into an audit payload must be declared, either registered for scrubbing on purge or declared non-PII. | error | ||
noctcore-observability/no-error-detail-loss | A catch block that reports a failure must not reduce the error to only e.message / String(e) / ${e} — log the error itself so its stack and cause survive. | error | ||
noctcore-observability/no-sensitive-fields-in-logs | A logger call must not reference an identifier, property, or object key whose name matches a sensitive-field denylist (password, token, secret, ...). Redact it before logging. | error | ||
noctcore-observability/structured-log-arguments | A logger call must not interpolate dynamic values into the message string (a template literal with expressions). Pass a static message and a structured context object instead. | error | ||
noctcore-security/no-shell-interpolation | A dynamically-interpolated command string must not flow into a shell runner (exec/execSync, or spawn/execFile with shell: true). Pass the program and arguments separately. | error | ||
noctcore-security/no-timing-unsafe-compare | An HMAC digest or signature must not be compared with === / !== / == / != or Buffer#equals; use crypto.timingSafeEqual. | error | ||
noctcore-security/no-user-controlled-fetch-url | Disallow HTTP requests whose origin is not fixed at authoring time: a runtime-controlled host enables SSRF. | error | ||
noctcore-security/no-user-controlled-redirect | Disallow redirects whose target origin is not fixed at authoring time: a user-controlled target is an open redirect. | error | ||
noctcore-security/require-path-containment | Request-shaped input (req.*) passed directly into path.join / path.resolve without a containment guard is a path-traversal sink. | not listed | ||
noctcore-security/require-sanitized-html | HTML reaching dangerouslySetInnerHTML, innerHTML, outerHTML or insertAdjacentHTML must be static markup or pass through a configured sanitizer. | not listed | ||
noctcore-security/server-action-through-client | In a 'use server' module every exported action must be built from a configured action client; a raw exported function bypasses input validation, error shaping and middleware. | not listed | ||
noctcore-prisma/mutation-entry-must-reach-audit | Require a mutation entry point whose type-resolved call graph reaches a Prisma write to also reach an audit write. Reports only when the whole graph was read. | not listed | required | |
noctcore-prisma/no-audit-write-in-transaction | Disallow an audit-log write inside a $transaction callback, where it rolls back with the business work. It does not check that mutations are audited at all. | error | ||
noctcore-prisma/no-cross-tenant-id-in-where | Disallow a Prisma query or write whose tenant id in where or data is read from client input. Without row-level security, a client-supplied tenant id is a cross-tenant access (IDOR). | error | ||
noctcore-prisma/no-raw-sql-outside-allowlist | Disallow raw Prisma SQL ($queryRaw, $executeRaw, $queryRawTyped, *Unsafe) that can touch a table outside an allowlist. A raw query has no model, so a tenant-scope extension passes it through unscoped. | error | ||
noctcore-prisma/no-request-body-in-write | Disallow a Prisma write whose data (or where) is the raw request body. Passing client input straight through lets a caller set any column (mass assignment) or widen the filter. | error | ||
noctcore-prisma/no-unscoped-prisma-outside-allowlist | Disallow the unscoped Prisma client and tenant-scope escape-hatch functions outside an allowlist of seeds, migrations, isolation tests, and designated system files. | error | ||
noctcore-prisma/prisma-tx-uses-tx-not-client | Inside a $transaction(async (tx) => ...) callback, writes must go through the tx parameter, not the outer client, so they participate in the transaction and roll back together. | error | ||
noctcore-prisma/prisma-write-in-transaction | Disallow two or more Prisma writes in a single function/method body that are not wrapped in a $transaction. A partial failure between writes leaves half-written state. | error | ||
noctcore-prisma/restrict-model-writes | Restrict Prisma writes to configured models (or to configured columns of them) to the files that own those writes, including nested relation writes. It fences who writes; it does not validate which values or state transitions are legal. | not listed | ||
noctcore-prisma/soft-deletable-tables-require-deleted-at | Require a filtered read or bulk write on a soft-deletable Prisma model to exclude soft-deleted rows in its where. Soft delete is convention only, with no Prisma extension injecting the filter, so a query that omits it reads and mutates deleted rows. | not listed | ||
noctcore-prisma/tenant-scoped-tables-require-where | Require every tenant field in the where of a read or bulk write on a tenant-scoped model through the unscoped client, and a scope column in the where of any query on a hand-scoped model. | not listed | ||
noctcore-prisma/tenant-write-must-carry-tenant-id | Require every tenant field in the data of a create on a tenant-scoped Prisma model through the unscoped client, which does not inject the tenant scope. | not listed | ||
noctcore-rsc/no-navigation-throw-in-try | Disallow redirect(), notFound() and the other throwing next/navigation calls inside a try whose catch swallows the error instead of rethrowing it. | error | ||
noctcore-llm/no-llm-output-to-sink | Text an LLM SDK call returned must not reach eval, a shell, raw SQL, HTML injection, a fetch origin or an fs path in the same function without being validated or sanitized first. | error | ||
lint-meta-rules/agents-doc-presence | AGENTS.md must exist at the repo root, every surface, and every non-opted-out package. | harness | ||
lint-meta-rules/canonical-helpers-single-home | Pure helpers must live in one canonical home (flag the same exported symbol appearing in multiple homes). | harness | ||
lint-meta-rules/dockerfile-base-image-digest-pin | Dockerfile FROM base images must be pinned by @sha256: digest (scratch and earlier build stages exempt). | harness | ||
lint-meta-rules/eslint-config-no-warn | Every rule in the RESOLVED ESLint config is "error" or "off", never "warn", including severities a spread preset injects. | harness | ||
lint-meta-rules/file-size-ratchet | Source files stay at or under 400 raw lines. Today's offenders are grandfathered by .nightcore/lint-meta/baselines/file-size-ratchet.json; a new/grown offender fails, and a stale/shrunk baseline entry demands tightening. | harness | ||
lint-meta-rules/github-actions-least-privilege-permissions | GitHub Actions workflows declare a read-only top-level permissions: (no write-all/read-all, no <scope>: write); writes go on the job that needs them. | harness | ||
lint-meta-rules/github-actions-no-template-injection | GitHub Actions run: and github-script bodies never expand attacker-controllable ${{ }} context (issue/PR titles, comments, branch names); pass it through env: instead. | harness | ||
lint-meta-rules/github-actions-runner-pinned | GitHub Actions jobs must run on a pinned runner image (for example ubuntu-24.04), never a *-latest label. | harness | ||
lint-meta-rules/github-actions-sha-pinned | GitHub Actions uses: refs must be pinned to a 40-character commit SHA with a # vN comment (local ./ actions exempt). | harness | ||
lint-meta-rules/idempotency-key-parity | Procedures carrying the idempotency middleware must have a client caller that sends an idempotency key, or no client caller at all. | harness | ||
lint-meta-rules/layer-rank | Fixed dependency direction by rank: a module imports only strictly-lower-ranked <scope> packages (equal/upward forbidden). | harness | ||
lint-meta-rules/no-cloned-component-folders | A component folder name may exist under only ONE feature. Shared surfaces are hoisted; divergent ones get a divergent name. Today’s clones are frozen in a shrinking allowlist. | harness | ||
lint-meta-rules/no-warn-severity | ESLint severity is 'error' or 'off', never 'warn'. A rule that matters is an error; a failure is fixed, not silenced. | harness | ||
lint-meta-rules/package-shape | Every workspace is named <scope>/<dir>; library packages expose a barrel and point main/module/types/exports at the built output. | harness | ||
lint-meta-rules/prisma-method-surface | The Prisma reads and writes the rules police partition the generated client's <Model>Delegate method surface exactly, so a Prisma upgrade cannot add an unguarded method. | harness | ||
lint-meta-rules/security-scanner-version-parity | The gitleaks version pinned in the workflows must equal the one in scripts/ci/pre-push.sh, and the hook must compare a native gitleaks against it at run time. | harness | ||
lint-meta-rules/service-image-digest-pin | Workflow service and container images, and docker-compose images, must be pinned by @sha256: digest (a service that builds locally is exempt). | harness | ||
lint-meta-rules/session-epoch-captured | Every call into the sign-in seam must pass the session epoch captured before the credential was read, or a revocation landing during the credential check loses the race. | harness | ||
lint-meta-rules/session-kind-stamped | Every call that mints a session must stamp the principal kind onto it, or sit in an allowlisted, provably single-kind flow; a session read without the kind falls back to a default and can silently promote one kind of account into another. | harness | ||
lint-meta-rules/session-landing-declared | Every file that opens a door into a session must declare where it leaves the caller, and a door whose landing demands a return shape (the one that carries the principal kind to the client) must have it. | harness | ||
lint-meta-rules/session-mint-callers | The method that mints a session may only be called from allowlisted files; a new sign-in entry point must route through the gate in front of it so the gate cannot be bypassed. | harness | ||
lint-meta-rules/tenant-model-registry-parity | Every tenant-bearing Prisma model is scoped by the runtime extension or exempt with a reason, and the tenant lint rules resolve with exactly that registry. | harness | ||
lint-meta-rules/test-runner-segregation | Bun-side packages use 'bun:test'; foreign-side packages use 'vitest'. Never mix runners. | harness | ||
lint-meta-rules/test-sibling-enforcement | Every source file matched by include must have a colocated sibling test. Pure helpers must ship a test. | harness | ||
lint-meta-rules/test-workspace-enrollment | Every candidate package with test files must be enumerated in the root 'test:node' script. | harness | ||
lint-meta-rules/translation-dead-keys | Every translation catalog key must be reachable from the source: named by a translation call, or spelled by some string in the code. | harness | ||
lint-meta-rules/ui-primitive-shape | A folder primitive under the ui root must ship its proof siblings (test, stories); a flat primitive must not carry sibling proof files at the root. | harness | ||
lint-meta-rules/workspace-graph-parity | Imported <scope>/* specifiers must be declared workspace:* deps, and tsconfig references must mirror those deps. | harness |
Preset: severity in the package's configs.recommended; off means the preset registers the rule switched off, not listed means it leaves the rule out; both are opt-in, so you turn the rule on yourself. harnessmeans the rule is a lint-meta rule with no ESLint preset. ❌ deprecated: the rule still works but is in no preset and will be removed; move to the rule named after it. Fix: 🔧 fixable with--fix, 💡 offers editor suggestions. Types: whether the rule needs a type-checked program (parserOptions.projectService), or uses one when present.
Machine-readable index
Section titled “Machine-readable index”rules.json is generated at build time from the same catalog as the
table above, so it cannot disagree with it. llms.txt at the site root
points here and at it. The shape is a public contract: fields are added, never renamed or removed,
without a schemaVersion bump. A build check asserts the file has exactly one entry per rule doc and
that every url resolves to a page on this site.
Top level:
| Field | Meaning |
|---|---|
schemaVersion |
Integer, currently 1. Bumped only on a breaking change to this shape. |
generatedAt |
ISO timestamp of the build that emitted the file. |
site |
The site root URL. |
rulesPage |
URL of this page. |
count |
Number of entries in rules. |
packages |
One entry per package: name (npm), short, version, description, kind, namespace, url. |
rules |
One entry per rule, in package order then by name. |
Each entry in rules:
| Field | Meaning |
|---|---|
id |
The id a config or a report uses: noctcore-react/no-prop-drilling, or the bare lint-meta id. |
name |
The rule name without its namespace. |
package |
npm name of the package that exports it. |
runner |
eslint, or harness for a lint-meta rule that runs under @noctcore/harness. |
description |
The rule’s meta.docs.description. |
url |
The rule’s page on this site, the same URL as its meta.docs.url. |
recommended |
error or off in the package’s recommended preset; null when the preset leaves it out, and for lint-meta rules. |
fixable |
Whether the rule has an autofix. |
hasSuggestions |
Whether the rule offers suggestions. |
typeInfo |
required, optional or none: whether the rule needs a type-checked program. |
deprecated |
Whether the rule is deprecated. A deprecated rule still works, but no preset enables it. |
replacedBy |
Ids of the rules to use instead of a deprecated one; empty when there is none. |
deprecatedSince |
The package version that deprecated the rule, or null. |
category, ciCritical, factory, entry |
lint-meta rules only: the harness category, whether a violation fails CI by default, the factory export and the entry point that exposes it. |