lint:meta rules
lint:meta
ESLint enforces architecture inside TypeScript modules. lint:meta
catches repo-level drift ESLint cannot see: unpinned GitHub Actions, env
cascade gaps, forbidden inline disables, cross-repo imports, and missing test
siblings. It runs inside bun run check / bun run check.
lint:meta
merge-gate layer
ui + api
template catalogs
registry.ts
source of truth
Merge gate stack
Section titled “Merge gate stack”typecheck → ESLint → lint:meta → knip → testsUI-only rules
Section titled “UI-only rules”The apps/ui catalog includes rules that only apply to the SPA repo:
no-cross-repo-import— CI-critical; UI imports must not reach into backend or infra sourcemodulepreload-size-limit-coverage— bundle size-limit config must cover modulepreload chunksno-dark-variant,no-dangerous-html,env-access,no-raw-fetch— source-text bans for Vite/React patterns
API-only rules
Section titled “API-only rules”The apps/api catalog adds backend test contracts:
routes-require-test-sibling— every*.routes.tsneeds a matchingtests/api/**/*.routes.test.tstouch-tests-too— opt-in viaLINT_META_TOUCHED_BASEfor diff-aware test enforcement
Shared rules
Section titled “Shared rules”Both templates share supply-chain, CI, env, artifact, and config rules (exact deps, pre-push CI parity, engine pin parity, generated artifact banners, forbidden inline disables, raw role literals, logic-file test siblings).
apps/ui catalog
Section titled “apps/ui catalog”Rule ID
CI-critical
What it guards
package-json-exact-depsno
dependencies and devDependencies must use exact versions; peerDependencies must use caret (^).
no-overlapping-libsno
package.json must not list forbidden overlapping library pairs.
Rule ID
CI-critical
What it guards
github-actions-permissionsno
GitHub Actions workflows require permissions block and SHA-pinned uses: refs.
github-actions-permissions:verifyno
Pinned action SHAs resolve on github.com (lint:meta:verify only).
pre-push-ci-parityno
CI workflow must include every command listed in scripts/ci/pre-push.manifest.json.
engine-pin-parityno
Node and Bun version pins must stay aligned across .nvmrc, package.json, Docker, and CI.
Rule ID
CI-critical
What it guards
env-cascade-driftno
Vite env keys must align across schema.ts, .env.example, and vite-env.d.ts.
Rule ID
CI-critical
What it guards
generated-artifact-contractno
Generated ACL types and OpenAPI schema files must exist with required banner text.
modulepreload-size-limit-coverageno
.size-limit.json must include globs for all modulepreload entry chunks.
Rule ID
CI-critical
What it guards
forbidden-textno
Source files must not contain inline lint/TS suppressions, raw HTML, direct env access, raw fetch, or banned Tailwind dark-mode variant classes.
no-inline-lint-disableno
Inline ESLint disables are not allowed.
no-ts-ignoreno
TypeScript suppression comments are not allowed.
no-dangerous-htmlno
Raw HTML rendering requires a dedicated sanitizer and security review.
env-accessno
Read Vite env through src/lib/env only.
no-raw-fetchno
Use the typed apiClient; raw fetch is restricted to src/lib/api/openapi.
no-dark-variantno
The `dark:` Tailwind variant is banned.
no-cross-repo-importyes
Relative imports must stay inside apps/ui; no backend or infra source paths.
no-raw-role-literalno
Use ROLE.* from acl.types instead of raw owner/admin/member/viewer string literals.
no-raw-fetch-scriptsno
Scripts must not call global fetch except github-actions-permissions.ts (lint:meta --verify SHA check).
Rule ID
CI-critical
What it guards
logic-files-require-test-siblingno
Logic modules must ship with a colocated *.test.ts or *.test.tsx sibling.
Rule ID
CI-critical
What it guards
eslint-config-no-warnno
ESLint severities must be "error" or "off", not "warn".
apps/api catalog
Section titled “apps/api catalog”Rule ID
CI-critical
What it guards
package-json-exact-depsno
dependencies and devDependencies must use exact versions (no ranges).
no-overlapping-libsno
package.json must not list forbidden overlapping library pairs.
Rule ID
CI-critical
What it guards
github-actions-permissionsno
GitHub Actions workflows require permissions block and SHA-pinned uses: refs.
github-actions-permissions:verifyno
Pinned action SHAs resolve on github.com (lint:meta:verify only).
pre-push-ci-parityno
CI workflow must include every command listed in scripts/ci/pre-push.manifest.json.
engine-pin-parityno
Bun version pin must stay aligned across package.json, Docker, and CI.
Rule ID
CI-critical
What it guards
env-cascade-driftno
TypeBox env schema keys must align with .env.example documentation.
Rule ID
CI-critical
What it guards
generated-artifact-contractno
Sibling apps/ui generated ACL and OpenAPI files must carry required banner text.
Rule ID
CI-critical
What it guards
forbidden-textno
Source files must not contain inline lint/TS suppression comments.
no-inline-lint-disableno
Inline ESLint disables are not allowed.
no-ts-ignoreno
TypeScript suppression comments are not allowed.
no-raw-role-literalno
Use ROLE.* from acl.constants.ts instead of raw owner/admin/member/viewer string literals.
Rule ID
CI-critical
What it guards
routes-require-test-siblingno
Route modules must ship with a matching HTTP-level test under tests/api/.
logic-files-require-test-siblingno
Logic modules must ship with a matching tests/**/*.test.ts sibling.
touch-tests-toono
Modified logic/route files must include a matching test change (opt-in via LINT_META_TOUCHED_BASE).
Rule ID
CI-critical
What it guards
eslint-config-no-warnno
ESLint severities must be "error" or "off", not "warn".
Adding a rule
Section titled “Adding a rule”- Implement
IMetaRuleunderscripts/lint-meta/rules/<category>/ - Register it in
scripts/lint-meta/registry.ts - Run
bun run generate:lint-meta-docs(ui) orbun run generate:lint-meta-docs(api) - Run the boringstack docs generators and commit the updated JSON catalogs
- Add a test under
tests/lint-meta/
Related
Section titled “Related”- Lint as the contract — ESLint plugin inventory
- Scripts & tooling — which script runs
lint:meta - Commands cheatsheet — day-to-day workflow commands