<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harshit Rathod</title>
    <description>The latest articles on DEV Community by Harshit Rathod (@harshit_rathod).</description>
    <link>https://dev.to/harshit_rathod</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972207%2F3affed39-1b37-462a-8eb0-c163842a5353.jpg</url>
      <title>DEV Community: Harshit Rathod</title>
      <link>https://dev.to/harshit_rathod</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshit_rathod"/>
    <language>en</language>
    <item>
      <title>Why Large Codebases Drain Your AI Token Budget and How to Fit It</title>
      <dc:creator>Harshit Rathod</dc:creator>
      <pubDate>Sun, 05 Jul 2026 13:33:09 +0000</pubDate>
      <link>https://dev.to/harshit_rathod/why-large-codebases-drain-your-ai-token-budget-and-how-to-fit-it-5a2m</link>
      <guid>https://dev.to/harshit_rathod/why-large-codebases-drain-your-ai-token-budget-and-how-to-fit-it-5a2m</guid>
      <description>&lt;p&gt;&lt;em&gt;A technical breakdown of where context budget goes in large codebases, and the structural patterns that reduce consumption while increasing accuracy.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hook:&lt;/strong&gt; You add a new feature to a large NestJS monorepo with Claude's help. By the end of the conversation, the model has read 40 files, re-derived your module conventions twice, and still got the service placement wrong. You spent thousands of tokens. Claude spent most of them guessing. This guide explains why — and what to do about it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context windows don't scale with codebases.&lt;/strong&gt; A large repo has more decisions, more conventions, and more ambiguity — all of which drive up token consumption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The largest token sinks are re-derivation and uncertainty.&lt;/strong&gt; Claude reads more files when it doesn't know the architecture; it generates more text when it doesn't know the conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is the highest-leverage token saver.&lt;/strong&gt; A 300-line briefing file can replace hundreds of lines of exploratory file reads per session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules save tokens by preventing regeneration.&lt;/strong&gt; A wrong pattern that gets corrected costs twice — once to generate, once to fix. A prohibition rule prevents it entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills load context on demand.&lt;/strong&gt; Templates and references in skills only enter the context window when invoked, not on every session.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Answer
&lt;/h2&gt;

&lt;p&gt;Large repositories burn through AI tokens because Claude must read files to infer what any experienced team member already knows: which service owns what, what the error-handling pattern is, how responses are shaped, what's been deliberately removed. Every exploratory read, every wrong-service guess, every pattern that violates a convention and gets corrected is wasted context. The fix is to externalize that tribal knowledge into &lt;code&gt;CLAUDE.md&lt;/code&gt; (a briefing loaded every session), rules (prohibitions that prevent wrong output), and skills (on-demand workflows with templates). One-time setup; recurs on every feature.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Context Budget Is a Finite Resource
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Every token Claude reads or writes is budget spent.&lt;/strong&gt; Context windows are measured in tokens — not files, not lines — and every session starts with the same ceiling. In a small project, that budget is generous. In a large monorepo with several services, dozens of modules, hundreds of DTOs, and cross-cutting conventions, the budget evaporates fast.&lt;/p&gt;

&lt;p&gt;There are two places budget goes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Input tokens&lt;/strong&gt; — everything Claude reads: your prompt, files it opens, rules and docs it loads, the running conversation history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output tokens&lt;/strong&gt; — everything Claude generates: code, explanations, corrections, re-generations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both are expensive. But in a large repo, the &lt;strong&gt;input side is where the hemorrhage starts&lt;/strong&gt; — because Claude reads aggressively to compensate for what it doesn't know.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the Tokens Actually Go
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Exploratory File Reads
&lt;/h3&gt;

&lt;p&gt;When Claude doesn't know where something lives, it goes looking. In a well-indexed codebase, that might mean reading 3–4 files to locate the right module. In a large monorepo with ambiguous service boundaries, it can mean reading 15–20 before it's confident enough to act.&lt;/p&gt;

&lt;p&gt;A typical unconfigured session flow for "add a consumer-visible status to a booking package":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads &lt;code&gt;services/&lt;/code&gt; directory listing — &lt;em&gt;orientation&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;operator-service/src/modules/order/&lt;/code&gt; — &lt;em&gt;wrong service, discovers mismatch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;api-service/src/modules/order/&lt;/code&gt; — &lt;em&gt;corrects course&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;order.entity.ts&lt;/code&gt; — &lt;em&gt;finds the shape&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;order.service.ts&lt;/code&gt; — &lt;em&gt;finds the pattern&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;order.repository.ts&lt;/code&gt; — &lt;em&gt;finds the query layer&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;order.controller.ts&lt;/code&gt; — &lt;em&gt;finds the response shape&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;order.dto.ts&lt;/code&gt; — &lt;em&gt;finds the DTO convention&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads &lt;code&gt;transform-response.helper.ts&lt;/code&gt; — &lt;em&gt;finds the adapter pattern&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Reads 3–4 more files to verify cross-service adapter usage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's ~10 file reads &lt;strong&gt;before writing a single line of output&lt;/strong&gt;. Each read costs input tokens. In a large NestJS monorepo, files are not small — services, repositories, and controllers routinely exceed 200–400 lines each.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The same task in a configured session:&lt;/strong&gt; Claude reads &lt;code&gt;CLAUDE.md&lt;/code&gt;, knows the service boundary immediately, reads the 3 directly relevant files, and starts generating. The exploratory reads never happen.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convention Re-derivation
&lt;/h3&gt;

&lt;p&gt;Even when Claude lands in the right file, it still needs to infer your team's conventions. Without explicit documentation, it reads examples to reconstruct patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reads existing controllers to learn how responses are shaped&lt;/li&gt;
&lt;li&gt;It reads existing services to find which logger you use&lt;/li&gt;
&lt;li&gt;It reads existing guards to understand your permission system&lt;/li&gt;
&lt;li&gt;It reads multiple DTOs to infer your validation patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is pattern-matching by example. It works — but it costs tokens for every session, for every engineer, indefinitely. The conventions don't change; the re-derivation does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Convention re-derivation cost per session (rough estimate for a large NestJS monorepo):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Convention Claude Must Re-Derive&lt;/th&gt;
&lt;th&gt;Files Typically Read&lt;/th&gt;
&lt;th&gt;Estimated Token Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Service ownership (which belongs where)&lt;/td&gt;
&lt;td&gt;3–5 entry points&lt;/td&gt;
&lt;td&gt;~2,000–4,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response shape and interceptor pattern&lt;/td&gt;
&lt;td&gt;2–3 controllers&lt;/td&gt;
&lt;td&gt;~1,500–3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission system (guards + decorators)&lt;/td&gt;
&lt;td&gt;2–3 guards/controllers&lt;/td&gt;
&lt;td&gt;~1,000–2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error handling (constants + exceptions)&lt;/td&gt;
&lt;td&gt;2–3 services&lt;/td&gt;
&lt;td&gt;~1,000–2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logger usage&lt;/td&gt;
&lt;td&gt;1–2 services&lt;/td&gt;
&lt;td&gt;~500–1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Import style (alias vs relative)&lt;/td&gt;
&lt;td&gt;Several files&lt;/td&gt;
&lt;td&gt;~300–600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total per session (estimation)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~13–18 files&lt;/td&gt;
&lt;td&gt;~6,300–12,600 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's before the prompt, before the output, and before any task-specific reads. It's overhead — pure re-derivation of knowledge your team already has.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Wrong-Service Placement and Corrections
&lt;/h3&gt;

&lt;p&gt;When a codebase has multiple services with overlapping domains — say, a &lt;code&gt;package&lt;/code&gt; entity that exists in both the operator service (definition) and the consumer API (consumer-visible metadata) — Claude will guess. Sometimes it guesses right. Often it doesn't.&lt;/p&gt;

&lt;p&gt;A wrong-service guess costs tokens in three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exploration in the wrong service&lt;/strong&gt; — reading module structure, entities, and services in a service that won't receive the change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating the wrong output&lt;/strong&gt; — producing code in the wrong service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction&lt;/strong&gt; — you point out the error; Claude re-reads, re-reasons, and regenerates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practice, one wrong-service guess can cost more tokens than the correct implementation from the start.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Pattern Violations and Regeneration
&lt;/h3&gt;

&lt;p&gt;Without explicit prohibitions, Claude uses its training defaults. Those defaults are reasonable — but they won't match your team's conventions. Common mismatches in NestJS projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;console.log&lt;/code&gt; instead of a structured logger&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if (user.roles.includes('admin'))&lt;/code&gt; instead of &lt;code&gt;PermissionCodes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Relative &lt;code&gt;../../&lt;/code&gt; imports instead of the &lt;code&gt;src/&lt;/code&gt; alias&lt;/li&gt;
&lt;li&gt;Hardcoded error strings instead of &lt;code&gt;ErrorMessages&lt;/code&gt; constants&lt;/li&gt;
&lt;li&gt;Raw DB queries in a service instead of going through a repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each violation costs tokens twice: once to generate the wrong pattern, once to correct it. A single code generation that needs three corrections has effectively quadrupled the output token cost for that block.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Conversation History Accumulation
&lt;/h3&gt;

&lt;p&gt;As a session grows, the running conversation history is included in every subsequent call. In a long debugging or implementation session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Early file reads stay in context even when they're no longer relevant&lt;/li&gt;
&lt;li&gt;Corrections and re-generations add to history&lt;/li&gt;
&lt;li&gt;Claude's reasoning about dead ends accumulates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A session that spans 20 exchanges in a large codebase can have a conversation history that alone approaches the token limit of shorter sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix: Externalize Knowledge, Don't Re-Derive It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The underlying cause of excess token consumption is the same in every case: Claude is spending tokens to learn things your team already knows.&lt;/strong&gt; The fix is to make that knowledge available upfront, in a form Claude can read efficiently, rather than re-deriving it from source files every session.&lt;/p&gt;

&lt;p&gt;Three mechanisms do this, each suited to a different type of knowledge:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;What it encodes&lt;/th&gt;
&lt;th&gt;When Claude reads it&lt;/th&gt;
&lt;th&gt;Token impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Architecture, ownership, conventions&lt;/td&gt;
&lt;td&gt;Loaded automatically, every session&lt;/td&gt;
&lt;td&gt;Replaces exploratory reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard prohibitions and invariants&lt;/td&gt;
&lt;td&gt;Always active; prevents wrong output&lt;/td&gt;
&lt;td&gt;Eliminates regeneration cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skills&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-step workflows + templates&lt;/td&gt;
&lt;td&gt;On demand, when invoked&lt;/td&gt;
&lt;td&gt;Keeps templates out of always-on context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  CLAUDE.md: Replace Exploration With Declaration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is the single highest-leverage tool for reducing token consumption.&lt;/strong&gt; It's loaded at the start of every session, before any file reads, and it replaces the exploratory phase entirely for the information it contains.&lt;/p&gt;

&lt;p&gt;The key insight is &lt;strong&gt;specificity over completeness.&lt;/strong&gt; A bloated &lt;code&gt;CLAUDE.md&lt;/code&gt; that describes everything about NestJS is worse than a lean one that answers the exact questions Claude would otherwise need to read files to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which service owns what kind of data?&lt;/li&gt;
&lt;li&gt;What does the standard response shape look like?&lt;/li&gt;
&lt;li&gt;How does cross-service communication work?&lt;/li&gt;
&lt;li&gt;What are the project-specific patterns (logger, errors, permissions)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 300-line &lt;code&gt;CLAUDE.md&lt;/code&gt; that precisely answers those questions saves more tokens than a 1,000-line one that also explains what a repository pattern is.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to Include
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Service Routing Decision Table
&lt;/h4&gt;

&lt;p&gt;This is the single most effective thing you can document. Instead of Claude reading 10 files to figure out which service owns a new feature, it reads one table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Which Service Owns What
&lt;span class="p"&gt;
-&lt;/span&gt; operator-service — if the data describes _what an experience is_:
  package definitions, pricing, taxes, availability, operator accounts.
&lt;span class="p"&gt;-&lt;/span&gt; api-service — if the data describes _a consumer's interaction_:
  bookings, users, auth, trip planning, payments, notifications.

| Task involves...                   | Service                            |
| ---------------------------------- | ---------------------------------- |
| Package categories, pricing, slots | operator-service                   |
| Booking status, user profiles      | api-service                        |
| Stripe payments (consumer side)    | api-service                        |
| Cross-service booking flow         | Start in api-service → IMS adapter |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This table costs ~150 tokens to include in the context. It replaces 2,000–4,000 tokens of exploratory service reads. &lt;strong&gt;That's a 10–25× return on every session.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Conventions That Would Otherwise Be Re-Derived
&lt;/h4&gt;

&lt;p&gt;Document only what isn't already obvious from reading a single file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## What Claude Must Not Do&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="sb"&gt;`console.log`&lt;/span&gt; → use &lt;span class="sb"&gt;`logMessage()`&lt;/span&gt; from &lt;span class="sb"&gt;`src/common/utils/logger`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Check &lt;span class="sb"&gt;`user.role`&lt;/span&gt; → use &lt;span class="sb"&gt;`PermissionCodes`&lt;/span&gt; + &lt;span class="sb"&gt;`@Permissions()`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; DB call inside a loop → use bulk queries (&lt;span class="sb"&gt;`IN`&lt;/span&gt;, &lt;span class="sb"&gt;`JOIN`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; Relative &lt;span class="sb"&gt;`../../`&lt;/span&gt; imports → use the &lt;span class="sb"&gt;`src/`&lt;/span&gt; alias
&lt;span class="p"&gt;-&lt;/span&gt; TypeORM &lt;span class="sb"&gt;`synchronize: true`&lt;/span&gt; → Flyway manages all schema changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five prohibitions. ~100 tokens. Replaces all the file reads Claude would do to infer these patterns — and eliminates the regeneration cost when it gets them wrong.&lt;/p&gt;

&lt;h4&gt;
  
  
  Response Shape
&lt;/h4&gt;

&lt;p&gt;Include the exact shape, not a prose description:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Standard Response Shape&lt;/span&gt;

Controllers return &lt;span class="sb"&gt;`{ data, meta }`&lt;/span&gt;. TransformInterceptor wraps automatically:

return { data: { items }, meta: { path: request.path } };
// → { success: true, data: { items }, meta: { path }, error: null }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, Claude reads 2–3 controllers to infer the pattern. With it, Claude knows immediately — and gets it right the first time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to Exclude
&lt;/h3&gt;

&lt;p&gt;The token efficiency of &lt;code&gt;CLAUDE.md&lt;/code&gt; depends as much on what you leave out as what you put in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework documentation&lt;/strong&gt; — Claude already knows what a NestJS guard is. Document only your project-specific guard setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code that's derivable from files&lt;/strong&gt; — if Claude can read one file and learn a pattern, don't repeat it in &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable, obvious conventions&lt;/strong&gt; — use TypeScript, use async/await, follow the module pattern. These are defaults; they cost tokens but add no information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task-specific templates&lt;/strong&gt; — templates belong in skills, not &lt;code&gt;CLAUDE.md&lt;/code&gt;. They should enter the context on demand, not every session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Target: under 300 lines.&lt;/strong&gt; If your &lt;code&gt;CLAUDE.md&lt;/code&gt; is longer, audit it for derivable content. Every line that doesn't prevent a file read or a wrong pattern is a line that should be cut.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rules: Prevent Regeneration at the Source
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A wrong pattern that's regenerated after correction costs twice the tokens of getting it right the first time.&lt;/strong&gt; Rules cut this cost to zero by making the wrong pattern impossible to generate.&lt;/p&gt;

&lt;p&gt;Rules live in &lt;code&gt;.claude/rules/&lt;/code&gt; as Markdown files. They're phrased as prohibitions — not preferences — because "NEVER call the DB in a loop" is enforced, while "prefer bulk queries" is suggestion that gets ignored under pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Cost of a Rule vs. a Correction
&lt;/h3&gt;

&lt;p&gt;Consider N+1 queries. Without a rule, here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude generates code with a DB call inside a loop &lt;em&gt;(output tokens)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You read the generated code and identify the N+1 &lt;em&gt;(your time)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You explain the issue to Claude &lt;em&gt;(input tokens)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Claude re-reads the context to understand the correction &lt;em&gt;(context re-processing)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Claude regenerates the correct bulk-query version &lt;em&gt;(output tokens)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total: roughly 2× the output tokens for that block, plus the input tokens for the correction exchange.&lt;/p&gt;

&lt;p&gt;With a rule:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rule is in context; Claude generates the correct bulk-query pattern &lt;em&gt;(output tokens)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total: 1× output tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rule itself costs ~200 tokens to include in the session. It saves 1× output tokens plus correction overhead on every N+1 occurrence.&lt;/strong&gt; In a session with 3–4 such violations, it pays for itself many times over.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-Value Rules for NestJS Projects
&lt;/h3&gt;

&lt;p&gt;Rules that deliver the highest token savings are those that prevent patterns Claude's training considers reasonable but that violate your project's conventions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;N+1 Query Prevention&lt;/strong&gt; — Claude defaults to per-entity lookups in loops; this stops it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Database Query Rules — No N+1&lt;/span&gt;

NEVER make a database call inside a loop. Use a single bulk query, then
group results in memory. If unsure whether a pattern causes N+1, ask first.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Permission System&lt;/strong&gt; — Claude defaults to role-name checks; this redirects it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Authorization — Never Check Role Names&lt;/span&gt;

NEVER check &lt;span class="sb"&gt;`user.role`&lt;/span&gt;, &lt;span class="sb"&gt;`user.roles`&lt;/span&gt;, or any role-name string.
Use &lt;span class="sb"&gt;`@Permissions([PermissionCodes.X])`&lt;/span&gt; with &lt;span class="sb"&gt;`PermissionsGuard`&lt;/span&gt; instead.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Import Style&lt;/strong&gt; — Claude defaults to relative imports; this enforces the alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Imports — Always Use the Path Alias&lt;/span&gt;

NEVER use relative imports that traverse more than one directory level.
Use &lt;span class="sb"&gt;`src/modules/...`&lt;/span&gt; alias imports everywhere.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these rules costs ~100–200 tokens per session to include. Each saves the token cost of generating a violation plus the correction exchange — conservatively 500–2,000 tokens per occurrence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Skills: Keep Templates Out of Always-On Context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Skills are on-demand context.&lt;/strong&gt; Templates, references, and workflow guides for repeated tasks are exactly the kind of high-token content that should not be in &lt;code&gt;CLAUDE.md&lt;/code&gt; — because they're only relevant when you're doing that specific task.&lt;/p&gt;

&lt;p&gt;A controller template for your NestJS service is ~50–100 lines. In a CLAUDE.md, that's 50–100 lines of context included in every session, even when you're debugging, writing tests, or reading logs. In a skill, those same lines only enter the context when you run &lt;code&gt;/api-development&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Budget Impact of Skills
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;In CLAUDE.md (always loaded)&lt;/th&gt;
&lt;th&gt;In a skill (on demand)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Controller template (80 lines)&lt;/td&gt;
&lt;td&gt;~400 tokens × every session&lt;/td&gt;
&lt;td&gt;~400 tokens × only when invoked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service template (80 lines)&lt;/td&gt;
&lt;td&gt;~400 tokens × every session&lt;/td&gt;
&lt;td&gt;~400 tokens × only when invoked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository template (60 lines)&lt;/td&gt;
&lt;td&gt;~300 tokens × every session&lt;/td&gt;
&lt;td&gt;~300 tokens × only when invoked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DTO examples (40 lines)&lt;/td&gt;
&lt;td&gt;~200 tokens × every session&lt;/td&gt;
&lt;td&gt;~200 tokens × only when invoked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~1,300 tokens per session&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~1,300 tokens when you need it&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you scaffold endpoints 3 times a week but run 20 sessions per week, templates in &lt;code&gt;CLAUDE.md&lt;/code&gt; cost 20 × 1,300 = 26,000 tokens. In a skill, they cost 3 × 1,300 = 3,900 tokens. &lt;strong&gt;Same result, 85% fewer tokens for the templates alone.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Skill Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/skills/api-development/
├── SKILL.md                    # Workflow: trigger, steps, decision points
├── assets/
│   ├── controller-template.md  # Real, compilable code templates
│   ├── service-template.md
│   ├── repository-template.md
│   └── dto-template.md
└── references/
    ├── nestjs-conventions.md
    └── swagger-documentation.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;SKILL.md&lt;/code&gt; workflow guides Claude through the task deterministically — DTO first (it defines the contract), then repository (queries only), then service (business logic), then controller (HTTP routing). Without the workflow, Claude invents its own order and sometimes generates the controller before the DTO exists, requiring re-generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture: Per-Service CLAUDE.md Files
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A monorepo has a root context problem.&lt;/strong&gt; Everything in the root &lt;code&gt;CLAUDE.md&lt;/code&gt; loads every session, regardless of which service you're working in. Details specific to &lt;code&gt;operator-service&lt;/code&gt;'s DI patterns are wasted tokens when you're debugging auth in &lt;code&gt;api-service&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix is a two-level structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/CLAUDE.md                   # Cross-cutting: routing, shared conventions
services/
  api-service/CLAUDE.md             # api-service specific: module patterns, auth, DI
  operator-service/CLAUDE.md        # operator-service specific: IMS adapter, pricing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude reads the root &lt;code&gt;CLAUDE.md&lt;/code&gt; always, and the service-level file when you work in that directory. Cross-cutting concerns (service ownership, response shape, shared error constants) live at root. Service-specific depth (auth flows, module patterns, DI tokens) lives in the service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token impact:&lt;/strong&gt; If each service file is 150 lines (~750 tokens), keeping them separate means you load at most 750 extra tokens per session instead of both services' details at all times. For a multi-service monorepo, that's up to 2,250 tokens of context avoided per session.&lt;/p&gt;




&lt;h2&gt;
  
  
  Measuring the Impact
&lt;/h2&gt;

&lt;p&gt;Here's the before/after for a realistic "add a consumer-visible booking status" task in a large NestJS monorepo:&lt;/p&gt;

&lt;h3&gt;
  
  
  Without Configuration
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Token Estimate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exploratory directory reads (service placement)&lt;/td&gt;
&lt;td&gt;~3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Convention re-derivation (logger, perms, errors)&lt;/td&gt;
&lt;td&gt;~6,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong-service generation and correction&lt;/td&gt;
&lt;td&gt;~4,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pattern violations and regeneration (3×)&lt;/td&gt;
&lt;td&gt;~3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual task output (correct code, 4 files)&lt;/td&gt;
&lt;td&gt;~4,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~20,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  With CLAUDE.md + Rules + Skills
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Token Estimate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLAUDE.md load (routing, conventions, shape)&lt;/td&gt;
&lt;td&gt;~1,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rules load (3 rules)&lt;/td&gt;
&lt;td&gt;~600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Targeted file reads (3 directly relevant files)&lt;/td&gt;
&lt;td&gt;~2,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill invocation (templates, workflow)&lt;/td&gt;
&lt;td&gt;~1,300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual task output (correct code, 4 files)&lt;/td&gt;
&lt;td&gt;~4,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~9,900&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;~50% reduction in total token consumption for a single task.&lt;/strong&gt; For a team running dozens of sessions per week, the savings are substantial — and they compound because the ratio stays roughly constant across tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes That Maximize Token Waste
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Each of these looks harmless and silently burns budget across every session.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Putting templates in CLAUDE.md.&lt;/strong&gt; Templates are task-specific. Loading them every session is waste. Move them to skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing CLAUDE.md as a tutorial.&lt;/strong&gt; Explaining NestJS fundamentals Claude already knows inflates context without replacing any file reads. Document only what's unique to your project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omitting the routing decision table.&lt;/strong&gt; Service placement ambiguity is the single largest driver of exploratory reads. A table makes the decision free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing rules as preferences.&lt;/strong&gt; "Prefer bulk queries" leaves Claude room to choose. "NEVER call the DB in a loop" doesn't. The second form prevents regeneration; the first doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One flat CLAUDE.md for a monorepo.&lt;/strong&gt; All service-specific content loads every session. Split into root + per-service files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cross-service communication rules.&lt;/strong&gt; Without explicit guidance, Claude reaches across service boundaries — reads the wrong DB, imports across services. The correction exchange is expensive. One sentence in CLAUDE.md prevents it.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Real-World Example: Token Budget on a Feature Request
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The request:&lt;/strong&gt; &lt;em&gt;"Add a consumer-visible status to a booking package."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unconfigured session token trace:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[read] services/                              ~200 tokens
[read] operator-service/src/modules/order/ ~150 tokens
[read] operator-service order.entity.ts    ~600 tokens  ← wrong service
[read] api-service/src/modules/order/      ~150 tokens  ← course correction
[read] api-service order.entity.ts         ~500 tokens
[read] api-service order.service.ts        ~800 tokens
[read] api-service order.repository.ts     ~600 tokens
[read] api-service order.controller.ts     ~700 tokens
[read] api-service order.dto.ts            ~400 tokens
[read] transform-response.helper.ts          ~300 tokens
[read] ims-adapter.ts                        ~700 tokens
...                                          ~3,000 more (permissions, logger, errors)
[generate] wrong permission check            ~400 tokens
[correction] permission explanation          ~200 tokens
[generate] correct permission                ~200 tokens
[generate] actual implementation (4 files)  ~4,000 tokens
Total: ~12,900 input + ~4,600 output ≈ 17,500 tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configured session token trace:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[load] CLAUDE.md (routing, conventions)      ~1,500 tokens
[load] rules (3 rules)                        ~600 tokens
[invoke] /api-development skill             ~1,300 tokens
[read] api-service order.service.ts        ~800 tokens  ← targeted read
[read] api-service order.repository.ts     ~600 tokens  ← targeted read
[read] ims-adapter.ts                        ~700 tokens  ← targeted read
[generate] implementation (4 files, correct) ~4,000 tokens
Total: ~5,500 input + ~4,000 output ≈ 9,500 tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation output is nearly identical. The savings come entirely from eliminating exploratory reads, wrong-service generation, and pattern violations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary: The Token Budget Formula
&lt;/h2&gt;

&lt;p&gt;Token consumption in a large repo follows a predictable formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total tokens = (exploration overhead) + (re-derivation overhead) + (correction overhead) + (actual task output)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration attacks the first three terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLAUDE.md&lt;/strong&gt; eliminates exploration overhead and most re-derivation overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules&lt;/strong&gt; eliminate correction overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; shift task-specific re-derivation from every-session to on-demand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The actual task output — the code you asked for — is roughly constant. Everything else is overhead, and it's reducible.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why does Claude read so many files in a large repo?&lt;/strong&gt;&lt;br&gt;
Claude compensates for uncertainty with exploration. When it doesn't know which service owns a feature, it reads multiple services to decide. When it doesn't know your response shape, it reads multiple controllers. &lt;code&gt;CLAUDE.md&lt;/code&gt; replaces that uncertainty with declared knowledge, eliminating the reads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a larger CLAUDE.md always save more tokens?&lt;/strong&gt;&lt;br&gt;
No — the relationship inverts past a threshold. A 300-line &lt;code&gt;CLAUDE.md&lt;/code&gt; that answers the right questions saves more tokens than a 1,000-line one that also includes tutorials and templates. The goal is maximum information density per line, not maximum coverage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much do wrong patterns actually cost?&lt;/strong&gt;&lt;br&gt;
A single N+1 query correction in a longer session can cost 500–2,000 tokens: input for your correction message plus output for the re-generation. Across a week of development with multiple sessions, prevention rules pay for themselves quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I measure token usage per session in Claude Code?&lt;/strong&gt;&lt;br&gt;
Claude Code doesn't currently expose per-session token metrics directly. Proxy signals: session length before context compression kicks in, whether you see "context window approaching limit" warnings, and how many file reads appear in the tool call log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are skills just macros?&lt;/strong&gt;&lt;br&gt;
Skills are more than macros — they bundle a workflow (ordered steps, decision points), templates (compilable code), and references (conventions, Swagger patterns) into a single invocable command. The workflow is what prevents out-of-order generation and the correction overhead that comes with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should &lt;code&gt;CLAUDE.md&lt;/code&gt; be the same for every engineer on the team?&lt;/strong&gt;&lt;br&gt;
Yes — commit it to git so the configuration is shared and versioned. Personal overrides go in &lt;code&gt;.claude/settings.local.json&lt;/code&gt;, which is gitignored. The team-level conventions in &lt;code&gt;CLAUDE.md&lt;/code&gt; apply to everyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this approach work for repos that aren't NestJS?&lt;/strong&gt;&lt;br&gt;
The token-saving logic applies to any large codebase with team-specific conventions. The specific content changes (replace NestJS patterns with your stack's patterns), but the structure — &lt;code&gt;CLAUDE.md&lt;/code&gt; for routing and conventions, rules for prohibitions, skills for repeated workflows — is framework-agnostic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways (Recap)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token waste in large repos has a root cause:&lt;/strong&gt; Claude reads files to learn what your team already knows. The fix is to tell it upfront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; replaces exploration.&lt;/strong&gt; A service routing table costs ~150 tokens; it replaces 2,000–4,000 tokens of exploratory reads per session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules eliminate regeneration.&lt;/strong&gt; A prohibition costs ~200 tokens once; it saves 500–2,000 tokens every time the wrong pattern would have been generated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills keep templates off the always-on context.&lt;/strong&gt; Load them only when you're scaffolding, not in every session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split by service.&lt;/strong&gt; Per-service &lt;code&gt;CLAUDE.md&lt;/code&gt; files prevent service-specific context from loading in unrelated sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The savings compound.&lt;/strong&gt; Every session, every engineer, every feature — the overhead reduction is consistent because the root cause is structural.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Token exhaustion in large repositories isn't a limitation of the AI — it's an information architecture problem. Claude reads aggressively because the knowledge it needs to act confidently isn't in any single file. It re-derives conventions that haven't changed. It generates wrong patterns that get corrected. It explores the wrong service before finding the right one.&lt;/p&gt;

&lt;p&gt;The fix isn't a larger context window. It's externalizing your team's tribal knowledge into structured, version-controlled form — a &lt;code&gt;CLAUDE.md&lt;/code&gt; that answers the questions Claude would otherwise spend tokens asking, rules that prevent the patterns it would otherwise spend tokens regenerating, and skills that load task-specific context only when you need it.&lt;/p&gt;

&lt;p&gt;The investment is a few hours. The savings recur on every session, for every engineer, indefinitely.&lt;/p&gt;




&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.claude.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code documentation&lt;/a&gt; — official setup, configuration, and best-practices reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="//./claude-code-nestjs-setup.md"&gt;How to Set Up Claude Code for a NestJS Monorepo&lt;/a&gt; — the companion guide to this article; step-by-step configuration walkthrough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.nestjs.com" rel="noopener noreferrer"&gt;NestJS documentation&lt;/a&gt; — providers, guards, interceptors, and module architecture&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Token estimates in this article are illustrative approximations based on observed session patterns in a production NestJS monorepo with several services. Actual consumption varies by model, file sizes, and task complexity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>contextengineering</category>
      <category>tokenoptimizations</category>
      <category>claude</category>
    </item>
    <item>
      <title>Claude Code for NestJS Monorepos: A Practical Setup Guide</title>
      <dc:creator>Harshit Rathod</dc:creator>
      <pubDate>Sun, 07 Jun 2026 08:53:54 +0000</pubDate>
      <link>https://dev.to/harshit_rathod/claude-code-for-nestjs-monorepos-a-practical-setup-guide-46l8</link>
      <guid>https://dev.to/harshit_rathod/claude-code-for-nestjs-monorepos-a-practical-setup-guide-46l8</guid>
      <description>&lt;p&gt;&lt;em&gt;A practical, step-by-step guide to configuring Claude Code with CLAUDE.md, rules, and skills so AI-generated code matches your team's conventions in a large NestJS monorepo.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hook:&lt;/strong&gt; Ask Claude to "add a consumer-visible status to a booking" in an unconfigured monorepo, and it will happily edit the &lt;em&gt;wrong microservice&lt;/em&gt;, hardcode an error string, and check &lt;code&gt;user.role === 'admin'&lt;/code&gt;. None of that is Claude being wrong — it's Claude guessing. This guide removes the guessing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code reads &lt;code&gt;.claude/&lt;/code&gt; from your git root&lt;/strong&gt;, so one configuration governs every service in the monorepo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three mechanisms do the heavy lifting:&lt;/strong&gt; &lt;code&gt;CLAUDE.md&lt;/code&gt; (always-loaded project briefing), &lt;strong&gt;rules&lt;/strong&gt; (hard prohibitions), and &lt;strong&gt;skills&lt;/strong&gt; (multi-step workflows with templates).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The single biggest win is service routing&lt;/strong&gt; — a decision table in &lt;code&gt;CLAUDE.md&lt;/code&gt; stops Claude from putting consumer logic in the operator service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write rules as prohibitions, not preferences&lt;/strong&gt; — "NEVER query the DB in a loop" is enforced; "prefer bulk queries" is ignored under pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup is a few hours, one-time&lt;/strong&gt;, and pays back on every feature: faster scaffolding, fewer convention violations in review, and faster onboarding.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Answer
&lt;/h2&gt;

&lt;p&gt;To set up Claude Code for a NestJS monorepo: &lt;br&gt;
(1) install it with &lt;code&gt;npm install -g @anthropic-ai/claude-code&lt;/code&gt; and authenticate once via &lt;code&gt;claude&lt;/code&gt;; (2) create a root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt; that documents which service owns what, your request pipeline, and your standard response shape; (3) add a &lt;code&gt;.claude/rules/&lt;/code&gt; folder with hard prohibitions (no N+1 queries, no role-name checks, no relative imports); (4) build a &lt;code&gt;.claude/skills/&lt;/code&gt; folder with multi-step workflows and code templates for repeated tasks like creating an endpoint; and (5) add &lt;code&gt;.claude/settings.json&lt;/code&gt; to allow safe commands and deny destructive ones. Commit &lt;code&gt;.claude/&lt;/code&gt; to git so the whole team shares it. The result: Claude generates code that follows your conventions on the first try, instead of guessing.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem: Why Claude Struggles With Large NestJS Projects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A large NestJS monorepo is one of the hardest environments for any AI coding assistant, because correctness depends on conventions that are invisible in any single file.&lt;/strong&gt; A codebase with dozens of modules, hundreds of DTOs, and custom guards, interceptors, filters, and adapters is genuinely ambiguous. Without context, Claude fills that ambiguity with reasonable defaults — and those defaults won't match your team's conventions.&lt;/p&gt;

&lt;p&gt;Concretely, an unconfigured Claude will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call the database directly from a service instead of going through a repository&lt;/li&gt;
&lt;li&gt;Hardcode error strings instead of using your &lt;code&gt;ErrorMessages&lt;/code&gt; constants&lt;/li&gt;
&lt;li&gt;Put a new file in the wrong service (booking logic in &lt;code&gt;operator-service&lt;/code&gt; when it belongs in &lt;code&gt;api-service&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;user.role === 'admin'&lt;/code&gt; instead of using &lt;code&gt;PermissionCodes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;console.log&lt;/code&gt; instead of your structured logger&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;../../common/utils&lt;/code&gt; instead of the &lt;code&gt;src/&lt;/code&gt; path alias&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Why This Problem Exists
&lt;/h2&gt;

&lt;p&gt;These aren't bugs in Claude — they're the predictable result of asking a model to infer team-specific decisions it was never told about. An AI assistant only sees the files it reads in a session; it cannot see &lt;em&gt;why&lt;/em&gt; your team removed &lt;code&gt;RolesGuard&lt;/code&gt;, that &lt;code&gt;synchronize&lt;/code&gt; must stay &lt;code&gt;false&lt;/code&gt;, or that two services communicate only over HTTP adapters. Tribal knowledge that lives in your engineers' heads is exactly the knowledge Claude lacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix is to externalize that tribal knowledge into version-controlled context&lt;/strong&gt; through three mechanisms, each suited to a different kind of knowledge:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;What it encodes&lt;/th&gt;
&lt;th&gt;When Claude uses it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Architecture, ownership, conventions&lt;/td&gt;
&lt;td&gt;Loaded automatically every session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard prohibitions and invariants&lt;/td&gt;
&lt;td&gt;Enforced on every code generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skills&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-step workflows + templates&lt;/td&gt;
&lt;td&gt;Invoked on demand for repeated tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Repository Structure
&lt;/h2&gt;

&lt;p&gt;Before configuring anything, anchor on the layout. A well-structured NestJS monorepo looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-backend/
├── .claude/                  # Everything Claude needs to operate well
│   ├── CLAUDE.md             # Root-level instructions (always loaded)
│   ├── rules/                # Enforced coding constraints
│   ├── skills/               # Custom slash commands with deep context
│   └── settings.json         # Command permissions
├── services/
│   ├── api-service/          # NestJS consumer API (port 5001)
│   ├── operator-service/     # NestJS operator/vendor API (port 5002)
│   ├── chat-service/         # Express + Socket.IO (JavaScript, port 5005)
│   └── job-service/          # Scheduled jobs, no HTTP server
├── db/migration/             # Flyway migrations per schema
└── package.json              # Root: only husky + lint-staged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each service is an independent NestJS app with its own &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;tsconfig.json&lt;/code&gt;, and build output. Inside each service, every feature module follows the same strict three-layer structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/modules/booking/
├── booking.module.ts
├── controllers/    # HTTP routing only, no logic
├── services/       # Business logic and orchestration
├── repositories/   # TypeORM queries only
└── dtos/           # Request/response shapes, validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; This separation is exactly what Claude needs to respect. If it doesn't know the pattern, it mixes layers — services querying the DB directly, controllers calling repositories.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Suggested visual: a diagram of the git-root &lt;code&gt;.claude/&lt;/code&gt; directory applying across all four services.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step: Configuring Claude Code for NestJS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Install Claude Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
claude   &lt;span class="c"&gt;# opens a browser for one-time OAuth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After authenticating, &lt;code&gt;claude&lt;/code&gt; works from any directory. Each developer installs and authenticates independently — there's no shared API key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Monorepo tip:&lt;/strong&gt; Claude reads &lt;code&gt;.claude/&lt;/code&gt; from the &lt;strong&gt;git root&lt;/strong&gt;, so its instructions apply no matter where you invoke Claude. When working on one service, &lt;code&gt;cd&lt;/code&gt; into it (e.g. &lt;code&gt;services/api-service/&lt;/code&gt;) so file searches and commands scope correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2 — Create CLAUDE.md
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is the single most important file you will write — it's the briefing Claude reads at the start of every session.&lt;/strong&gt; Think of it as onboarding documentation for a senior engineer on day one. Place it at two levels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — service ownership, shared conventions, the request pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-service &lt;code&gt;services/{service}/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — module patterns, auth, and DI specific to that service&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  The Root CLAUDE.md
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Claude can't tell which service should own a new file, so it guesses — and lands consumer logic in the operator service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A routing decision table plus explicit "never do this" rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Files land in the correct service on the first pass.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Monorepo Structure&lt;/span&gt;

Four services under &lt;span class="sb"&gt;`services/`&lt;/span&gt;, each independently runnable.
Run all commands from inside the service directory.

| Service            | Port | Stack                    | Purpose              |
| ------------------ | ---- | ------------------------ | -------------------- |
| &lt;span class="sb"&gt;`api-service`&lt;/span&gt;      | 5001 | NestJS + TypeScript      | Consumer-facing API  |
| &lt;span class="sb"&gt;`operator-service`&lt;/span&gt; | 5002 | NestJS + TypeScript      | Operator/vendor mgmt |
| &lt;span class="sb"&gt;`chat-service`&lt;/span&gt;     | 5005 | Express + Socket.IO + JS | Real-time messaging  |
| &lt;span class="sb"&gt;`job-service`&lt;/span&gt;      | —    | Node.js + TypeScript     | Scheduled jobs       |

&lt;span class="gu"&gt;## Which Service Owns What&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="gs"&gt;**operator-service**&lt;/span&gt; — if the data describes _what an experience is_:
  package definitions, pricing, taxes, availability, operator accounts.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**api-service**&lt;/span&gt; — if the data describes _a consumer's interaction_:
  bookings, users, auth, trip planning, payments, notifications.

| Task involves...                   | Service                            |
| ---------------------------------- | ---------------------------------- |
| Package categories, pricing, slots | operator-service                   |
| Booking status, user profiles      | api-service                        |
| Stripe payments (consumer side)    | api-service                        |
| Cross-service booking flow         | Start in api-service → IMS adapter |

&lt;span class="gu"&gt;## Global Request Pipeline (in order)&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="sb"&gt;`TraceContextMiddleware`&lt;/span&gt; — sets &lt;span class="sb"&gt;`correlationId`&lt;/span&gt; in &lt;span class="sb"&gt;`AsyncLocalStorage`&lt;/span&gt;
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="sb"&gt;`ValidationPipe`&lt;/span&gt; — whitelist mode, flattens DTO errors
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="sb"&gt;`LoggerInterceptor`&lt;/span&gt; — logs request/response
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="sb"&gt;`TransformInterceptor`&lt;/span&gt; — wraps return value in the standard shape
&lt;span class="p"&gt;5.&lt;/span&gt; Exception filters (&lt;span class="sb"&gt;`HttpExceptionFilter`&lt;/span&gt;, &lt;span class="sb"&gt;`TypeOrmExceptionFilter`&lt;/span&gt;, …)

&lt;span class="gu"&gt;## Standard Response Shape&lt;/span&gt;

Controllers return &lt;span class="sb"&gt;`{ data, meta }`&lt;/span&gt;; &lt;span class="sb"&gt;`TransformInterceptor`&lt;/span&gt; wraps it:
return { data: { items }, meta: { path: request.path } };
// → { success: true, data: { items }, meta: { path }, error: null }

&lt;span class="gu"&gt;## Cross-Service Communication&lt;/span&gt;

api-service NEVER touches operator-service's database. All reads/writes go
through HTTP adapters in &lt;span class="sb"&gt;`src/common/adapters/`&lt;/span&gt; (they handle OAuth refresh and
trace propagation). Need operator data? Call the adapter, never the DB.

&lt;span class="gu"&gt;## What Claude Must Never Do&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Use &lt;span class="sb"&gt;`console.log`&lt;/span&gt; → use &lt;span class="sb"&gt;`logMessage()`&lt;/span&gt; from &lt;span class="sb"&gt;`src/common/utils/logger`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Check &lt;span class="sb"&gt;`user.role`&lt;/span&gt; → use &lt;span class="sb"&gt;`PermissionCodes`&lt;/span&gt; + &lt;span class="sb"&gt;`@Permissions()`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Query the DB inside a loop → use bulk queries (&lt;span class="sb"&gt;`IN`&lt;/span&gt;, &lt;span class="sb"&gt;`JOIN`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; Use relative &lt;span class="sb"&gt;`../../`&lt;/span&gt; imports → use the &lt;span class="sb"&gt;`src/`&lt;/span&gt; alias
&lt;span class="p"&gt;-&lt;/span&gt; Set TypeORM &lt;span class="sb"&gt;`synchronize: true`&lt;/span&gt; → Flyway manages all schema changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What makes a good CLAUDE.md:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision rules over directory listings.&lt;/strong&gt; "If the data describes what an experience &lt;em&gt;is&lt;/em&gt;, it lives in operator-service" lets Claude resolve ambiguity without asking you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include the response shape.&lt;/strong&gt; Otherwise Claude manually wraps responses in every controller, creating inconsistencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List what NOT to do.&lt;/strong&gt; "Never use &lt;code&gt;console.log&lt;/code&gt;" is more actionable than "use our logger."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document what was removed.&lt;/strong&gt; When you delete a &lt;code&gt;RolesGuard&lt;/code&gt; or a &lt;code&gt;synchronize&lt;/code&gt; flag, say why — or Claude will reintroduce it because it looks natural.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Service-Level CLAUDE.md
&lt;/h4&gt;

&lt;p&gt;Each service gets its own file for details too specific for the root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# api-service/CLAUDE.md&lt;/span&gt;

&lt;span class="gu"&gt;## Module Architecture — never mix layers&lt;/span&gt;

controllers/ HTTP routing only — call service, return data
services/ Business logic — orchestrate repos, no direct DB calls
repositories/ TypeORM queries only — accept EntityManager for transactions

&lt;span class="gu"&gt;## Authentication&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="sb"&gt;`JwtAuthGuard`&lt;/span&gt; validates Bearer tokens, attaches &lt;span class="sb"&gt;`UserRequest`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`PermissionsGuard`&lt;/span&gt; reads &lt;span class="sb"&gt;`@Permissions([PermissionCodes.X])`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never use RolesGuard or check role names — removed intentionally

&lt;span class="gu"&gt;## Dependency Injection&lt;/span&gt;

Register services by interface token, and inject by token, not class:
{ provide: SERVICE_INTERFACE.BOOKING_SERVICE, useClass: BookingService }

&lt;span class="gu"&gt;## Background Jobs&lt;/span&gt;

BullMQ + Redis. Processors live in &lt;span class="sb"&gt;`src/modules/{module}/processors/`&lt;/span&gt;.
Enqueue via the module's service — never from a controller.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 — Add Rules
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rules are hard prohibitions — they don't describe architecture, they prevent specific patterns, like an ESLint config for AI-generated code.&lt;/strong&gt; They live in &lt;code&gt;.claude/rules/&lt;/code&gt; as Markdown files.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use &lt;code&gt;CLAUDE.md&lt;/code&gt; for&lt;/th&gt;
&lt;th&gt;Use &lt;code&gt;rules/&lt;/code&gt; for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architecture, module structure&lt;/td&gt;
&lt;td&gt;Hard prohibitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service ownership decisions&lt;/td&gt;
&lt;td&gt;Patterns Claude must never emit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conventions, command reference&lt;/td&gt;
&lt;td&gt;Security / performance invariants&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Rule: Prevent N+1 Queries
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; N+1 queries are easy to introduce and slip through review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; a prohibition rule with a correct bulk-query pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; Claude writes the bulk query at generation time — the bug is never created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/database-queries.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong — N queries&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;bookings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Correct — one query&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;In&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="nx"&gt;bookings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Rule: Permission Checks
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/permissions.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Correct&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Permissions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;PermissionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MANAGE_BOOKINGS&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UseGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JwtAuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermissionsGuard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; role names get merged, split, and renamed; checks against them break&lt;br&gt;
silently. &lt;code&gt;PermissionCodes&lt;/code&gt; are stable constants that survive role&lt;br&gt;
restructuring. Import from &lt;code&gt;src/common/constants/permissions.constant.ts&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Rule: Import Style
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;.claude/rules/imports.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Wrong&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../services/user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Correct&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/modules/user/services/user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src/&lt;/code&gt; alias is configured in &lt;code&gt;tsconfig.json&lt;/code&gt; (&lt;code&gt;baseUrl: "./"&lt;/code&gt;) and Jest's&lt;br&gt;
&lt;code&gt;moduleNameMapper&lt;/code&gt;. Use it everywhere.&lt;/p&gt;
&lt;h4&gt;
  
  
  Other Rules Worth Defining
&lt;/h4&gt;

&lt;p&gt;The same prohibition pattern applies to many recurring NestJS pitfalls. A few more rules worth their own file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt; — always throw from &lt;code&gt;ErrorMessages&lt;/code&gt;/&lt;code&gt;ResponseCodeKeys&lt;/code&gt; constants and use NestJS exceptions; never hardcode strings or return raw error objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt; — use the structured &lt;code&gt;logMessage()&lt;/code&gt; helper at the right level; never &lt;code&gt;console.log&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions&lt;/strong&gt; — multi-write operations must run in a single &lt;code&gt;EntityManager&lt;/code&gt; transaction; never fire independent writes that can half-commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DTO validation&lt;/strong&gt; — every request DTO needs &lt;code&gt;class-validator&lt;/code&gt; decorators; the &lt;code&gt;ValidationPipe&lt;/code&gt; whitelist drops anything undecorated, so missing decorators silently lose data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity ↔ migration parity&lt;/strong&gt; — any entity change needs a matching Flyway migration; &lt;code&gt;synchronize&lt;/code&gt; stays &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger coverage&lt;/strong&gt; — every endpoint carries &lt;code&gt;@ApiSpec&lt;/code&gt; + a typed response DTO so the generated docs stay accurate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 4 — Build Skills
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Skills are project-specific slash commands that bundle a workflow, code templates, and references — they turn a repeated multi-file task into one command.&lt;/strong&gt; Write one for any repeated, multi-step task: building an endpoint, writing a migration, scaffolding a module, reviewing a PR.&lt;/p&gt;
&lt;h4&gt;
  
  
  Skill Structure
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/skills/api-development/
├── SKILL.md                    # Workflow, trigger, steps
├── assets/
│   ├── controller-template.md
│   ├── service-template.md
│   ├── repository-template.md
│   └── dto-template.md
└── references/
    ├── nestjs-conventions.md
    └── swagger-documentation.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Writing SKILL.md
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# API Development Skill&lt;/span&gt;

&lt;span class="gu"&gt;## Trigger&lt;/span&gt;

Invoke with &lt;span class="sb"&gt;`/api-development`&lt;/span&gt; when building or modifying a NestJS endpoint.

&lt;span class="gu"&gt;## Workflow&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Determine service &amp;amp; module**&lt;/span&gt; — check CLAUDE.md routing; ask if ambiguous.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Read what exists**&lt;/span&gt; — entities, repositories, DTOs already in the module.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the DTO first**&lt;/span&gt; — it defines the contract. class-validator
   decorators; extend &lt;span class="sb"&gt;`PaginationRequestDTO`&lt;/span&gt; for lists.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the repository**&lt;/span&gt; — inject &lt;span class="sb"&gt;`DataSource`&lt;/span&gt;; accept an optional
   &lt;span class="sb"&gt;`EntityManager`&lt;/span&gt; for transactions; queries only, no logic.
&lt;span class="p"&gt;5.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the service**&lt;/span&gt; — inject the repository interface token; use
   &lt;span class="sb"&gt;`ErrorMessages`&lt;/span&gt; constants; throw &lt;span class="sb"&gt;`NotFoundException`&lt;/span&gt; etc.
&lt;span class="p"&gt;6.&lt;/span&gt; &lt;span class="gs"&gt;**Generate the controller**&lt;/span&gt; — &lt;span class="sb"&gt;`@ApiSpec`&lt;/span&gt; + &lt;span class="sb"&gt;`@ApiOkResponse`&lt;/span&gt;; return
   &lt;span class="sb"&gt;`{ data, meta }`&lt;/span&gt;; no business logic.
&lt;span class="p"&gt;7.&lt;/span&gt; &lt;span class="gs"&gt;**Wire the module**&lt;/span&gt; — add to &lt;span class="sb"&gt;`providers`&lt;/span&gt;, export by interface token.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Asset Template (example)
&lt;/h4&gt;

&lt;p&gt;Templates should be real, compilable code — not pseudocode. &lt;code&gt;assets/controller-template.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bookings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookingController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERVICE_INTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOOKING_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;bookingService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBookingService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UseGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JwtAuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermissionsGuard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Permissions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;PermissionCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE_BOOKING&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Create a new booking&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ApiCreatedResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateBookingSuccessDto&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createBooking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateBookingDto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Req&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BookingEntity&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bookingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBooking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;booking&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this skill, a complete endpoint (controller + service + repository + DTOs, wired into the module) takes &lt;strong&gt;under 3 minutes instead of ~20&lt;/strong&gt; — and matches your conventions on the first try.&lt;/p&gt;

&lt;h4&gt;
  
  
  Other Skills Worth Building
&lt;/h4&gt;

&lt;p&gt;Any repeated, multi-step workflow with team-specific conventions is a skill candidate. Beyond endpoint scaffolding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Migration generator&lt;/strong&gt; — scaffold a Flyway migration in the right schema folder with your versioning and naming convention, plus the matching entity change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module scaffolder&lt;/strong&gt; — generate a full module skeleton (module file, three layers, DI tokens) wired and ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR review&lt;/strong&gt; — review a diff against your conventions: N+1 checks, permission usage, layer boundaries, missing tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test generator&lt;/strong&gt; — produce &lt;code&gt;*.spec.ts&lt;/code&gt; files following your mocking and fixture patterns for a given service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-service adapter&lt;/strong&gt; — generate a new IMS adapter method plus its response interface and transform helper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use-case / BDD docs&lt;/strong&gt; — turn a requirement into user stories with Given/When/Then acceptance criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5 — Configure Settings &amp;amp; Permissions
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt; controls which Bash commands run without a permission prompt. Allow read-only and safe test/lint operations freely; deny anything destructive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run lint:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run test:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run build)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npx jest *)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(rm -rf *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push *)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(git reset --hard *)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;th&gt;Committed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Everyone on the team&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/settings.local.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You only (overrides)&lt;/td&gt;
&lt;td&gt;No (gitignored)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Best Practice callout:&lt;/strong&gt; Treat &lt;code&gt;.claude/&lt;/code&gt; as production code. It ships your conventions to every engineer and every AI session — review it, version it, and prune it like any other source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep CLAUDE.md under ~300 lines.&lt;/strong&gt; Context has a cost; a bloated file crowds out the code Claude needs to read. If it's derivable from the code, cut it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write rules as prohibitions, not guidance.&lt;/strong&gt; "NEVER call the DB in a loop" is enforced; "prefer bulk queries" is ignored under pressure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put templates in skills, not CLAUDE.md&lt;/strong&gt; — they should load only when the skill is invoked, not on every session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version &lt;code&gt;.claude/&lt;/code&gt; in git.&lt;/strong&gt; It's part of your codebase: same review, same history. New rules get PRs; stale rules get deleted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use decision tables liberally.&lt;/strong&gt; Anywhere two reasonable choices exist — DTO placement, entity location, service boundaries — a table beats prose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recommended &lt;code&gt;.claude/&lt;/code&gt; layout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
├── CLAUDE.md                  # Root guide (&amp;lt;300 lines)
├── settings.json              # Team permissions (committed)
├── rules/
│   ├── database-queries.md    # No N+1
│   ├── permissions.md         # PermissionCodes, no role checks
│   └── imports.md             # src/ alias only
└── skills/
    └── api-development/
        ├── SKILL.md
        ├── assets/            # controller/service/repository/dto templates
        └── references/        # conventions, swagger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Each of these silently degrades output quality — Claude will &lt;em&gt;look&lt;/em&gt; like it's working while quietly violating your conventions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Writing CLAUDE.md as a tutorial.&lt;/strong&gt; Don't explain what NestJS is — Claude knows. Document only what's unique to your project: module names, error constants, response shape, permission system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omitting negative rules.&lt;/strong&gt; Telling Claude what &lt;em&gt;not&lt;/em&gt; to do prevents whole classes of mistakes. The expensive errors are the ones that look correct but violate your patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cramming everything into the root CLAUDE.md.&lt;/strong&gt; It loads in every session. Split service-specific depth into per-service files so it doesn't pollute context when you're elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No routing decision table.&lt;/strong&gt; Wrong-service placement comes from ambiguity, not ignorance. A table makes the decision deterministic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the cross-service adapter pattern.&lt;/strong&gt; In an HTTP-linked monorepo, Claude will try to import across services or query the other DB. Spell out that all cross-service calls go through adapters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not mentioning &lt;code&gt;synchronize: false&lt;/code&gt;.&lt;/strong&gt; Claude assumes TypeORM manages the schema. If you use Flyway, entity changes without a matching migration fail silently — say so explicitly.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Real-World Example: Adding a Consumer-Visible Booking Status
&lt;/h2&gt;

&lt;p&gt;A walkthrough of how a configured setup changes one real task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The request:&lt;/strong&gt; &lt;em&gt;"Add a consumer-visible status to a booking package."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without configuration&lt;/strong&gt;, Claude reasons: "packages live in &lt;code&gt;operator-service&lt;/code&gt;," and edits the package entity there — the wrong service. It hardcodes the status string, and adds an &lt;code&gt;if (user.roles.includes('admin'))&lt;/code&gt; guard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With configuration&lt;/strong&gt;, here's the chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Routing table&lt;/strong&gt; in &lt;code&gt;CLAUDE.md&lt;/code&gt; tells Claude that &lt;em&gt;consumer-visible&lt;/em&gt; status describes a consumer interaction → it belongs in &lt;code&gt;api-service&lt;/code&gt;, not &lt;code&gt;operator-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-service rule&lt;/strong&gt; reminds it the operator's package definition is read via an IMS adapter, so it adds the field to the adapter's transform — not by reaching into the other DB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/api-development&lt;/code&gt; skill&lt;/strong&gt; scaffolds the DTO, repository method, service logic, and controller in the right order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission rule&lt;/strong&gt; makes it emit &lt;code&gt;@Permissions([PermissionCodes.VIEW_BOOKING_STATUS])&lt;/code&gt; instead of a role check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error rule&lt;/strong&gt; makes it throw &lt;code&gt;NotFoundException&lt;/code&gt; with an &lt;code&gt;ErrorMessages&lt;/code&gt; constant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One ambiguous sentence, resolved into correct, convention-matching code across four files — without a single clarifying question.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results &amp;amp; Metrics
&lt;/h2&gt;

&lt;p&gt;A few hours of one-time setup changes the day-to-day in measurable ways:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review every generated file for hardcoded strings, wrong imports, role checks&lt;/td&gt;
&lt;td&gt;Rules make those impossible — review focuses on logic, not conventions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New endpoint ≈ 20 min wiring four layers by hand&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/api-development&lt;/code&gt; scaffolds + wires it in under 3 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files landed in the wrong service, caught late in review&lt;/td&gt;
&lt;td&gt;Routing table places them correctly on the first pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N+1 queries and &lt;code&gt;console.log&lt;/code&gt; slipped into PRs&lt;/td&gt;
&lt;td&gt;Caught at generation time, never written&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New hires guessed at module boundaries and patterns&lt;/td&gt;
&lt;td&gt;CLAUDE.md teaches the conventions implicitly on day one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compounding wins that don't show up in a single PR:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency.&lt;/strong&gt; Code generated months apart looks the same, because it comes from the same templates and rules — not from whatever Claude inferred that day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less review fatigue.&lt;/strong&gt; Reviewers stop flagging the same convention violations and spend attention on actual design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster onboarding.&lt;/strong&gt; Routing tables and rules are documentation that also executes — a new engineer's first AI-assisted feature already follows house style.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower context cost.&lt;/strong&gt; A tight CLAUDE.md plus on-demand skills means Claude spends its context budget reading &lt;em&gt;your&lt;/em&gt; code, not re-deriving conventions every session.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extractable insight:&lt;/strong&gt; The investment pays for itself within the first few features and keeps paying on every one after — because the cost is one-time and the benefit recurs on every task.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is CLAUDE.md?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; is a Markdown file Claude Code reads automatically at the start of every session. It briefs the AI on your project's architecture, conventions, and prohibitions — the equivalent of onboarding docs for a new engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should CLAUDE.md go in a monorepo?&lt;/strong&gt;&lt;br&gt;
Put a root &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt; at the git root for cross-cutting concerns (service ownership, shared conventions), and a &lt;code&gt;CLAUDE.md&lt;/code&gt; inside each service for service-specific patterns. Claude reads the root first, then the service-level file when you work in that directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between CLAUDE.md and rules?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; describes architecture and conventions; rules (in &lt;code&gt;.claude/rules/&lt;/code&gt;) are hard prohibitions Claude must never violate. Use &lt;code&gt;CLAUDE.md&lt;/code&gt; for "here's how things work" and rules for "never do this," such as banning N+1 queries or role-name checks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do Claude Code skills work?&lt;/strong&gt;&lt;br&gt;
A skill is a project-specific slash command (e.g. &lt;code&gt;/api-development&lt;/code&gt;) backed by a &lt;code&gt;SKILL.md&lt;/code&gt; workflow plus code templates and references. Invoking it makes Claude follow a deterministic, multi-step process — like scaffolding a full NestJS endpoint across four files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long should CLAUDE.md be?&lt;/strong&gt;&lt;br&gt;
Aim for under ~300 lines. Context is finite, and a bloated file crowds out the actual code Claude needs to read. Document only what isn't derivable from the codebase itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Claude Code work with a NestJS monorepo of multiple services?&lt;/strong&gt;&lt;br&gt;
Yes. Claude reads &lt;code&gt;.claude/&lt;/code&gt; from the git root, so one configuration governs every service. A routing decision table in &lt;code&gt;CLAUDE.md&lt;/code&gt; tells Claude which service owns which kind of data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I stop Claude from writing N+1 queries or role-based permission checks?&lt;/strong&gt;&lt;br&gt;
Add prohibition rules in &lt;code&gt;.claude/rules/&lt;/code&gt;. A &lt;code&gt;database-queries.md&lt;/code&gt; rule bans DB calls inside loops; a &lt;code&gt;permissions.md&lt;/code&gt; rule bans &lt;code&gt;user.role&lt;/code&gt; checks in favor of &lt;code&gt;PermissionCodes&lt;/code&gt; and &lt;code&gt;@Permissions()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I commit the .claude directory to git?&lt;/strong&gt;&lt;br&gt;
Yes — commit &lt;code&gt;.claude/CLAUDE.md&lt;/code&gt;, &lt;code&gt;rules/&lt;/code&gt;, &lt;code&gt;skills/&lt;/code&gt;, and &lt;code&gt;settings.json&lt;/code&gt; so the whole team shares the same configuration. Keep personal overrides in &lt;code&gt;.claude/settings.local.json&lt;/code&gt;, which is gitignored.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways (Recap)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claude struggles in large NestJS monorepos because &lt;strong&gt;correctness depends on conventions invisible in any single file&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Externalize that knowledge with &lt;strong&gt;CLAUDE.md (briefing), rules (prohibitions), and skills (workflows)&lt;/strong&gt; — all committed to git.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;service-routing decision table&lt;/strong&gt; is the highest-leverage thing you can write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules phrased as prohibitions&lt;/strong&gt; are enforced; preferences are not.&lt;/li&gt;
&lt;li&gt;Setup is &lt;strong&gt;a few hours, one-time&lt;/strong&gt;, and compounds across every feature and every new hire.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Setting up Claude Code for a NestJS monorepo isn't about making Claude smarter — it's about eliminating guesswork. A codebase with dozens of modules, hundreds of DTOs, and custom guards and adapters is genuinely ambiguous without context, and Claude's reasonable defaults won't match your conventions.&lt;/p&gt;

&lt;p&gt;The investment is small and one-time: a focused &lt;code&gt;CLAUDE.md&lt;/code&gt; for routing and prohibitions, a few rules files for hard constraints, and one or two skills for your most repeated tasks. After that, Claude generates code that looks like your team wrote it — not like someone who just read the NestJS docs.&lt;/p&gt;




&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.claude.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code documentation&lt;/a&gt; — official setup, configuration, and best-practices reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.nestjs.com" rel="noopener noreferrer"&gt;NestJS documentation&lt;/a&gt; — providers, guards, interceptors, and module architecture&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://typeorm.io" rel="noopener noreferrer"&gt;TypeORM&lt;/a&gt; · &lt;a href="https://github.com/typestack/class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; · &lt;a href="https://documentation.red-gate.com/flyway" rel="noopener noreferrer"&gt;Flyway&lt;/a&gt; — the data, validation, and migration tooling referenced above&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Patterns here are drawn from a production NestJS monorepo running four services: a consumer API, an operator management system, a real-time chat service, and a scheduled job runner. The approach scales to any NestJS project with conventions worth preserving.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>monorepo</category>
    </item>
  </channel>
</rss>
