<?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: NongdyZ</title>
    <description>The latest articles on DEV Community by NongdyZ (@nongdyz_d9c3069b1acb2a08c).</description>
    <link>https://dev.to/nongdyz_d9c3069b1acb2a08c</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%2F4005348%2F445dafed-1b33-4340-8386-43a33db1c0fe.jpg</url>
      <title>DEV Community: NongdyZ</title>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nongdyz_d9c3069b1acb2a08c"/>
    <language>en</language>
    <item>
      <title>The SaaS Metrics Every Founder Should Track (MRR, CAC, LTV, Runway)</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Sun, 12 Jul 2026 01:10:28 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/the-saas-metrics-every-founder-should-track-mrr-cac-ltv-runway-3f61</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/the-saas-metrics-every-founder-should-track-mrr-cac-ltv-runway-3f61</guid>
      <description>&lt;p&gt;Most early SaaS dashboards I see track the wrong things. Page views. Signups. Total revenue this quarter. Those numbers feel good and tell you almost nothing about whether the business is actually healthy.&lt;/p&gt;

&lt;p&gt;The metrics that matter are the ones that answer four questions: &lt;em&gt;Is recurring revenue growing? Can I afford to acquire customers? Are those customers worth more than they cost? How long until I run out of money?&lt;/em&gt; That's MRR, CAC, LTV, and runway. Get these four right and you can make almost every early-stage decision with confidence.&lt;/p&gt;

&lt;p&gt;Here's how to calculate each one correctly — including the mistakes that quietly inflate them — with the actual formulas.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. MRR — and the four movements inside it
&lt;/h2&gt;

&lt;p&gt;MRR (Monthly Recurring Revenue) is the predictable revenue you can expect every month. The number itself is easy. What founders miss is that a flat MRR can hide a business that's bleeding.&lt;/p&gt;

&lt;p&gt;Normalize everything to monthly first. An annual plan at $1,200 is &lt;strong&gt;$100 MRR&lt;/strong&gt;, not $1,200 — never book the full annual amount as one month's MRR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MRR = sum of each customer's monthly subscription value

Annual plan? MRR = annual price / 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then break the &lt;em&gt;change&lt;/em&gt; in MRR into four movements — this is the part that reveals the truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Net New MRR = New + Expansion + Reactivation − Contraction − Churned

  New           = MRR from brand-new customers
  Expansion     = upgrades / seats added by existing customers
  Reactivation  = previously-churned customers who came back
  Contraction   = downgrades by existing customers
  Churned       = MRR lost from customers who cancelled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two companies can both show "+$5k MRR this month." One did it with $5k of new sales and zero churn. The other added $15k of new sales while losing $10k to churn — a leaky bucket that will stall the moment sales slows. Only the breakdown tells them apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Churn — the metric that caps your growth
&lt;/h2&gt;

&lt;p&gt;Churn is the single most important early signal. High churn means you're filling a bucket with a hole; no amount of marketing fixes it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer churn rate = customers lost in period / customers at start of period

Revenue churn rate  = MRR lost (churn + contraction) in period / MRR at start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Track &lt;strong&gt;revenue churn&lt;/strong&gt; alongside customer churn. If you lose small accounts but keep big ones, revenue churn looks great even when logo churn is ugly — and vice versa. When expansion revenue exceeds churned revenue, you have &lt;strong&gt;negative net revenue churn&lt;/strong&gt;: the holy grail, where your existing customer base grows even if you add zero new customers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Net Revenue Retention (NRR) = (starting MRR + expansion − contraction − churn) / starting MRR

NRR &amp;gt; 100% means the existing base is growing on its own.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. CAC — what a customer actually costs
&lt;/h2&gt;

&lt;p&gt;CAC (Customer Acquisition Cost) is the fully-loaded cost to win one customer. The common mistake is counting only ad spend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CAC = (total sales + marketing spend in period) / new customers acquired in period
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Fully-loaded" means everything: ad spend, salaries of sales and marketing people, tooling, agency fees, content costs. If you only count the ad bill, your CAC looks half what it really is, and you'll overspend into a loss.&lt;/p&gt;

&lt;p&gt;A useful companion is &lt;strong&gt;CAC payback period&lt;/strong&gt; — how many months of gross margin it takes to earn back the cost of acquiring a customer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CAC Payback (months) = CAC / (ARPA × gross margin %)

ARPA = average revenue per account per month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under ~12 months is healthy for most B2B SaaS; under 6 is excellent. Long payback means your growth is financed by cash you don't get back for a year — dangerous when runway is short.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. LTV and the ratio that decides if you have a business
&lt;/h2&gt;

&lt;p&gt;LTV (Lifetime Value) is the total gross profit you expect from a customer before they churn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Average customer lifetime (months) = 1 / monthly customer churn rate

LTV = ARPA × gross margin % × average customer lifetime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always multiply by &lt;strong&gt;gross margin&lt;/strong&gt;. Revenue isn't value — if it costs you 40 cents in hosting and support to deliver a dollar, only 60 cents is real. Skipping margin is the most common way founders fool themselves with a beautiful LTV.&lt;/p&gt;

&lt;p&gt;Now the ratio that ties CAC and LTV together — the one a serious investor checks first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LTV : CAC ratio = LTV / CAC

&amp;lt; 1   : you lose money on every customer. Stop and fix the model.
~ 3:1 : healthy. The standard target for sustainable SaaS.
&amp;gt; 5:1 : often means you're UNDER-investing in growth — spend more.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 3:1 ratio means each customer returns three dollars of lifetime gross profit for every dollar spent acquiring them. Below 1:1, scaling just loses money faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Runway — how long the clock runs
&lt;/h2&gt;

&lt;p&gt;Everything above is academic if you run out of cash. Runway is the number of months until you hit zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Net burn = monthly cash out − monthly cash in
Runway (months) = current cash balance / net burn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're burning $40k a month with $480k in the bank, that's &lt;strong&gt;12 months&lt;/strong&gt; of runway. Watch the trend, not just the snapshot: rising MRR shrinks net burn and extends runway every month — that's the whole game pre-profitability. Once cash in exceeds cash out, net burn goes negative and runway is effectively infinite. That's the finish line.&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked example
&lt;/h2&gt;

&lt;p&gt;Say you're at: 200 customers, $50 ARPA, 80% gross margin, 4% monthly customer churn, $600 CAC, $300k cash, $30k net burn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MRR              = 200 × $50            = $10,000
Avg lifetime     = 1 / 0.04             = 25 months
LTV              = $50 × 0.80 × 25      = $1,000
LTV : CAC        = $1,000 / $600        = 1.67  → below target, fix churn or CAC
CAC payback      = $600 / ($50 × 0.80)  = 15 months → a bit long
Runway           = $300,000 / $30,000   = 10 months
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The story those five numbers tell: revenue is real but churn is high (4%/month is steep), which drags LTV down so the unit economics are thin (1.67:1), and you have 10 months to fix it. That's a far more useful picture than "MRR is $10k and growing." The priority is obvious — attack churn first, because it improves LTV, the ratio, and payback all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put it in a model, not a memory
&lt;/h2&gt;

&lt;p&gt;The mistake isn't not knowing these formulas — it's not having them wired into one live model where changing churn instantly updates LTV, the ratio, payback, and runway. When they're connected, you can ask "what if I cut churn to 2%?" and watch every downstream number move. That's when metrics become a decision tool instead of a report card.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want it pre-built
&lt;/h2&gt;

&lt;p&gt;Wiring a clean, investor-ready model with all of these linked — MRR movements, cohort churn, LTV:CAC, payback, and a runway forecast that updates as you change assumptions — is a weekend of spreadsheet work if you start from scratch. I built one so you don't have to: the &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/jxravw?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=saas-metrics-founders-track" rel="noopener noreferrer"&gt;SaaS Metrics &amp;amp; Financial Model&lt;/a&gt;&lt;/strong&gt; is a ready-to-use spreadsheet with every formula in this post connected, scenario toggles, and a START HERE guide that walks you through plugging in your own numbers in about ten minutes.&lt;/p&gt;

&lt;p&gt;But you don't need it to start — the formulas above are the whole framework. Calculate your LTV:CAC and runway today; those two numbers alone will sharpen your next decision.&lt;/p&gt;

&lt;p&gt;Which of these five do you actually track today, and which one have you been avoiding? Be honest in the comments — I suspect churn is the one most of us look away from.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>founders</category>
      <category>business</category>
    </item>
    <item>
      <title>Multi-Agent Code Review with Claude Code Subagents</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Thu, 09 Jul 2026 13:00:03 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/multi-agent-code-review-with-claude-code-subagents-gn8</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/multi-agent-code-review-with-claude-code-subagents-gn8</guid>
      <description>&lt;p&gt;A single AI reviewing your code is like asking one person to be your security auditor, your test engineer, and your style nitpicker at the same time. They'll do all three jobs at 60%. You get a review that mentions a missing semicolon and misses the SQL injection.&lt;/p&gt;

&lt;p&gt;Claude Code's &lt;strong&gt;subagents&lt;/strong&gt; fix this by splitting one generalist into a panel of specialists, each with its own focused instructions and — importantly — its own context window. One agent thinks only about security. Another thinks only about test coverage. A third synthesizes their findings into a verdict. The result reviews more like a real team than a single chatbot.&lt;/p&gt;

&lt;p&gt;Here's a multi-agent code review workflow you can build today, with the actual subagent files.&lt;/p&gt;

&lt;h2&gt;
  
  
  How subagents work in Claude Code
&lt;/h2&gt;

&lt;p&gt;A subagent is just a Markdown file in &lt;code&gt;.claude/agents/&lt;/code&gt; with frontmatter and a system prompt. The frontmatter declares its name, when to use it, and which tools it's allowed. Claude Code can invoke them by name or delegate to them automatically based on the &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The magic is the &lt;strong&gt;separate context window&lt;/strong&gt;. The security agent isn't distracted by the test agent's reasoning. Each one stays sharp on its single job, and you can run them in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent 1: The reviewer (correctness)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-reviewer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bugs,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;correctness,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;convention&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;violations.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;after&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;writing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code."&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Bash&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are a senior code reviewer. Review ONLY the changed lines plus immediate context.

Output exactly three sections:
&lt;span class="p"&gt;1.&lt;/span&gt; Blocking — bugs, data-loss risks, broken logic. Each with file:line and a concrete fix.
&lt;span class="p"&gt;2.&lt;/span&gt; Should fix — correctness/clarity issues that aren't blocking.
&lt;span class="p"&gt;3.&lt;/span&gt; Nits — naming/style. Keep short.

Rules:
&lt;span class="p"&gt;-&lt;/span&gt; If there are no blocking issues, say so on line one. Do not invent problems to look thorough.
&lt;span class="p"&gt;-&lt;/span&gt; Check: unhandled null, off-by-one, error paths, N+1 queries, wrong async/await, edge cases.
&lt;span class="p"&gt;-&lt;/span&gt; Quote the exact line you flag. No vague "consider improving error handling".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agent 2: The security auditor
&lt;/h2&gt;

&lt;p&gt;This one thinks in vulnerability categories, not vibes. Giving it OWASP as a checklist is what stops it from rubber-stamping.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security-auditor&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Audits changed code for security vulnerabilities. Use on any diff touching input handling, auth, queries, or file/network IO.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Bash&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are an application security auditor. Review ONLY the diff and its immediate context.

Walk these categories explicitly and report findings per category:
&lt;span class="p"&gt;-&lt;/span&gt; Injection (SQL, command, template, NoSQL)
&lt;span class="p"&gt;-&lt;/span&gt; AuthN/AuthZ (missing checks, broken object-level access, privilege escalation)
&lt;span class="p"&gt;-&lt;/span&gt; Input validation &amp;amp; output encoding (XSS, SSRF, path traversal)
&lt;span class="p"&gt;-&lt;/span&gt; Secrets &amp;amp; data exposure (hardcoded keys, logging PII/tokens)
&lt;span class="p"&gt;-&lt;/span&gt; Unsafe deserialization, insecure defaults, missing rate limits

For each finding: severity (Critical/High/Medium/Low), file:line, the exploit in one sentence, and the fix.
If a category is clean, write "OK" — do not pad. Do not flag theoretical issues the code can't actually hit.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agent 3: The test engineer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-reviewer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Evaluates whether a change is adequately tested and writes the missing tests. Use after code-reviewer.&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Bash, Write&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

You are a test engineer. Given a diff, assess test coverage of the &lt;span class="ge"&gt;*behavior that changed*&lt;/span&gt;.

Output:
&lt;span class="p"&gt;1.&lt;/span&gt; Coverage gaps — for each changed behavior, list the cases NOT tested: edge values, null/empty,
   error path, boundary, concurrency. Be specific to this code.
&lt;span class="p"&gt;2.&lt;/span&gt; Missing tests — write the actual test code for the highest-value gaps, matching the repo's existing test style.

Rules:
&lt;span class="p"&gt;-&lt;/span&gt; Don't praise existing happy-path tests. Find what's missing.
&lt;span class="p"&gt;-&lt;/span&gt; Test the public contract, not private internals, so refactors don't break the tests.
&lt;span class="p"&gt;-&lt;/span&gt; If coverage is genuinely sufficient, say so — don't manufacture busywork tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The orchestration: a &lt;code&gt;/review&lt;/code&gt; command
&lt;/h2&gt;

&lt;p&gt;Tie them together with a slash command in &lt;code&gt;.claude/commands/review.md&lt;/code&gt; so one keystroke runs the whole panel:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run the full multi-agent review on the current diff&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

Run a complete review of the staged/unstaged changes:
&lt;span class="p"&gt;
1.&lt;/span&gt; Get the diff with &lt;span class="sb"&gt;`git diff HEAD`&lt;/span&gt;.
&lt;span class="p"&gt;2.&lt;/span&gt; Invoke @code-reviewer on the diff.
&lt;span class="p"&gt;3.&lt;/span&gt; Invoke @security-auditor on the diff.
&lt;span class="p"&gt;4.&lt;/span&gt; Invoke @test-reviewer on the diff.
&lt;span class="p"&gt;5.&lt;/span&gt; Synthesize all three into a single verdict:
&lt;span class="p"&gt;   -&lt;/span&gt; VERDICT: SHIP / FIX FIRST / NEEDS DISCUSSION
&lt;span class="p"&gt;   -&lt;/span&gt; Blocking items (from any agent), deduplicated, sorted by severity.
&lt;span class="p"&gt;   -&lt;/span&gt; A short ordered to-do list to get to SHIP.

Keep the synthesis tight. Don't repeat every agent's full output — surface what blocks the merge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run &lt;code&gt;/review&lt;/code&gt;, Claude Code dispatches the three specialists, collects their reports, and the orchestrator boils it down to a decision. You read one verdict instead of three walls of text.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;On a recent endpoint change, the three agents split the work cleanly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;code-reviewer&lt;/strong&gt; caught an unhandled &lt;code&gt;null&lt;/code&gt; when the user had no orders — a 500 waiting to happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;security-auditor&lt;/strong&gt; flagged that the &lt;code&gt;userId&lt;/code&gt; came from the query string with no authorization check: any logged-in user could read anyone's orders (broken object-level access — the #1 item on the OWASP API Top 10).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;test-reviewer&lt;/strong&gt; noticed there was no test for the empty-orders case &lt;em&gt;or&lt;/em&gt; the unauthorized case, and wrote both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single generalist agent, in my experience, finds the null and stops — it feels "done" after one solid catch. The panel keeps going because each specialist is measured against its own job, not the overall vibe of "did I find something."&lt;/p&gt;

&lt;h2&gt;
  
  
  Build it incrementally
&lt;/h2&gt;

&lt;p&gt;You don't need all three on day one. Start with &lt;code&gt;code-reviewer&lt;/code&gt; plus the &lt;code&gt;/review&lt;/code&gt; command that calls just that one. Add &lt;code&gt;security-auditor&lt;/code&gt; the first time a security bug slips through. Add &lt;code&gt;test-reviewer&lt;/code&gt; when you notice untested changes shipping. Each agent is one small file — the cost of adding one is minutes, and a bad agent is just a file you delete.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want the whole panel pre-built
&lt;/h2&gt;

&lt;p&gt;Tuning the output formats so the agents are actionable instead of fluffy is the real time sink — getting "quote the exact line" and "don't invent problems" dialed in took me weeks. If you'd rather drop a finished setup into any repo, I packaged my full configuration as &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/womhu?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=multi-agent-code-review-claude-code" rel="noopener noreferrer"&gt;Claude Code Agent OS&lt;/a&gt;&lt;/strong&gt;: 26 specialized subagents (reviewer, security, tests, refactor, and more), 12 slash commands including &lt;code&gt;/review&lt;/code&gt; and &lt;code&gt;/ship&lt;/code&gt;, ready-to-edit &lt;code&gt;CLAUDE.md&lt;/code&gt; templates, MCP configs, and safety hooks — with a START HERE quickstart that has you running in about five minutes.&lt;/p&gt;

&lt;p&gt;But the three agents above are enough to feel the difference right now. Copy &lt;code&gt;code-reviewer&lt;/code&gt; and the &lt;code&gt;/review&lt;/code&gt; command into your repo and run it on your next diff.&lt;/p&gt;

&lt;p&gt;If you build your own review panel, which specialist earns its keep the most for you? I'd like to know in the comments.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AI Debugging Prompts That Actually Find the Bug</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Mon, 06 Jul 2026 13:00:03 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/ai-debugging-prompts-that-actually-find-the-bug-44o</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/ai-debugging-prompts-that-actually-find-the-bug-44o</guid>
      <description>&lt;p&gt;The default way most people debug with AI is to paste a stack trace and type "fix this." Sometimes it works. More often the model invents a plausible-sounding cause, "fixes" it, and the bug is still there — now hidden under a layer of confident wrong code.&lt;/p&gt;

&lt;p&gt;The problem is the same one that ruins human debugging: jumping to a fix before understanding the cause. A good debugging prompt forces the model to do what a senior engineer does — &lt;strong&gt;reproduce, isolate, form a hypothesis, then test it&lt;/strong&gt; — instead of pattern-matching the error string to the nearest Stack Overflow answer.&lt;/p&gt;

&lt;p&gt;Here are the prompts I actually use, organized by the kind of bug. They work in Cursor, Claude, ChatGPT, or any assistant. Copy them, paste your context, and notice how the output stops being a guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "fix this" fails
&lt;/h2&gt;

&lt;p&gt;"Fix this" gives the model no role, no method, and no constraint against guessing. So it does the easy thing: it finds the most common cause of that error message and assumes that's yours. For generic errors (&lt;code&gt;undefined is not a function&lt;/code&gt;, &lt;code&gt;connection refused&lt;/code&gt;) the most common cause is rarely &lt;em&gt;your&lt;/em&gt; cause.&lt;/p&gt;

&lt;p&gt;The fix is to make the model show its reasoning &lt;em&gt;before&lt;/em&gt; it writes a single line of code — and to forbid it from changing anything until you've agreed on the cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 1: Root-cause analysis (no fix yet)
&lt;/h2&gt;

&lt;p&gt;This is my default. The key constraint is the last line — it stops the model from skipping to a patch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior engineer debugging a problem. Do NOT write a fix yet.

Here is the symptom: &amp;lt;what you observe&amp;gt;
Here is the error / log: &amp;lt;paste&amp;gt;
Here is the relevant code: &amp;lt;paste&amp;gt;
What I've already ruled out: &amp;lt;list, or "nothing yet"&amp;gt;

Work through this in order:
1. State exactly what the symptom tells us — and what it does NOT tell us.
2. List the 3-4 most likely causes, ranked by probability for THIS code (not in general).
3. For each cause, give the single cheapest check that would confirm or eliminate it.
4. Tell me which check to run first and what result would point where.

Do not propose a code change until I report back what the checks showed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You run the checks, paste the results, and &lt;em&gt;then&lt;/em&gt; it fixes — now with evidence instead of a guess. This one prompt has saved me from more wrong "fixes" than anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 2: Regression hunt ("it worked yesterday")
&lt;/h2&gt;

&lt;p&gt;When something broke and you have version control, the bug is almost always &lt;em&gt;in the diff&lt;/em&gt;. Point the model at the change, not the whole file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This worked before and now it doesn't. The behavior change is: &amp;lt;before vs after&amp;gt;.

Here is the diff of recent changes: &amp;lt;paste git diff, or the commit range&amp;gt;
Here is the failing case: &amp;lt;input → expected → actual&amp;gt;

Analyze the diff specifically:
1. Which changed lines could plausibly cause this exact symptom? Quote them.
2. For the top suspect, trace how the new code produces the wrong result, step by step with the failing input.
3. Confirm it's the cause before fixing: what value would I see at &amp;lt;line&amp;gt; if you're right?

Ignore unchanged code unless the diff broke an assumption it relied on.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last line matters. Without it, the model wanders off into unrelated parts of the file. A regression lives in what changed — anchor it there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 3: Race conditions and intermittent failures
&lt;/h2&gt;

&lt;p&gt;Intermittent bugs are where AI guessing is most dangerous, because the "fix" appears to work (the bug just didn't happen to fire). Force the model to reason about &lt;em&gt;interleaving and ordering&lt;/em&gt;, not just the code path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This bug is intermittent — it fails maybe 1 in 20 runs. Assume it's a timing/ordering issue.

Here is the code: &amp;lt;paste async/concurrent code&amp;gt;
Here is what's shared between the concurrent paths: &amp;lt;state, files, DB rows, caches&amp;gt;

Reason about it as a concurrency problem:
1. Identify every piece of shared mutable state and who reads/writes it.
2. Find an interleaving of operations that produces the bad result. Write it as a numbered timeline (Thread A line X, then Thread B line Y...).
3. Name the category: race, deadlock, lost update, stale read, missing await, or unhandled rejection.
4. Propose a fix that removes the race (lock, atomic op, await, idempotency key) — not one that just makes it rarer.

If you can't construct a failing timeline, say so — don't invent one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "write it as a numbered timeline" instruction is what turns hand-waving into something you can verify. If the timeline is real, the bug is real. If the model can't build one, it admits it instead of fabricating a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 4: The "explain it back to me" sanity check
&lt;/h2&gt;

&lt;p&gt;Before you accept any AI fix, run this. It catches the cases where the model fixed the symptom but misunderstood the cause.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before I apply your fix, explain it back to me:
1. In one sentence, what was the actual root cause?
2. Why did the bug appear only under &amp;lt;the conditions I described&amp;gt; and not always?
3. What does your fix change, and why does that address the cause (not just the symptom)?
4. What input would still break this code after your fix? Is there an edge case left?

If any answer is "I'm not sure," tell me what to check instead of guessing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the model can't cleanly answer #2 — &lt;em&gt;why these conditions and not others&lt;/em&gt; — it didn't understand the bug, and its fix is a coincidence. That single question has caught more bad patches for me than any test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern behind all of these
&lt;/h2&gt;

&lt;p&gt;Every prompt here does the same four things: assigns a &lt;strong&gt;role&lt;/strong&gt;, demands a &lt;strong&gt;method&lt;/strong&gt; (reproduce → hypothesize → verify), forbids &lt;strong&gt;guessing&lt;/strong&gt;, and delays the &lt;strong&gt;fix&lt;/strong&gt; until there's evidence. That's not an AI trick — it's just disciplined debugging, written down so the model can't skip steps.&lt;/p&gt;

&lt;p&gt;You can build these yourself from the templates above. The only real work is keeping a tuned library so you grab the right one instantly instead of rewriting it at 2 a.m. during an incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want the full library ready to go
&lt;/h2&gt;

&lt;p&gt;I keep a much larger set than fits in one post — prompts for root-cause, performance profiling, flaky tests, memory leaks, log analysis, and writing the minimal repro. I cleaned them up and packaged them as the &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/sfgkr?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=ai-prompts-for-debugging" rel="noopener noreferrer"&gt;Developer's AI Prompt Arsenal&lt;/a&gt;&lt;/strong&gt;: 140 copy-paste prompts across debugging, code review, refactoring, testing, and architecture, organized so you find the right one in seconds, with a START HERE guide on how to fill in the variables.&lt;/p&gt;

&lt;p&gt;That said, the four prompts above cost nothing and will change your very next debugging session. Start with Prompt 1 — paste your current bug into it before you let any AI touch the code.&lt;/p&gt;

&lt;p&gt;What's the most stubborn bug an AI prompt ever helped you crack — or the one it kept getting wrong? Tell me in the comments; I'm collecting the patterns.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>debugging</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>10 Cursor Rules Every Developer Should Steal (.mdc)</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Fri, 03 Jul 2026 13:00:03 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/10-cursor-rules-every-developer-should-steal-mdc-3a72</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/10-cursor-rules-every-developer-should-steal-mdc-3a72</guid>
      <description>&lt;p&gt;I used to think AI coding assistants plateaued because the models weren't good enough. Then I watched a teammate's Cursor produce cleaner code than mine on the same task, with the same model. The difference was his &lt;code&gt;.cursor/rules/&lt;/code&gt; folder. His assistant had a contract; mine was improvising.&lt;/p&gt;

&lt;p&gt;A good Cursor rule isn't a motivational poster ("write clean code"). It's a &lt;strong&gt;specific, enforceable check&lt;/strong&gt; scoped to &lt;em&gt;when&lt;/em&gt; it matters. Below are ten rules I've stolen, refined, and now copy into every repo. Steal the ones that fit your stack. Each is a real &lt;code&gt;.mdc&lt;/code&gt; file you can paste into &lt;code&gt;.cursor/rules/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick refresher on &lt;code&gt;.mdc&lt;/code&gt; frontmatter
&lt;/h2&gt;

&lt;p&gt;Cursor's Project Rules live in &lt;code&gt;.cursor/rules/*.mdc&lt;/code&gt;. Three frontmatter fields decide &lt;em&gt;when&lt;/em&gt; a rule loads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alwaysApply: true&lt;/code&gt; — in context on every request. Keep these short and universal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;globs: "**/*.tsx"&lt;/code&gt; — auto-attaches only when a matching file is touched.&lt;/li&gt;
&lt;li&gt;Neither set — Cursor pulls it in when the &lt;code&gt;description&lt;/code&gt; looks relevant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scoping is the whole point. Ten rules loaded on every request dilute the context until the model ignores all of them. Ten &lt;em&gt;scoped&lt;/em&gt; rules stay sharp because only the relevant two or three are ever present at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The non-negotiable global rule
&lt;/h2&gt;

&lt;p&gt;This is the only one I set to &lt;code&gt;alwaysApply: true&lt;/code&gt;. Everything in it is a check the model can apply to a diff, not an aspiration.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Global&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;engineering&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;guardrails&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;—&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apply"&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Validate and type all external input (request bodies, query params, env) at the boundary.
&lt;span class="p"&gt;-&lt;/span&gt; No secrets in code. Read from env. Never log tokens, passwords, or full PII.
&lt;span class="p"&gt;-&lt;/span&gt; Functions that can fail return a typed error or throw — never return null silently.
&lt;span class="p"&gt;-&lt;/span&gt; When you change a signature, update every caller in the same edit.
&lt;span class="p"&gt;-&lt;/span&gt; Prefer deleting code over adding a flag. The best fix removes complexity.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Kill &lt;code&gt;any&lt;/code&gt; before it spreads (TypeScript)
&lt;/h2&gt;

&lt;p&gt;Left alone, Cursor reaches for &lt;code&gt;any&lt;/code&gt; constantly — it's the path of least resistance. This glob-scoped rule forces it to think about the real type.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript type-safety rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.ts,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/*.tsx"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; No &lt;span class="sb"&gt;`any`&lt;/span&gt;. Use &lt;span class="sb"&gt;`unknown`&lt;/span&gt; + a narrow, or define the type. If truly stuck, add &lt;span class="sb"&gt;`// TODO: type`&lt;/span&gt; with a reason.
&lt;span class="p"&gt;-&lt;/span&gt; Components are typed function components with an explicit props interface. No &lt;span class="sb"&gt;`React.FC`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Exported functions have explicit return types. No relying on inference at module boundaries.
&lt;span class="p"&gt;-&lt;/span&gt; Prefer discriminated unions over optional-everything objects.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. SQL safety, loaded on demand
&lt;/h2&gt;

&lt;p&gt;No &lt;code&gt;alwaysApply&lt;/code&gt; — it eats no context on your CSS work, but the &lt;code&gt;description&lt;/code&gt; makes Cursor pull it in the moment you write a query.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Database and SQL safety — apply when writing queries or migrations&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Always use parameterized queries / prepared statements. Never interpolate input into SQL.
&lt;span class="p"&gt;-&lt;/span&gt; Any query that can return many rows is paginated or bounded with LIMIT.
&lt;span class="p"&gt;-&lt;/span&gt; Watch for N+1: fetching a list then querying per item is a bug, not a style choice.
&lt;span class="p"&gt;-&lt;/span&gt; Migrations are reversible and never run automatically — generate the file, let a human apply it.
&lt;span class="p"&gt;-&lt;/span&gt; Select named columns, not &lt;span class="sb"&gt;`SELECT *`&lt;/span&gt;, in application queries.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Tests that target edges, not happy paths
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test-writing conventions — apply when adding or editing tests&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.*,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/*.spec.*"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Cover the edge cases first: empty input, null, boundary values, duplicate, and the error path.
&lt;span class="p"&gt;-&lt;/span&gt; One behavior per test. The test name states the expected behavior, not the function name.
&lt;span class="p"&gt;-&lt;/span&gt; No tests against private internals — test the public contract so refactors don't break them.
&lt;span class="p"&gt;-&lt;/span&gt; Don't mock what you don't own without a thin wrapper around it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "edge cases first" line is what changes the output. Without it, Cursor writes the one test that proves the function runs and stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Commit messages a human can scan
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Git commit message format&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Use Conventional Commits: type(scope): subject. Types: feat, fix, refactor, test, docs, chore.
&lt;span class="p"&gt;-&lt;/span&gt; Subject is imperative and under 60 chars: "fix: handle empty cart on checkout".
&lt;span class="p"&gt;-&lt;/span&gt; Body explains &lt;span class="ge"&gt;*why*&lt;/span&gt;, not &lt;span class="ge"&gt;*what*&lt;/span&gt; — the diff already shows what.
&lt;span class="p"&gt;-&lt;/span&gt; One logical change per commit. Don't bundle a refactor with a feature.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Accessibility, scoped to the frontend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Accessibility rules for UI&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.tsx,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/*.jsx,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/*.vue"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Every interactive element is keyboard-reachable and has an accessible name (label, aria-label, or text).
&lt;span class="p"&gt;-&lt;/span&gt; Images have alt text; decorative images use alt="".
&lt;span class="p"&gt;-&lt;/span&gt; Don't rely on color alone to convey state — pair it with text or an icon.
&lt;span class="p"&gt;-&lt;/span&gt; Focus is visible and never trapped. Modals return focus to the trigger on close.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Error handling that surfaces, not swallows
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Error handling&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Never catch an error just to log it and continue — either handle it meaningfully or rethrow.
&lt;span class="p"&gt;-&lt;/span&gt; Error messages include enough context to debug without a repro (id, operation, input shape).
&lt;span class="p"&gt;-&lt;/span&gt; User-facing errors are friendly; internal errors keep the stack. Never leak internals to the client.
&lt;span class="p"&gt;-&lt;/span&gt; No empty catch blocks. Ever.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Comments that explain "why"
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comment discipline&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Comment &lt;span class="ge"&gt;*why*&lt;/span&gt;, not &lt;span class="ge"&gt;*what*&lt;/span&gt;. If a comment restates the code, delete it and rename instead.
&lt;span class="p"&gt;-&lt;/span&gt; Flag non-obvious decisions, workarounds, and "do not change this because…" with a reason.
&lt;span class="p"&gt;-&lt;/span&gt; No commented-out code in commits. That's what git history is for.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Dependency restraint
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dependency policy&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Don't add a dependency to solve what 15 lines of code can. State the tradeoff if you do add one.
&lt;span class="p"&gt;-&lt;/span&gt; Prefer the platform/standard library before reaching for a package.
&lt;span class="p"&gt;-&lt;/span&gt; No new dependency without checking it's maintained (recent commits) and has no known critical CVEs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. The "stay in scope" rule
&lt;/h2&gt;

&lt;p&gt;The one that saves the most cleanup time. Cursor loves to "helpfully" refactor three files you didn't ask about.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Scope discipline — always apply&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Change only what the task requires. Don't reformat or refactor unrelated code in the same edit.
&lt;span class="p"&gt;-&lt;/span&gt; If you spot an unrelated bug, mention it — don't fix it without asking.
&lt;span class="p"&gt;-&lt;/span&gt; Keep diffs reviewable. A 400-line diff for a 2-line fix is a failure.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to actually adopt these
&lt;/h2&gt;

&lt;p&gt;Don't paste all ten today — you'll dilute the context and burn out maintaining them. Start with three: rule #1 (global guardrails), one stack rule (#2 if you're on TypeScript), and rule #10 (scope discipline). Live with those for a week. Add another only when you catch Cursor making the same mistake twice. A rule earns its place by preventing a real, repeated error — not by sounding good in a blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you'd rather start from a tuned set
&lt;/h2&gt;

&lt;p&gt;Curating and maintaining a rule library is its own small project. If you want a head start, I packaged my full tuned collection as the &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/gflkji?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cursor-rules-developers-should-steal" rel="noopener noreferrer"&gt;Cursor AI Power Pack&lt;/a&gt;&lt;/strong&gt; — a set of ready-to-drop &lt;code&gt;.mdc&lt;/code&gt; rules organized by stack and concern, plus prompt recipes and a START HERE guide so you know which rule to enable when. It's the same scoped, anti-fluff philosophy as the ten above, just done for you.&lt;/p&gt;

&lt;p&gt;But you don't need it to get value here. Copy rules #1 and #10 into your repo right now — those two alone will make your next Cursor session noticeably tighter.&lt;/p&gt;

&lt;p&gt;Which rule does your team enforce that I left off this list? Drop it in the comments — I'm always hunting for ones worth stealing.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>10 AI Prompts That Make Code Review Actually Useful</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Tue, 30 Jun 2026 13:01:51 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/10-ai-prompts-that-make-code-review-actually-useful-430i</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/10-ai-prompts-that-make-code-review-actually-useful-430i</guid>
      <description>&lt;p&gt;"Review my code." You paste a function, and the AI replies with a tidy paragraph: &lt;em&gt;"This code looks good! You might consider adding error handling and improving variable names."&lt;/em&gt; Thanks. You knew that. You wanted it to find the off-by-one in the loop and the unhandled null on line 14.&lt;/p&gt;

&lt;p&gt;The problem isn't the model. It's the prompt. "Review my code" gives the AI no role, no priorities, and no output format, so it defaults to vague praise. The fix is to prompt it the way a senior engineer would brief a reviewer: &lt;strong&gt;who you are, what to look for, what to ignore, and how to report it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below are the principles plus a few of the exact prompts I use. Copy them, swap in your code, and watch the quality of the feedback change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why structure beats length
&lt;/h2&gt;

&lt;p&gt;A good review prompt has four parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role + context&lt;/strong&gt; — "You are a senior backend reviewer. This runs in production handling payments."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What to check&lt;/strong&gt; — a concrete list, in priority order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraints&lt;/strong&gt; — what &lt;em&gt;not&lt;/em&gt; to do. This is the part everyone skips, and it's the part that kills the fluff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output format&lt;/strong&gt; — so you get a triaged list, not an essay.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The constraint &lt;em&gt;"Do not suggest improvements you cannot point to a specific line for"&lt;/em&gt; alone removes about half the generic noise. The model can no longer say "consider improving error handling" — it has to find the line where error handling is actually missing, or stay quiet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 1: The triaged review
&lt;/h2&gt;

&lt;p&gt;This is my default. The priority ordering and the "blocking first" rule mean the important stuff isn't buried under nitpicks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior engineer reviewing a diff for production code.

Review the code I provide. Check, in this order:
1. Correctness — logic errors, off-by-one, wrong conditionals, edge cases (empty, null, very large input).
2. Security — injection, missing authz checks, unsafe deserialization, secrets in code.
3. Reliability — unhandled errors, resource leaks, race conditions, missing timeouts.
4. Clarity — naming and structure that will confuse the next reader.

Output three sections: BLOCKING, SHOULD-FIX, NITS.
For every item, quote the exact line and give the fix as a code snippet.

Constraints:
- If a category has no issues, write "none". Do not invent problems to seem thorough.
- Do not comment on style covered by a formatter.
- No general advice. Every point must reference a specific line.

Here is the code:
[PASTE CODE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prompt 2: The adversarial "break it" review
&lt;/h2&gt;

&lt;p&gt;Sometimes you don't want a polite review — you want the AI to actively try to break your code. This catches edge cases a normal review glides past.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a hostile QA engineer. Your goal is to find inputs and conditions
that make this function behave incorrectly, crash, or produce wrong output.

For each issue, give:
- The exact input or condition that triggers it.
- What goes wrong and why.
- A minimal test that reproduces it.

Focus on: empty/null/undefined, boundary values, unexpected types, concurrent
calls, and extremely large input. Do not suggest stylistic changes.

Code:
[PASTE CODE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "give me a test that reproduces it" line is what makes this prompt pay off — you don't just hear about the bug, you get the failing test to confirm it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 3: The security-only pass
&lt;/h2&gt;

&lt;p&gt;When the code touches auth, payments, or user input, run a dedicated security pass instead of relying on the general review to catch it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a security auditor. Review this code ONLY for security issues.
Map each finding to a category: injection, broken auth/authz, sensitive data
exposure, SSRF, insecure deserialization, or missing input validation.

For each finding: severity (high/med/low), the vulnerable line, an example
exploit, and the fix. If you find nothing exploitable, say so plainly —
do not pad the report.

Code:
[PASTE CODE]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running security as its own pass works better than folding it into a general review, because a focused prompt keeps the model in one mode instead of splitting attention across naming, structure, and security all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern you can reuse for anything
&lt;/h2&gt;

&lt;p&gt;Look at what those three share: a &lt;strong&gt;role&lt;/strong&gt;, a &lt;strong&gt;prioritized checklist&lt;/strong&gt;, a hard &lt;strong&gt;constraint against fluff&lt;/strong&gt;, and a &lt;strong&gt;fixed output format&lt;/strong&gt;. That same skeleton works for debugging ("you are a debugger, reproduce before theorizing"), for refactoring ("preserve behavior, change one thing at a time"), for test writing ("target edge cases, not the happy path"), and for SQL review ("check for N+1, missing indexes, full scans").&lt;/p&gt;

&lt;p&gt;Once you internalize the skeleton, you stop typing "review my code" forever. You write prompts that tell the AI exactly what job it's doing — and it stops guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small homework
&lt;/h2&gt;

&lt;p&gt;Take the triaged-review prompt above, run it on a function you wrote this week, then run plain "review my code" on the same function. The difference is the whole point of this post — and it's free to try right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want these prompts wired into a real workflow?
&lt;/h2&gt;

&lt;p&gt;Prompts get even better when they're not floating in a chat box but baked into named, repeatable steps. That's what I built with &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/womhu?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=ai-prompts-for-code-review" rel="noopener noreferrer"&gt;Claude Code Agent OS&lt;/a&gt;&lt;/strong&gt;: it turns reviewer, debugger, test-writer, security-auditor and more into focused subagents you invoke with one command — each with the same five-part, anti-fluff structure (role, checklist, output format, constraints) as the prompts above, plus 12 slash commands and ready-to-edit &lt;code&gt;CLAUDE.md&lt;/code&gt; templates. Works with Claude Code today, and the prompts themselves drop into ChatGPT, Cursor, or Copilot.&lt;/p&gt;

&lt;p&gt;But the three prompts in this post are yours to keep and will sharpen your reviews today. Steal them, adapt them to your stack, and ship better code.&lt;/p&gt;

&lt;p&gt;Which review constraint made the biggest difference for you? I'm always collecting the lines that kill AI fluff — share yours below.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>codereview</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Cursor Rules That Actually Improve AI Output (.mdc Project Rules)</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 19:06:17 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/cursor-rules-that-actually-improve-ai-output-mdc-project-rules-50cg</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/cursor-rules-that-actually-improve-ai-output-mdc-project-rules-50cg</guid>
      <description>&lt;p&gt;Most Cursor rules I see online are wish lists. "Write clean code." "Follow best practices." "Be concise." Cursor reads them, nods politely, and ships exactly the same code it would have without them.&lt;/p&gt;

&lt;p&gt;The reason is simple: vague rules give the model nothing to act on. A rule only changes output if it's &lt;strong&gt;specific, enforceable, and scoped to when it matters.&lt;/strong&gt; After rewriting my rules around those three properties, Cursor went from "code that works but I'd reject in review" to "code that passes review the first time" on most requests.&lt;/p&gt;

&lt;p&gt;Here's what actually moved the needle, with real &lt;code&gt;.mdc&lt;/code&gt; rules you can paste in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The format: &lt;code&gt;.cursor/rules/*.mdc&lt;/code&gt;, not &lt;code&gt;.cursorrules&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Cursor has moved to &lt;strong&gt;Project Rules&lt;/strong&gt; stored as &lt;code&gt;.mdc&lt;/code&gt; files in &lt;code&gt;.cursor/rules/&lt;/code&gt;. The big advantage over the old single &lt;code&gt;.cursorrules&lt;/code&gt; file is &lt;strong&gt;scoping&lt;/strong&gt;: each rule has frontmatter that controls &lt;em&gt;when&lt;/em&gt; it loads.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Security&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code"&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three frontmatter fields decide everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alwaysApply: true&lt;/code&gt; — the rule is in context on every request. Use for short, universal rules (security, error handling).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;globs: "**/*.tsx"&lt;/code&gt; — the rule auto-attaches only when a matching file is in play. Use for stack-specific rules so your React rules don't pollute your Python context.&lt;/li&gt;
&lt;li&gt;Neither set — the agent pulls the rule in &lt;em&gt;when it judges it relevant&lt;/em&gt;, based on the &lt;code&gt;description&lt;/code&gt;. Use for situational best-practice rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This scoping is the whole game. Loading every rule on every request dilutes the context and the model starts ignoring all of them. Scoped rules stay sharp because only the relevant ones are present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 1: A global rule the model can actually enforce
&lt;/h2&gt;

&lt;p&gt;Keep your always-on rule short and written as concrete checks, not aspirations:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global engineering rules — always apply&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Validate and type all external input (API bodies, query params, env vars) at the boundary.
&lt;span class="p"&gt;-&lt;/span&gt; Every function that can fail returns a typed error or throws — never returns null silently.
&lt;span class="p"&gt;-&lt;/span&gt; No secrets in code. Read from env. Never log tokens, passwords, or full PII.
&lt;span class="p"&gt;-&lt;/span&gt; When you change a function's signature, update every caller in the same change.
&lt;span class="p"&gt;-&lt;/span&gt; Prefer deleting code over adding flags. The best fix removes complexity.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice there's no "write clean code." Every line is a check the model can apply to a specific diff. "Validate input at the boundary" produces a &lt;code&gt;zod&lt;/code&gt; schema; "write clean code" produces nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 2: A stack rule scoped by glob
&lt;/h2&gt;

&lt;p&gt;This one only loads when a TypeScript/React file is involved, so it never interferes with your backend or scripts:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React + TypeScript conventions&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.tsx,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/*.ts"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Components are typed function components. No &lt;span class="sb"&gt;`React.FC`&lt;/span&gt;. Props via an explicit interface.
&lt;span class="p"&gt;-&lt;/span&gt; No &lt;span class="sb"&gt;`any`&lt;/span&gt;. Use &lt;span class="sb"&gt;`unknown`&lt;/span&gt; + a narrow, or define the type. If you truly can't, add a &lt;span class="sb"&gt;`// TODO: type`&lt;/span&gt; and explain.
&lt;span class="p"&gt;-&lt;/span&gt; Follow the Rules of Hooks: no hooks in conditions or loops. Effects list every dependency they read.
&lt;span class="p"&gt;-&lt;/span&gt; Data fetching goes through the existing query layer, not raw &lt;span class="sb"&gt;`fetch`&lt;/span&gt; inside components.
&lt;span class="p"&gt;-&lt;/span&gt; Every interactive element is keyboard-accessible and has an accessible name (label, aria-label, or text).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;no any&lt;/code&gt; rule is the one people underrate. Left alone, Cursor reaches for &lt;code&gt;any&lt;/code&gt; constantly because it's the path of least resistance. One scoped line removes most of it and forces it to think about the actual type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 3: A best-practice rule the agent loads on demand
&lt;/h2&gt;

&lt;p&gt;Some rules only matter sometimes — like database access. Leave &lt;code&gt;alwaysApply&lt;/code&gt; off and write a clear &lt;code&gt;description&lt;/code&gt; so the agent pulls it in when it touches SQL:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Database and SQL safety — apply when writing queries or migrations&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="p"&gt;-&lt;/span&gt; Always use parameterized queries / prepared statements. Never interpolate user input into SQL.
&lt;span class="p"&gt;-&lt;/span&gt; Every query that can return many rows is paginated or explicitly bounded with LIMIT.
&lt;span class="p"&gt;-&lt;/span&gt; Add an index before shipping a query that filters or joins on a non-indexed column — call it out.
&lt;span class="p"&gt;-&lt;/span&gt; Migrations are reversible and never run automatically. Generate the file; let the human apply it.
&lt;span class="p"&gt;-&lt;/span&gt; Watch for N+1: fetching a list then querying per item is a bug, not a style choice.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because this rule isn't always loaded, it doesn't eat context on your CSS work. But the moment you ask Cursor to write a query, its description makes it relevant and it gets pulled in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The before/after that convinced me
&lt;/h2&gt;

&lt;p&gt;Same request — "add an endpoint to fetch a user's orders" — with and without the rules above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without rules:&lt;/strong&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="nx"&gt;app&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/orders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;res&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;userId&lt;/span&gt; &lt;span class="o"&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;query&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`SELECT * FROM orders WHERE user_id = &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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orders&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;SQL injection, no input validation, no pagination, &lt;code&gt;SELECT *&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With the rules:&lt;/strong&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/orders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;res&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;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&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;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&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="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="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&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;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT id, total, status, created_at FROM orders WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3&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="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&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;Parameterized, validated, paginated, explicit columns. Same model, same prompt. The rules did that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to start without overdoing it
&lt;/h2&gt;

&lt;p&gt;Don't write twenty rules on day one — you'll dilute the context and burn out maintaining them. Start with exactly three:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One short &lt;code&gt;alwaysApply&lt;/code&gt; global rule (security + error handling).&lt;/li&gt;
&lt;li&gt;One glob-scoped rule for your main stack.&lt;/li&gt;
&lt;li&gt;One on-demand rule for whatever bites you most (SQL, accessibility, tests).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Live with those for a week, then add a rule only when you catch Cursor making the same mistake twice. Rules earn their place by preventing a real, repeated error.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want a full, tuned AI-coding setup
&lt;/h2&gt;

&lt;p&gt;Rules are one half of the picture. The other half is giving your AI assistant a real workflow — focused review/test/refactor steps instead of one generalist doing everything. I packaged my complete setup as &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/womhu?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=cursor-rules-that-actually-work" rel="noopener noreferrer"&gt;Claude Code Agent OS&lt;/a&gt;&lt;/strong&gt;: 26 specialized subagents, 12 slash commands, ready-to-edit &lt;code&gt;CLAUDE.md&lt;/code&gt; templates, MCP configs, and safety hooks — the same scoped, anti-fluff philosophy as the rules above, applied to the whole coding loop. It works alongside Cursor and any editor.&lt;/p&gt;

&lt;p&gt;That said, the three-rule starter in this post costs nothing and will improve your very next Cursor session. Build those first, then decide if you want the full setup.&lt;/p&gt;

&lt;p&gt;What's the one mistake Cursor keeps making in your codebase? Tell me in the comments and I'll suggest a rule for it.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I Set Up Claude Code with 26 Production Subagents (CLAUDE.md, MCP, Hooks)</title>
      <dc:creator>NongdyZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 13:54:39 +0000</pubDate>
      <link>https://dev.to/nongdyz_d9c3069b1acb2a08c/how-i-set-up-claude-code-with-26-production-subagents-claudemd-mcp-hooks-3jij</link>
      <guid>https://dev.to/nongdyz_d9c3069b1acb2a08c/how-i-set-up-claude-code-with-26-production-subagents-claudemd-mcp-hooks-3jij</guid>
      <description>&lt;p&gt;When I first opened Claude Code on a real project, it felt like hiring a brilliant junior who had read every book but never shipped anything. It could write code fast, but it would forget my conventions halfway through a session, run a migration without asking, and "fix" a bug by deleting the failing test.&lt;/p&gt;

&lt;p&gt;After a few weeks of tuning, it now behaves like a small senior team: it plans before it codes, reviews its own work, writes tests, and refuses to run anything destructive. The difference wasn't a better model. It was a better &lt;strong&gt;setup&lt;/strong&gt; — a &lt;code&gt;CLAUDE.md&lt;/code&gt;, a set of focused subagents, a couple of MCP servers, and two small hooks.&lt;/p&gt;

&lt;p&gt;Here is exactly how that setup works, so you can build your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. CLAUDE.md is the contract, not a wishlist
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; is the file Claude Code reads automatically at the start of every session. Most people treat it like a README. It works far better as a &lt;strong&gt;contract&lt;/strong&gt;: short, specific, and written in always/never terms the agent can't misread.&lt;/p&gt;

&lt;p&gt;The two rules that gave me the biggest jump in quality:&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;## Build &amp;amp; test (run these, do not guess)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Install:  pnpm install
&lt;span class="p"&gt;-&lt;/span&gt; Dev:      pnpm dev
&lt;span class="p"&gt;-&lt;/span&gt; Test:     pnpm test -- --run
&lt;span class="p"&gt;-&lt;/span&gt; Lint:     pnpm lint
&lt;span class="p"&gt;-&lt;/span&gt; Typecheck: pnpm typecheck

&lt;span class="gu"&gt;## Always&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Run &lt;span class="sb"&gt;`pnpm typecheck &amp;amp;&amp;amp; pnpm test -- --run`&lt;/span&gt; before saying a task is done.
&lt;span class="p"&gt;-&lt;/span&gt; Use parameterized queries. Never build SQL with string concatenation.
&lt;span class="p"&gt;-&lt;/span&gt; When you change a public function, update its tests in the same edit.

&lt;span class="gu"&gt;## Never&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Never run &lt;span class="sb"&gt;`git push`&lt;/span&gt;, &lt;span class="sb"&gt;`git reset --hard`&lt;/span&gt;, or any DB migration without me confirming.
&lt;span class="p"&gt;-&lt;/span&gt; Never add a dependency to fix something a few lines of code can solve.
&lt;span class="p"&gt;-&lt;/span&gt; Never disable a failing test to make the suite pass.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason the "Build &amp;amp; test" block matters: without the exact commands, the agent &lt;strong&gt;guesses&lt;/strong&gt; them (&lt;code&gt;npm test&lt;/code&gt;, &lt;code&gt;yarn test&lt;/code&gt;, &lt;code&gt;make test&lt;/code&gt;) and wastes turns failing. Give it the real commands once and it stops guessing.&lt;/p&gt;

&lt;p&gt;Keep this file under ~50 lines. A long &lt;code&gt;CLAUDE.md&lt;/code&gt; gets diluted in the context and the agent starts ignoring the middle of it. Be ruthless.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Subagents: split one generalist into many specialists
&lt;/h2&gt;

&lt;p&gt;A single agent juggling "review this, also write tests, also refactor" produces mediocre output at every task. Subagents fix this by giving each job its own focused instructions and its own context window. In Claude Code these live in &lt;code&gt;.claude/agents/*.md&lt;/code&gt; and you invoke them by name.&lt;/p&gt;

&lt;p&gt;A subagent is just a Markdown file with frontmatter and a system prompt. Here's a real one — my &lt;code&gt;code-reviewer&lt;/code&gt;:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-reviewer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bugs,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;security&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;issues,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;convention&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;violations.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;after&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;writing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code."&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Bash&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are a senior code reviewer. Review ONLY the changed lines plus their immediate context.

Output exactly three sections:
&lt;span class="p"&gt;1.&lt;/span&gt; &lt;span class="gs"&gt;**Blocking**&lt;/span&gt; — bugs, security holes, data loss risks. Each with file:line and a fix.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Should fix**&lt;/span&gt; — correctness or clarity issues that aren't blocking.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Nits**&lt;/span&gt; — style/naming. Keep this short.

Rules:
&lt;span class="p"&gt;-&lt;/span&gt; If there are no blocking issues, say so on line one. Do not invent problems to look thorough.
&lt;span class="p"&gt;-&lt;/span&gt; Check: injection, missing error handling, N+1 queries, unhandled null, race conditions.
&lt;span class="p"&gt;-&lt;/span&gt; Quote the exact line you're flagging. No vague "consider improving error handling".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two lines that make it useful are &lt;em&gt;"Do not invent problems to look thorough"&lt;/em&gt; and &lt;em&gt;"Quote the exact line."&lt;/em&gt; Without them, reviewers either rubber-stamp everything or generate a wall of generic advice. With them, you get actionable output.&lt;/p&gt;

&lt;p&gt;I run a roster of focused specialists this way — a &lt;code&gt;debugger&lt;/code&gt; that reproduces before it theorizes, a &lt;code&gt;test-writer&lt;/code&gt; that targets edge cases instead of happy paths, a &lt;code&gt;security-auditor&lt;/code&gt; that thinks in OWASP categories, an &lt;code&gt;api-designer&lt;/code&gt;, a &lt;code&gt;refactor-architect&lt;/code&gt;, and so on. Each one is a small file with a tight output format. The pattern is always the same: &lt;strong&gt;one job, one output format, one anti-fluff constraint.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. MCP: give the agent eyes and memory
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers are how Claude Code reaches outside the chat — the filesystem, a browser, a persistent memory store. You configure them in &lt;code&gt;.mcp.json&lt;/code&gt;:&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;"mcpServers"&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;"filesystem"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;span class="nl"&gt;"sequential-thinking"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-sequential-thinking"&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;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;p&gt;The one I'd add first is &lt;strong&gt;sequential-thinking&lt;/strong&gt;. It gives the agent a scratchpad to break a problem into steps before acting, which noticeably reduces the "confidently wrong" answers on multi-step tasks. A browser MCP (Playwright) is the second I reach for, because it lets the agent actually load the page and read the console instead of guessing why the UI broke.&lt;/p&gt;

&lt;p&gt;One caution: MCP servers move fast and some get abandoned. Pin to maintained ones and check they still install before you rely on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Hooks: the safety net that runs without asking
&lt;/h2&gt;

&lt;p&gt;Hooks are shell commands Claude Code runs on events you choose. Two are worth setting up on day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-format on save&lt;/strong&gt; — so you never review a diff full of whitespace noise:&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;"hooks"&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;"PostToolUse"&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;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Edit|Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pnpm prettier --write &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$CLAUDE_FILE_PATHS&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;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;p&gt;&lt;strong&gt;Block dangerous commands&lt;/strong&gt; — a pre-execution guard that refuses destructive shell calls even if the agent tries them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# .claude/hooks/guard.sh — exit non-zero to block the command&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CLAUDE_TOOL_INPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf /|git reset --hard|DROP TABLE'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Blocked: destructive command refused by guard hook."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the difference between trusting an autonomous agent and babysitting it. The model can be wrong; the hook is deterministic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together: a feature, start to finish
&lt;/h2&gt;

&lt;p&gt;With the setup above, my actual workflow on a new feature is short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask the agent to &lt;strong&gt;plan&lt;/strong&gt; — it writes the steps before touching code.&lt;/li&gt;
&lt;li&gt;It scaffolds and implements, formatting on save via the hook.&lt;/li&gt;
&lt;li&gt;I invoke &lt;code&gt;code-reviewer&lt;/code&gt; on the diff, then &lt;code&gt;test-writer&lt;/code&gt; for the gaps it found.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pnpm typecheck &amp;amp;&amp;amp; pnpm test&lt;/code&gt; runs because &lt;code&gt;CLAUDE.md&lt;/code&gt; says it must.&lt;/li&gt;
&lt;li&gt;It drafts the commit and PR description.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent does the typing. I do the deciding. That's the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want the whole thing as a drop-in?
&lt;/h2&gt;

&lt;p&gt;Building all of this from scratch is a real time sink — the 26 subagents alone took me weeks of tuning to get the output formats right. If you'd rather skip that and drop a finished setup into any repo, I packaged my exact configuration as &lt;strong&gt;&lt;a href="https://planfulnest.gumroad.com/l/womhu" rel="noopener noreferrer"&gt;Claude Code Agent OS&lt;/a&gt;&lt;/strong&gt;: 26 specialized subagents, 12 slash commands (&lt;code&gt;/plan&lt;/code&gt;, &lt;code&gt;/review&lt;/code&gt;, &lt;code&gt;/test&lt;/code&gt;, &lt;code&gt;/ship&lt;/code&gt;...), 5 ready-to-edit &lt;code&gt;CLAUDE.md&lt;/code&gt; templates, the MCP configs, and the safety + format hooks (bash and PowerShell) — with a START HERE quickstart that gets you running in about 5 minutes.&lt;/p&gt;

&lt;p&gt;But you don't need it to get value from this post. Start with a tight &lt;code&gt;CLAUDE.md&lt;/code&gt; and one &lt;code&gt;code-reviewer&lt;/code&gt; subagent today; that pair alone will change how your next commit feels.&lt;/p&gt;

&lt;p&gt;If you build your own subagent roster, I'd genuinely like to see which specialists you find most useful — drop them in the comments.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
