Tell a Next.js codebase's claims from its behaviour: Prisma models nothing queries, env vars nothing reads, locales that drifted. CLI + MCP server for coding agents. Zero dependencies.
saas-audit provides 8 read-only tools with clear, domain-specific descriptions (avg 180 chars, well above 34-char baseline). All tools have input schemas with type definitions. However, parameter descriptions are sparse or missing entirely, most tools have 0-1 parameter descriptions despite accepting parameters. Tool names are clear verbs (audit, route_map, data_model, plans, locales, conventions, size, env_check) but lack the verb_noun pattern consistency. No output schemas are documented, forcing LLMs to infer response structure. Error handling is absent, no recovery guidance, categorization, or actionable error messages. Security is strong (read-only, no secrets exposed), but composition lacks pagination support and result limits for potentially large datasets.
The gaps between what this codebase declares and what it runs: Prisma models nothing queries, env vars read but undeclared, env vars declared but unread, locales that drifted. Call this before claiming a feature works, and again after a refactor. An empty list is a real answer.
The rules this codebase is written to — AGENTS.md, CLAUDE.md and .cursorrules, verbatim, whichever exist. Read them before your first edit rather than inferring conventions from a sample of files.
Prisma models with their field count and how many times src/ actually queries them through the generated client. A model with 0 uses is an empty table, not a feature — say so rather than describing it as one.
Environment variables the code reads, cross-checked against .env.example: which are declared, which are read by an SDK rather than by our code, which are missing, which are dead. Call this when a feature 'does nothing' — an undefined variable is the usual cause and it fails silently.
Per-locale translation health: keys missing against the default locale, empty values, extra keys, and ICU placeholder drift. Call this after adding any user-facing string — this project fails its build when one of the eight message files falls behind.
No output schemas documented. LLMs cannot infer response structure (fields, types, nesting). Agents must guess what data is returned, risking failed downstream tool calls and wasted context.
Parameter descriptions missing or minimal. 'locale' param in locales tool has description, but data_model, plans, conventions, size have empty input objects with no guidance. LLMs cannot determine what values are valid or expected.
No error handling or recovery guidance. Tools are read-only and unlikely to fail, but if they do (e.g., missing Prisma schema, malformed locale files), LLMs receive no actionable error message or next steps.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | 2026-07-28+ | v2 |
The billing plans exactly as src/lib/stripe.ts defines them: prices, limits (projects, apiCalls, seats) and feature lists. Read this before writing any plan gate or pricing copy — the pricing page, the seat enforcement and the API-key gate all derive from this one object, and hard-coding a number here is how they drift apart.
Every route derived from src/app/, with its kind (page or api) and whether src/middleware.ts guards it. Use this instead of guessing where a page lives or whether an endpoint is protected. A route can still guard itself with requireUser() even when the middleware does not match it.
How big this codebase actually is, per directory: file count, total lines, and lines that are neither blank nor comment. Useful for answering 'is this worth reading end to end' honestly.
No pagination or result limits documented. route_map and data_model could return hundreds of items; no limit parameter or guidance on max results. Large responses waste tokens and risk context window exhaustion.
Tool names lack consistent verb_noun pattern. 'route_map', 'data_model', 'plans', 'conventions', 'size' are nouns or noun phrases, not action verbs. Should be 'get_route_map', 'get_data_model', 'get_plans', 'get_conventions', 'get_size' for clarity.