Skip to content

Built-in Checks

Built-in checks are registered under devManager.quality.builtin.*. Most run in pure Node.js (filesystem + regex) with no extra install. A few invoke npx or external CLIs when present — those are also documented on CLI Tool Checks. All are enabled by default; each returns skip when it does not apply to the project.

Code Size & Complexity

CheckWhat it detectsDefault thresholds
Line CountSource files that are too longwarn ≥ 300, fail ≥ 500 lines
Function LengthFunctions / methods that are too longwarn ≥ 40, fail ≥ 80 lines
Cyclomatic ComplexityFunctions with too many brancheswarn ≥ 10, fail ≥ 20
File SizeFiles exceeding size limitswarn ≥ 50 KB, fail ≥ 200 KB
Long LinesLines exceeding column widthwarn if >5% of lines over 120 chars
Import DepthDeep ../../../ import chainswarn ≥ 4, fail ≥ 6 levels
Directory DepthFolder nesting too deepwarn ≥ 7, fail ≥ 10 levels
Dependency CountToo many direct dependencieswarn ≥ 50, fail ≥ 100

Code Quality & Maintainability

CheckWhat it detects
TODO CountTODO, FIXME, HACK, BUG, XXX, NOSONAR markers in comments
Commented CodeBlocks of source code that have been commented out
Duplicate FilesExact binary-identical files with different names
Test RatioRatio of test files to source files — warns when tests are sparse
Mixed IndentFiles mixing tabs and spaces inconsistently
EncodingNon-UTF-8 files that cause cross-platform issues
Debug Leaksconsole.log, print(), debugger, var_dump(), dd() in production code
Secret LeaksHardcoded API keys, tokens, passwords, private keys
Gitignore CheckFiles tracked by git that match .gitignore patterns
Magic NumbersHardcoded numeric literals that should be named constants
Parameter CountFunctions / methods with too many parameters
Barrel FilesOversized index.ts/js re-export files that hurt tree-shaking and build times

Architecture & Design

CheckWhat it detects
Coupling MetricsHigh afferent/efferent coupling; flags “god files” and architecturally unstable modules
Cross-Layer ImportsForbidden import directions (e.g. UI components importing Prisma; API routes importing React)
Component InventorySimilar UI components/hooks grouped by pattern — suggests consolidation opportunities
Heavy ImportsFull-package imports of large libraries (lodash, moment, @mui/material) that block tree-shaking

Type Safety & Documentation

CheckWhat it detects
Any CoverageTypeScript any usage — counts explicit annotations, casts (as any), generics
JSDoc CoveragePercentage of exported functions, classes, and interfaces with JSDoc comments

Test Quality

CheckWhat it detects
Test RatioTest-to-source file ratio
Empty Testsit() / test() / def test_ / #[test] blocks with no assertions
LCOV CoverageReads existing lcov.info or coverage-summary.json — reports line, branch, function % without running tests

CI/CD Security

CheckWhat it detects
GitHub Actions AuditUnpinned actions, pull_request_target misuse, ${{ }} injection, hardcoded secrets in workflow files

Project health

CheckWhat it detects
.env ConsistencyKeys in .env missing from .env.example (fail); keys in .env.example missing from .env (warn); missing .env.example (warn)
Lockfile SyncMissing lockfile when a manifest exists (fail); lockfile older than manifest by mtime (warn) — npm/yarn/pnpm, Cargo, Go, Composer, Poetry
Node Version ConsistencyMismatched Node major/minor across .nvmrc, .node-version, .tool-versions, package.json engines, Dockerfile FROM node:
README CheckMissing README.md, too few lines, or missing Installation / Usage / Contributing / License sections
Changelog CheckMissing or non–Keep a Changelog CHANGELOG.md (## [Unreleased], version headings, standard subsections)
CODEOWNERS CheckMissing .github/CODEOWNERS, invalid paths, or missing catch-all * rule (git repos only)

TypeScript & frontend heuristics

CheckWhat it detects
Async/Await Misuseasync callbacks in .forEach(), .then() without .catch(), discarded Promise.all / race results (JS/TS)
Error HandlingEmpty or swallowed catch blocks; Python except: pass; Ruby rescue with no handling
Return TypesTypeScript functions / methods without explicit return type annotations (warnAt / failAt thresholds)
React Hook RulesuseEffect / useCallback / useMemo / useLayoutEffect / useInsertionEffect without a dependency array — only if react is in package.json
Accessibility CheckMissing img alt, empty decorative alt, unlabeled input / button / a in JSX, TSX, HTML, Vue, Svelte

Linters, tsconfig, and framework hints

CheckWhat it detects
ESLintProject ESLint rules when ESLint is configured
BiomeBiome diagnostics when biome.json (or related config) is present
OxlintFast Oxc linter when configured for the repo
Type SafetyType escape hatches: as any, @ts-ignore, and similar patterns
Non-null AssertionsOveruse of postfix ! non-null assertions
TS Config Audittsconfig.json strictness and important compiler flags
Enum UsageQuestionable enum patterns vs const objects / unions
Broad TypesOver-broad types such as Record<K, any>, Array<any>, loose object / Function
Zod ConsistencyDuplication or drift between Zod schemas and manual TypeScript types
ESLint Disableeslint-disable / file-level suppressions worth reviewing
Zod Anyz.any() fields that effectively disable validation
N+1ORM / query patterns that suggest N+1 round-trips in loops
Edge CompatibilityNode-only APIs that are incompatible with edge / worker runtimes
Use Client BoundaryNext.js 'use client' modules importing server-only resources

AI Agent Context

Project-scope checks for every file an AI coding agent reads before acting (AGENTS.md, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, Cursor / Antigravity / Windsurf / Zed rules, slash commands, prompt files, chatmodes, Anthropic Skills, and @import graphs). Limits are sourced from Anthropic Claude Code docs, OpenAI Codex docs, Cursor docs, and ACL 2023 tokenization research — not made up.

CheckWhat it detects
Context BudgetCombined token budget across all agent-visible files
Line Count / File SizePer-file caps for AGENTS.md, CLAUDE.md, copilot-instructions.md, rules
Recommended SectionsEnforces the SnakeFlow 10-section AGENTS.md template (Overview, Tech Stack, Commands, Code Style, Architecture, Testing, Security, PR/Commits, Common Tasks, Verify)
Structure Block DriftWarns when the managed <!-- SNAKEFLOW:STRUCTURE:BEGIN/END --> block in AGENTS.md drifted from projectStructure settings
Import GraphRejects @import chains deeper than 5 levels or with cycles
Cursor Rules FrontmatterValidates YAML frontmatter for .cursor/rules/*.mdc (required name, description, apply-mode)
CLAUDE.md ↔ AGENTS.md SyncFlags significant content drift between the two files
Copilot / AGENTS ConflictWarns when both .github/copilot-instructions.md and AGENTS.md exist with overlapping instructions
Absolute PathsMachine-specific paths (C:\Users\…, /home/…) that break on other machines
Secrets in ContextLeaked API keys / tokens inside any agent context file
Cyrillic Outside CodeCyrillic text in instructions (~2.75× token cost vs. English per ACL 2023)
Orphaned / Duplicate RulesUnreferenced or duplicated rule files across platforms

AGENTS.md Structure Sync — the command SnakeFlow: Sync AGENTS.md Structure Block regenerates a managed region inside AGENTS.md from projectStructure.fileRules / folderRules and quality.skipFiles / skipDirs. The block only injects non-inferable architectural hints (layer boundaries, file placement, required exports, don’t-touch zones) — numeric limits are deliberately excluded because auto-generated context files have been shown to reduce agent success rates by 0.5–3% (ETH Zurich, Feb 2026). Auto-sync triggers on settings change when devManager.agentContext.structureSync.autoSync is true.

Project Structure — Layer Visibility

The projectStructure.layers setting declares architectural layers with an explicit import allow-list (inspired by Bazel visibility = [...] / Buck package_boundary). Each file belongs to the first layer whose path glob matches; its relative imports must resolve to a layer listed in canImport.

Per-file exceptions — layers can declare exceptions: [{file, canImport}] for friend-module patterns (e.g. one file granted access to an otherwise private layer). The first exception whose file glob matches wins; if none match, the layer’s default canImport applies.

{
"name": "auth", "path": "src/auth/**", "canImport": ["utils"],
"exceptions": [
{ "file": "src/auth/service.ts", "canImport": ["utils", "crypto"] }
]
}

Config validation — before scanning imports, SnakeFlow validates the layer graph: duplicate names, unknown layer references in canImport / exceptions, and cyclic canImport edges (A -> B -> A) produce a single fail result with the exact cycle path. This turns misconfiguration into one actionable error instead of thousands of noisy per-import warnings chasing a broken contract.

A matching User Agent Context provider (agentContextUser.*) validates your global, cross-project files (~/.claude/**, ~/.codex/AGENTS.md, ~/.cursor/rules/**, ~/.cursor/skills/**, etc.) with the same rules.

Project Structure ↔ dependency-cruiser

Project Structure and dependency-cruiser are two independent checks with different jobs. SnakeFlow does not translate projectStructure.layers into depcruise forbidden rules — the two configs live side by side, and the relationship between them is enforced by a third check (Architecture Guidance) plus your AGENTS.md.

DimensionProject Structure (projectStructure.layers)dependency-cruiser (.dependency-cruiser.cjs)
Runs whereIn-process inside the extension (fast, live in editor)External CLI via npx depcruise (slower, CI-friendly)
Config sourceVS Code settings (devManager.quality.builtin.projectStructure.layers)Repo file: .dependency-cruiser.{cjs,js,mjs,json} or devManager.quality.builtin.dependencyCruiser.rules
Primary purposeLayer visibility / import allow-list (who-may-import-whom)Circular imports + arbitrary forbidden rule graph
ScopeYour own source only; respects skipDirsWhole JS/TS import graph incl. resolved node_modules refs
Per-file exceptionsYes — exceptions: [{file, canImport}] (friend modules)Yes — via depcruise forbidden[*].from.path regexes
Failure modePer-import warn/fail in Quality HubSingle aggregated report (count of cycles + violations)
Auto-translationNo — rules are not converted into depcruise configNo — reads only its own config
What the skill seesSettings JSON + the injected Project Structure block in AGENTS.md.dependency-cruiser.cjs + cruise:err script + AGENTS.md line

Why both?

  • Project Structure gives sub-second feedback while typing: it understands globs, friend-module exceptions, and emits one diagnostic per offending import. Great for the inner loop.
  • dependency-cruiser is the CI source of truth: it detects cycles the layer check intentionally doesn’t model, integrates with depcruise-reporter, produces SVG graphs, and is what external contributors’ PRs are gated on.
  • Running both means an agent that violates visibility gets caught twice: once live in the editor, once in CI. Different wording, same contract.

The bridge: Architecture Guidance (part of the agentContext provider). When SnakeFlow sees a .dependency-cruiser.{cjs,js,mjs,json} file (or .madgerc, or eslint-plugin-boundaries) but no mention of the tool in AGENTS.md / CLAUDE.md / GEMINI.md / copilot-instructions.md, it emits a warn:

Agent context doesn’t mention: dependency-cruiser — agents may write code that violates layer rules and fail CI

with the suggested fix:

## Verify Your Change
- Layer rules live in .dependency-cruiser.cjs; run `npm run cruise:err` before PR.

This is the mechanism that makes the skill actually see depcruise: it’s a plain-text line under ## Architecture / ## Verify Your Change that the agent reads the same way a human does, not a generated block.

Recommended setup when you use layer architecture:

  1. Declare layers once in projectStructure.layers — this is your source of truth for the inner loop and for the auto-synced Project Structure block in AGENTS.md (non-inferable hints only: layer boundaries, file placement, don’t-touch zones).
  2. Mirror the same boundaries in .dependency-cruiser.cjs as forbidden rules + a no-circular rule. Wire a cruise:err npm script:
    "scripts": { "cruise:err": "depcruise --config .dependency-cruiser.cjs src" }
  3. Add one line under ## Architecture in AGENTS.md: Layer rules live in .dependency-cruiser.cjs; run \npm run cruise:err` before PR.That line is whatArchitecture Guidance` looks for, and what the agent skill picks up when planning changes that touch imports.
  4. Leave devManager.quality.builtin.dependencyCruiser.enabled: true (default) so Quality Hub runs depcruise on every sweep — it reuses your repo’s .dependency-cruiser.cjs automatically.

Config resolution for dependency-cruiser (priority order, settings-wins):

  1. devManager.quality.builtin.dependencyCruiser.rules (written to a temp JSON file per run, passed via --config, then deleted).
  2. Local .dependency-cruiser.{cjs,js,mjs,json} in the manifest dir.
  3. --no-config (depcruise defaults — cycles only).

Database & migrations

CheckWhat it detects
Prisma Validateprisma validate when the Prisma CLI is available (supports single-file schema.prisma and multi-file prisma/schema/*.prisma — pass the folder to --schema)
Prisma Migrate StatusPending / drift Prisma migrations (needs DATABASE_URL when configured). When realtime is on, re-runs on changes under prisma/migrations/** and .env* (debounced, cached) — disable with devManager.quality.builtin.prismaMigrateStatus.realtime
Drizzle CheckDrizzle schema vs migration consistency when Drizzle tooling is present
No Manual MigrationsHand-written or hand-edited migration SQL (Drizzle, Prisma, or Atlas); optional git history scan for deleted/renamed migrations — also runs in realtime on save and file watch when enabled
Migrations CI GatePure Node: fails when a Prisma/Drizzle/Atlas project has no GitHub Actions workflow that runs migration safety commands (prisma migrate diff, drizzle-kit check, atlas migrate validate, SnakeFlow / cruise:err, etc.), or when realtime or No Manual Migrations is disabled locally

No Manual Migrations {#no-manual-migrations}

builtin-noManualMigrations discourages editing migration files by hand. It runs in the full Quality Hub sweep and, when realtime quality is on, re-checks on save and when watched migration/schema files change. Diagnostics attach to the offending file.

StackHow it works
DrizzlePreferred: a temporary wrapper drizzle.config.mjs re-exports your config with out: pointing to a temp dir, then drizzle-kit generate runs there and the extension diffs the result against your real migrations folder — this catches edits to existing .sql files, not only stray files. Fallback when regen is unavailable (old drizzle-kit, TS-only config without tsx, etc.): meta/_journal.json must list every .sql in out, plus drizzle-kit check / generate --check for drift. The migrations out path is resolved by importing the config via Node ESM (with npx tsx for .ts configs), cached by file mtime, with a regex fallback.
Prismaprisma migrate diff compares the schema to applied migrations and checks that concatenated migration.sql matches what Prisma would regenerate. Multi-file schema: if prisma/schema/*.prisma exists, --schema is passed the folder (same as Prisma CLI).
Atlasatlas migrate validateatlas.sum checksums must match migration files.
All adaptersWhen checkRemoved is on (default), recent git history is scanned for deleted or renamed files under the migrations directory — applied migrations should be append-only. Requires git in PATH and a git repo.

Settings:

"devManager.quality.builtin.noManualMigrations.enabled": true,
"devManager.quality.builtin.noManualMigrations.severity": "error",
"devManager.quality.builtin.noManualMigrations.adapters": ["drizzle", "prisma", "atlas"],
"devManager.quality.builtin.noManualMigrations.checkRemoved": true,
"devManager.quality.builtin.noManualMigrations.gitLookback": 50

adapters limits which toolchains to probe; each adapter skips when that stack is not detected. gitLookback is the number of recent commits scanned for delete/rename events (1–5000). Other ORMs (Rails, Django, TypeORM, etc.) are not covered in v1. Requires the relevant CLI in PATH or resolvable via npx where applicable.

See CLI tool checks — No Manual Migrations for install notes.

Squawk extras (data migrations & rollbacks)

The Squawk provider still runs the squawk-cli linter on .sql files. In addition, a pure Node post-pass can flag risky data migrations and missing down paths (configurable):

  • unbatched-data-migrationUPDATE / DELETE FROM without LIMIT or a batched WHERE … IN (…) pattern (heuristic; tune or disable if noisy).
  • missing-lock-timeoutBEGIN/COMMIT present without SET LOCAL lock_timeout or SET LOCAL statement_timeout.
  • missing-down-migration — for non-Prisma / non-Drizzle SQL or TS migrations: require a sibling *.down.sql next to *.up.sql, or a down() export in .ts/.js migrations (requireDownMigration).
"devManager.quality.builtin.squawk.dataRisk": "warn",
"devManager.quality.builtin.squawk.requireDownMigration": false

dataRisk: off | warn | error (default warn).


Configuring Thresholds

Every built-in check supports enabled, and most support warnAt/failAt thresholds:

"devManager.quality.builtin.lineCount.enabled": true,
"devManager.quality.builtin.lineCount.warnLines": 300,
"devManager.quality.builtin.lineCount.failLines": 500,
"devManager.quality.builtin.functionLength.warnLines": 40,
"devManager.quality.builtin.functionLength.failLines": 80,
"devManager.quality.builtin.complexity.warnScore": 10,
"devManager.quality.builtin.complexity.failScore": 20,
"devManager.quality.builtin.parameterCount.warnAt": 4,
"devManager.quality.builtin.parameterCount.failAt": 7,
"devManager.quality.builtin.dependencyCount.warnAt": 50,
"devManager.quality.builtin.dependencyCount.failAt": 100,
"devManager.quality.builtin.returnTypes.warnAt": 10,
"devManager.quality.builtin.returnTypes.failAt": 50

To disable a check entirely:

"devManager.quality.builtin.magicNumbers.enabled": false

The TypeScript Check (tscCheck) runs npx tsc --noEmit when tsconfig.json exists — see CLI Tool Checks.