<?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: Nova Elvaris</title>
    <description>The latest articles on DEV Community by Nova Elvaris (@novaelvaris).</description>
    <link>https://dev.to/novaelvaris</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3774356%2F1cb4e0e2-edf0-49b3-a78f-5f7aa4523cb4.png</url>
      <title>DEV Community: Nova Elvaris</title>
      <link>https://dev.to/novaelvaris</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/novaelvaris"/>
    <language>en</language>
    <item>
      <title>Why Your AI Code Review Misses Stateful Bugs (and the 3-Context Fix)</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Sat, 11 Apr 2026 11:53:24 +0000</pubDate>
      <link>https://dev.to/novaelvaris/why-your-ai-code-review-misses-stateful-bugs-and-the-3-context-fix-12pl</link>
      <guid>https://dev.to/novaelvaris/why-your-ai-code-review-misses-stateful-bugs-and-the-3-context-fix-12pl</guid>
      <description>&lt;p&gt;A lot of AI code reviews look sharp right up until they miss the bug that actually matters.&lt;/p&gt;

&lt;p&gt;They catch naming noise, dead comments, maybe a missing null check. But they miss the regression caused by a cache key change, the migration that no longer matches the model, or the new flag that breaks the retry path two services away.&lt;/p&gt;

&lt;p&gt;The pattern I've noticed is simple: the model isn't bad at review, it's under-contextualized.&lt;/p&gt;

&lt;p&gt;Most review prompts only include the diff. Stateful bugs usually live outside the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the diff alone isn't enough
&lt;/h2&gt;

&lt;p&gt;A diff shows what changed. It does &lt;strong&gt;not&lt;/strong&gt; show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what state existed before the change&lt;/li&gt;
&lt;li&gt;what surrounding invariants must still hold&lt;/li&gt;
&lt;li&gt;what hidden dependency the change now violates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a PR changes this:&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diff looks syntactically harmless. But if downstream readers still call &lt;code&gt;cache.get(user.id)&lt;/code&gt;, you've just created a bug that only appears in a later request path.&lt;/p&gt;

&lt;p&gt;The model won't reliably catch that if you only hand it the patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-context fix
&lt;/h2&gt;

&lt;p&gt;I now structure review prompts around three layers of context.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Change context
&lt;/h3&gt;

&lt;p&gt;This is the diff itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Here is the unified diff for the PR. Identify likely logic, state, and integration risks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Necessary, but not sufficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Runtime context
&lt;/h3&gt;

&lt;p&gt;Tell the model what state or workflow the code participates in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Runtime context:
&lt;span class="p"&gt;-&lt;/span&gt; cache keys are always user IDs
&lt;span class="p"&gt;-&lt;/span&gt; writes happen during login
&lt;span class="p"&gt;-&lt;/span&gt; reads happen during profile fetch and billing sync
&lt;span class="p"&gt;-&lt;/span&gt; stale cache entries can cause cross-user data leaks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is usually the missing layer. It gives the model something to reason &lt;em&gt;against&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Invariant context
&lt;/h3&gt;

&lt;p&gt;List the rules that must stay true after the change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Invariants:
&lt;span class="p"&gt;-&lt;/span&gt; cache write key must equal cache read key
&lt;span class="p"&gt;-&lt;/span&gt; one user may never read another user's profile
&lt;span class="p"&gt;-&lt;/span&gt; failed sync retries must remain idempotent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invariants are powerful because they shift review from "does this code look nice?" to "what rule might this break?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt template
&lt;/h2&gt;

&lt;p&gt;This is the version I keep around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;You are reviewing a code change for bugs, not style.

&lt;span class="gu"&gt;## Change context&lt;/span&gt;
[paste diff]

&lt;span class="gu"&gt;## Runtime context&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; describe where this code runs
&lt;span class="p"&gt;-&lt;/span&gt; describe stateful dependencies
&lt;span class="p"&gt;-&lt;/span&gt; describe side effects

&lt;span class="gu"&gt;## Invariant context&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; list 3-5 rules that must remain true

&lt;span class="gu"&gt;## Output format&lt;/span&gt;
Return:
&lt;span class="p"&gt;1.&lt;/span&gt; short summary
&lt;span class="p"&gt;2.&lt;/span&gt; likely bug risks
&lt;span class="p"&gt;3.&lt;/span&gt; missing tests
&lt;span class="p"&gt;4.&lt;/span&gt; what additional file/context you would inspect next

Do not comment on naming, formatting, or refactors unless they create a bug risk.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line matters. Otherwise the model burns attention on surface-level cleanup.&lt;/p&gt;

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

&lt;p&gt;Here's a compact example with a queue consumer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# before
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;mark_failed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# after
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;mark_failed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine, right?&lt;/p&gt;

&lt;p&gt;But if the invariant is "a job gets 3 retries after the initial run," then &lt;code&gt;&amp;gt;= 3&lt;/code&gt; changes the allowed retry count. That's a behavioral bug, not a syntax bug.&lt;/p&gt;

&lt;p&gt;A diff-only review may miss it.&lt;/p&gt;

&lt;p&gt;A review with runtime and invariant context usually flags it immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed for me after using this
&lt;/h2&gt;

&lt;p&gt;Once I started feeding these three context types into review prompts, the comments got noticeably better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer style nitpicks&lt;/li&gt;
&lt;li&gt;more integration warnings&lt;/li&gt;
&lt;li&gt;better test suggestions&lt;/li&gt;
&lt;li&gt;clearer calls for follow-up inspection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model still doesn't replace a human reviewer. But it stops acting like a linter with opinions and starts acting more like a junior engineer who understands the system constraints.&lt;/p&gt;

&lt;p&gt;That's a much better role.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; What's the last bug your AI review missed, and was the missing piece really model quality, or just missing runtime context?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 Fields Every Prompt Contract Needs Before a Team Can Trust It</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Sat, 11 Apr 2026 11:38:20 +0000</pubDate>
      <link>https://dev.to/novaelvaris/5-fields-every-prompt-contract-needs-before-a-team-can-trust-it-3jo6</link>
      <guid>https://dev.to/novaelvaris/5-fields-every-prompt-contract-needs-before-a-team-can-trust-it-3jo6</guid>
      <description>&lt;p&gt;Most prompt failures on teams are not model failures. They're spec failures.&lt;/p&gt;

&lt;p&gt;One person writes a prompt that returns JSON. Someone else adds a tone instruction. A third person pastes it into a different tool that expects markdown. By Friday, everyone is using "the same prompt" and getting different behavior.&lt;/p&gt;

&lt;p&gt;That's why I like Prompt Contracts: a short spec for how a prompt is supposed to work. But a contract only helps if it includes the fields a team actually needs.&lt;/p&gt;

&lt;p&gt;Here are the five fields I now consider mandatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Purpose
&lt;/h2&gt;

&lt;p&gt;If a prompt contract can't answer "what job is this prompt for?" in one sentence, it's already too vague.&lt;/p&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Generate a useful response about the code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Review a git diff and return actionable bug findings before merge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single sentence narrows scope. It also makes it obvious when someone tries to turn the same prompt into a style checker, architecture reviewer, and mentoring assistant all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Inputs
&lt;/h2&gt;

&lt;p&gt;Teams break prompts when they silently change the input shape.&lt;/p&gt;

&lt;p&gt;Spell out what the prompt expects:&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;## Inputs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`diff`&lt;/span&gt;: unified git diff, required
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`language`&lt;/span&gt;: programming language, optional
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`focus`&lt;/span&gt;: one of &lt;span class="sb"&gt;`bugs | security | maintainability`&lt;/span&gt;, default &lt;span class="sb"&gt;`bugs`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the downstream caller knows what to send, and a teammate can't casually add "also pass screenshots and ticket IDs" without updating the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Output schema
&lt;/h2&gt;

&lt;p&gt;This is the field most teams skip, and it's the one that causes the ugliest breakage.&lt;/p&gt;

&lt;p&gt;If a prompt is part of a workflow, define the output format explicitly:&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;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"findings"&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;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high|medium|low"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"issue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&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;"blocking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;Once you do this, two good things happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;humans know what a "correct" answer looks like&lt;/li&gt;
&lt;li&gt;scripts can validate output instead of hoping the model behaved&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Error modes
&lt;/h2&gt;

&lt;p&gt;A lot of prompts work on the happy path and fall apart the second the input is weird.&lt;/p&gt;

&lt;p&gt;Add an error section:&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;## Error modes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; If &lt;span class="sb"&gt;`diff`&lt;/span&gt; is empty, return an empty findings array
&lt;span class="p"&gt;-&lt;/span&gt; If input exceeds 2,000 lines, return &lt;span class="sb"&gt;`error: split_input`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; If required context is missing, ask exactly one clarifying question
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the difference between a reliable prompt and a polite chaos machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Non-goals
&lt;/h2&gt;

&lt;p&gt;I love this field because it stops "helpful" scope creep.&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;## Non-goals&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Do not rewrite working code
&lt;span class="p"&gt;-&lt;/span&gt; Do not suggest dependency swaps
&lt;span class="p"&gt;-&lt;/span&gt; Do not flag style issues when focus=bugs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without non-goals, assistants tend to drift toward whatever they can comment on. Suddenly your bug review prompt is giving naming advice and suggesting framework migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The compact template
&lt;/h2&gt;

&lt;p&gt;Here's the version I actually use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Prompt Contract: Code Review&lt;/span&gt;

&lt;span class="gu"&gt;## Purpose&lt;/span&gt;
Review a diff and find merge-blocking issues.

&lt;span class="gu"&gt;## Inputs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; diff (required)
&lt;span class="p"&gt;-&lt;/span&gt; language (optional)
&lt;span class="p"&gt;-&lt;/span&gt; focus=bugs|security|maintainability

&lt;span class="gu"&gt;## Output schema&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; summary
&lt;span class="p"&gt;-&lt;/span&gt; findings[]
&lt;span class="p"&gt;-&lt;/span&gt; blocking

&lt;span class="gu"&gt;## Error modes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; empty diff -&amp;gt; empty findings
&lt;span class="p"&gt;-&lt;/span&gt; oversize diff -&amp;gt; split_input
&lt;span class="p"&gt;-&lt;/span&gt; missing context -&amp;gt; ask one clarifying question

&lt;span class="gu"&gt;## Non-goals&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; no rewrites
&lt;span class="p"&gt;-&lt;/span&gt; no style nits unless requested
&lt;span class="p"&gt;-&lt;/span&gt; no dependency advice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fits on one page, which matters. If the contract turns into a mini novel, nobody reads it consistently, including the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works better than prompt folklore
&lt;/h2&gt;

&lt;p&gt;Teams often share prompts through Slack messages, Notion pages, or copied snippets in random repos. That's folklore, not a system.&lt;/p&gt;

&lt;p&gt;A contract turns "the prompt Alex swears by" into a reusable asset that can be reviewed, versioned, and tested.&lt;/p&gt;

&lt;p&gt;And once you start doing that, prompt quality stops depending on memory.&lt;/p&gt;

&lt;p&gt;It starts depending on a file.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; If you had to add just one field to your current prompts today, would it be inputs, output schema, or non-goals?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Why AI Forgets Your Project's Conventions (and the One-File Fix)</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Fri, 10 Apr 2026 13:15:05 +0000</pubDate>
      <link>https://dev.to/novaelvaris/why-ai-forgets-your-projects-conventions-and-the-one-file-fix-1d7o</link>
      <guid>https://dev.to/novaelvaris/why-ai-forgets-your-projects-conventions-and-the-one-file-fix-1d7o</guid>
      <description>&lt;p&gt;You spend 20 minutes explaining to your AI assistant that this codebase uses tabs not spaces, that every function needs a docstring, that you prefer early returns over nested ifs, that this project uses &lt;code&gt;snake_case&lt;/code&gt; for files even though the team uses &lt;code&gt;kebab-case&lt;/code&gt; elsewhere. It nails the next three files. You're thrilled.&lt;/p&gt;

&lt;p&gt;Then you start a new session the next morning. It's back to spaces, nested ifs, and JSDoc-style comments. Like the last conversation never happened.&lt;/p&gt;

&lt;p&gt;Here's why that's built into how these tools work — and the one-file pattern I use to fix it permanently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this keeps happening
&lt;/h2&gt;

&lt;p&gt;LLMs have no persistent memory between sessions. Whatever you taught the model in yesterday's chat is gone the moment you open a new window. The only "memory" that survives is whatever you put into the prompt at the start of the new session.&lt;/p&gt;

&lt;p&gt;Most people solve this by re-explaining conventions every time, or by copy-pasting a style guide into every prompt. Both are tedious and error-prone. You'll forget to include the "prefer early returns" rule three times a week, and the model will cheerfully write nested nightmares until you catch it.&lt;/p&gt;

&lt;p&gt;The real fix is to make the conventions a file in your project, and to make reading that file the first thing any AI assistant does when it touches your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CONVENTIONS.md pattern
&lt;/h2&gt;

&lt;p&gt;Create a file at the root of your project called &lt;code&gt;CONVENTIONS.md&lt;/code&gt;. It's short, specific, and written in imperative voice. Here's the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Conventions&lt;/span&gt;

&lt;span class="gu"&gt;## Tone / voice (for generated content)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Neutral, concise, no emojis in code comments
&lt;span class="p"&gt;-&lt;/span&gt; Prefer active voice

&lt;span class="gu"&gt;## Formatting&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Indentation: 4 spaces (NOT tabs)
&lt;span class="p"&gt;-&lt;/span&gt; Line length: 100 chars
&lt;span class="p"&gt;-&lt;/span&gt; Trailing commas: yes (for diff-friendliness)

&lt;span class="gu"&gt;## Naming&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Files: snake_case.py
&lt;span class="p"&gt;-&lt;/span&gt; Classes: PascalCase
&lt;span class="p"&gt;-&lt;/span&gt; Functions: snake_case
&lt;span class="p"&gt;-&lt;/span&gt; Constants: SCREAMING_SNAKE
&lt;span class="p"&gt;-&lt;/span&gt; Never abbreviate except: &lt;span class="sb"&gt;`db`&lt;/span&gt;, &lt;span class="sb"&gt;`id`&lt;/span&gt;, &lt;span class="sb"&gt;`url`&lt;/span&gt;, &lt;span class="sb"&gt;`http`&lt;/span&gt;

&lt;span class="gu"&gt;## Code style&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Prefer early returns over nested &lt;span class="sb"&gt;`if`&lt;/span&gt;s
&lt;span class="p"&gt;-&lt;/span&gt; No single-letter variable names except in comprehensions
&lt;span class="p"&gt;-&lt;/span&gt; Docstrings on every public function (Google style)
&lt;span class="p"&gt;-&lt;/span&gt; Type hints on every function signature

&lt;span class="gu"&gt;## Libraries&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; HTTP: requests (NOT httpx)
&lt;span class="p"&gt;-&lt;/span&gt; Testing: pytest (NOT unittest)
&lt;span class="p"&gt;-&lt;/span&gt; Dates: datetime with explicit UTC (NOT pendulum, NOT arrow)

&lt;span class="gu"&gt;## Directory rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Tests live in tests/, mirroring src/ structure
&lt;span class="p"&gt;-&lt;/span&gt; No code in __init__.py beyond imports
&lt;span class="p"&gt;-&lt;/span&gt; One class per file unless they're tightly coupled

&lt;span class="gu"&gt;## Things to NEVER do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Don't add new dependencies without asking
&lt;span class="p"&gt;-&lt;/span&gt; Don't refactor unrelated code
&lt;span class="p"&gt;-&lt;/span&gt; Don't "improve" existing code style to match elsewhere
&lt;span class="p"&gt;-&lt;/span&gt; Don't add comments that explain what the code does (only WHY)

&lt;span class="gu"&gt;## Things to ALWAYS do&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Run mypy --strict on any file you modify
&lt;span class="p"&gt;-&lt;/span&gt; Add a test for every new public function
&lt;span class="p"&gt;-&lt;/span&gt; Update CHANGELOG.md for user-facing changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep it under 100 lines. If it's longer, nobody (human or model) will internalize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The invocation ritual
&lt;/h2&gt;

&lt;p&gt;At the start of every AI-assisted session on this project, paste this one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before you do anything else, read CONVENTIONS.md in the project root. Follow it strictly. If anything I ask contradicts it, ask me which should win before proceeding.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The model now has explicit instructions to (a) load the conventions, (b) follow them, and (c) flag conflicts rather than silently deviating.&lt;/p&gt;

&lt;p&gt;I bolt this onto my project scaffolding template, so every new project starts with a CONVENTIONS.md and the invocation line sits in my session-starter snippet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one file beats a styleguide folder
&lt;/h2&gt;

&lt;p&gt;You might be tempted to split this across multiple files — naming conventions in one place, formatting in another, library choices in a third. Don't. The model has to read all of them anyway, and when they're split, you lose the ability to just say "read CONVENTIONS.md." You're now juggling "which files do you need to load?" again.&lt;/p&gt;

&lt;p&gt;One file. Root of the project. Always read first. Simple rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when conventions change
&lt;/h2&gt;

&lt;p&gt;When the team decides to switch from &lt;code&gt;requests&lt;/code&gt; to &lt;code&gt;httpx&lt;/code&gt;, you update exactly one line in CONVENTIONS.md. Every future AI session will pick up the change automatically. No hunting through old prompts. No "wait, which library did we standardize on?"&lt;/p&gt;

&lt;p&gt;This is the same reason README files work: &lt;strong&gt;a single canonical source of truth beats a dozen scattered reminders.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A real test
&lt;/h2&gt;

&lt;p&gt;I ran a blind test on a Python project with a complex convention set (40 rules across formatting, naming, libraries, and anti-patterns):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Without CONVENTIONS.md:&lt;/strong&gt; Across 10 new files, the model violated an average of 7.2 conventions per file. Mostly formatting and library choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With CONVENTIONS.md and the invocation line:&lt;/strong&gt; Across 10 new files, the model violated an average of 0.6 conventions per file. Three files were completely clean.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's an order-of-magnitude improvement from one file and one sentence.&lt;/p&gt;

&lt;p&gt;The broader lesson: &lt;strong&gt;anything you find yourself re-explaining to your assistant is a missing file in your project.&lt;/strong&gt; Write it down once, reference it always.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; What's the one convention you're tired of re-explaining to your AI assistant? Mine is "early returns, not nested ifs" — I must have said it 200 times before I wrote it down.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>5 Signs Your Prompt Is Leaking Tokens (and How to Seal Each One)</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Fri, 10 Apr 2026 12:24:31 +0000</pubDate>
      <link>https://dev.to/novaelvaris/5-signs-your-prompt-is-leaking-tokens-and-how-to-seal-each-one-57o3</link>
      <guid>https://dev.to/novaelvaris/5-signs-your-prompt-is-leaking-tokens-and-how-to-seal-each-one-57o3</guid>
      <description>&lt;p&gt;A "leaky" prompt is one that burns tokens without contributing to the output. The model gets bigger inputs, the bill goes up, and the quality gets &lt;em&gt;worse&lt;/em&gt; because the signal drowns in noise. I audited my own prompt library last week and found 5 categories of leaks. Here they are, with the fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign 1: You're pasting the whole file when the model only needs 20 lines
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Your prompts look like &lt;code&gt;"Here's my project: [3000 lines of code]. Now fix the bug in the login function."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it leaks:&lt;/strong&gt; The model has to scan the entire context to find the relevant section. For every leak like this, you pay ingestion cost twice — once to find the relevant code, once to actually reason about it. And the larger the haystack, the more likely the model pulls irrelevant context into its answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Extract the minimal slice. For a bug in &lt;code&gt;login()&lt;/code&gt;, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;login()&lt;/code&gt; function itself&lt;/li&gt;
&lt;li&gt;Its direct callers (one or two at most)&lt;/li&gt;
&lt;li&gt;The types/interfaces it uses&lt;/li&gt;
&lt;li&gt;NOT the unrelated 2,000 lines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 30-second &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; gets you there. Most IDEs have "copy symbol with references" built in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign 2: You keep re-explaining the same context in every prompt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Every prompt in your session starts with "I'm building a Flask app that uses Postgres and handles user auth via JWT..."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it leaks:&lt;/strong&gt; You're paying ingestion cost for the same context on every single turn. In a 20-turn session, that's 20x the tokens for no benefit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; &lt;strong&gt;Seed files.&lt;/strong&gt; Put the project context in a single file (&lt;code&gt;CONTEXT.md&lt;/code&gt;) and reference it once at the top of the session. Then let the model remember via its own context window, or re-inject only on genuine switches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'm working on the project described in CONTEXT.md (attached).
For this session, focus on: &lt;span class="nt"&gt;&amp;lt;specific&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Context explained once, referenced by name after that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign 3: Your examples are longer than your instructions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; You give the model three full-length input/output pairs as "few-shot examples" to teach it a format, and the examples eat 80% of your prompt budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it leaks:&lt;/strong&gt; Examples are necessary, but they compound fast. Three 200-word examples = 600 words just to set up a task that should be 100 words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Use &lt;strong&gt;minimal-pair examples.&lt;/strong&gt; Instead of full realistic examples, give tiny toy examples that only demonstrate the format, then describe the real inputs separately.&lt;/p&gt;

&lt;p&gt;Before (leaky):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example 1:
Input: [300 words of realistic text]
Output: [250 words of formatted output]

Example 2:
Input: [300 more words]
Output: [250 more words]

Now process this: [real input]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After (sealed):&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="err"&gt;Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;every&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"urgency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"low"&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="s2"&gt;"med"&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;Example:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Input:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ship broken"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Output:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ship broken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"bug"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"urgency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;Now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;process:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;real&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;input&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;Same signal, a tenth of the tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign 4: You're including chat history the model doesn't need
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Your conversation is 15 turns deep and you're still sending all 15 turns to the model for every new message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it leaks:&lt;/strong&gt; The model re-processes the entire history on every turn. Turn 15 pays for context from turns 1-14 &lt;em&gt;every single time&lt;/em&gt;, even if those turns were tool errors, clarifying questions, or false starts that are no longer relevant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; &lt;strong&gt;Compact the history.&lt;/strong&gt; At turn 5, 10, or 15, ask the model to summarize what's been decided and what state we're in. Then start a new thread with just the summary. (See also: The Handoff Prompt — same idea, different trigger.)&lt;/p&gt;

&lt;p&gt;Most chat UIs won't do this automatically. You have to build the habit: "Summarize our progress so far, then I'll start fresh."&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign 5: You're using verbose natural language where a schema would do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Prompts like &lt;code&gt;"Return the answer as a JSON object with a field called 'summary' which should be a string containing a brief description, and then a field called 'tags' which should be an array of strings, and also include a field called 'urgency' which can be one of 'low', 'medium', or 'high'..."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it leaks:&lt;/strong&gt; You're using 80 tokens to describe what a 20-token schema fragment could say unambiguously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Write the schema directly:&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="err"&gt;Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(strict&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;prose):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"urgency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"low"&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="s2"&gt;"medium"&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="s2"&gt;"high"&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;Fewer tokens, less ambiguity, better compliance from the model. Modern LLMs handle type-like notation better than long English descriptions for format instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the audit on your own prompts
&lt;/h2&gt;

&lt;p&gt;Pick your 10 most-used prompts. For each one, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Am I pasting more context than the task needs?&lt;/li&gt;
&lt;li&gt;Am I re-explaining things the model already knew?&lt;/li&gt;
&lt;li&gt;Are my examples longer than my instructions?&lt;/li&gt;
&lt;li&gt;Is my chat history a graveyard?&lt;/li&gt;
&lt;li&gt;Am I describing structure in prose?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A single "yes" is a leak. Two or more, and you're probably spending 2-3x what you should on tokens without improving quality.&lt;/p&gt;

&lt;p&gt;I cut my token usage by about 40% after doing this audit on my own stuff. The unexpected bonus: the &lt;em&gt;quality&lt;/em&gt; of the outputs also went up, because the signal-to-noise ratio improved in every prompt.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; Which of these five leaks is your worst offender? Mine is #4 — I let chat histories run way too long before compacting. Curious where everyone else's leaks live.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Handoff Prompt: Transfer AI Context Between Models Without Losing State</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Fri, 10 Apr 2026 12:18:26 +0000</pubDate>
      <link>https://dev.to/novaelvaris/the-handoff-prompt-transfer-ai-context-between-models-without-losing-state-39a4</link>
      <guid>https://dev.to/novaelvaris/the-handoff-prompt-transfer-ai-context-between-models-without-losing-state-39a4</guid>
      <description>&lt;p&gt;Here's a workflow I run almost every day: start a task with a fast cheap model, hit its limits, then escalate to a bigger model for the hard part. Or go the other way — use a big model to design something, then switch to a small one for mechanical execution.&lt;/p&gt;

&lt;p&gt;The problem: every time I switched, I'd paste half my chat history into the new window and the new model would start with the wrong context. Missing decisions, misread scope, re-asking questions I'd already answered.&lt;/p&gt;

&lt;p&gt;So I stopped copy-pasting chats and started writing a &lt;strong&gt;Handoff Prompt&lt;/strong&gt; — a structured summary the outgoing model writes for the incoming one. Here's the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with raw chat transfer
&lt;/h2&gt;

&lt;p&gt;When you paste a long conversation into a new model, three things go wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Signal-to-noise drops.&lt;/strong&gt; Most chat turns are tool errors, clarifications, false starts. The new model has to re-infer what's still relevant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decisions disappear.&lt;/strong&gt; "We decided to use Postgres instead of DynamoDB" is buried in turn 14. The new model might recommend DynamoDB on turn 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implicit context is lost.&lt;/strong&gt; Things the old model "knew" from earlier in the conversation aren't spelled out anywhere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Raw transcripts are the worst possible format for context transfer. They're optimized for humans replaying a conversation, not for an agent picking up work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Handoff Prompt template
&lt;/h2&gt;

&lt;p&gt;At the end of a session (or whenever I want to switch models), I ask the current model to generate a handoff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;You are about to hand off this task to another AI assistant. Write a HANDOFF PROMPT that contains everything the next assistant needs, and nothing it doesn't. Use this exact structure:

&lt;span class="gh"&gt;# Handoff: &amp;lt;one-line task summary&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Goal&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;what&lt;/span&gt; &lt;span class="na"&gt;we&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;re&lt;/span&gt; &lt;span class="na"&gt;trying&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="na"&gt;accomplish&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="na"&gt;-3&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Current state&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;what&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt; &lt;span class="na"&gt;been&lt;/span&gt; &lt;span class="na"&gt;done&lt;/span&gt; &lt;span class="na"&gt;so&lt;/span&gt; &lt;span class="na"&gt;far&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="na"&gt;concrete&lt;/span&gt; &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;not&lt;/span&gt; &lt;span class="na"&gt;narrative&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Decisions made (do not re-litigate)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;decision&amp;gt;&lt;/span&gt;: &lt;span class="nt"&gt;&amp;lt;reason&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;decision&amp;gt;&lt;/span&gt;: &lt;span class="nt"&gt;&amp;lt;reason&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Open questions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;question&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="na"&gt;hasn&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;t&lt;/span&gt; &lt;span class="na"&gt;answered&lt;/span&gt; &lt;span class="na"&gt;yet&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Constraints&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;hard&lt;/span&gt; &lt;span class="na"&gt;constraint&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;e.g.&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;no&lt;/span&gt; &lt;span class="na"&gt;external&lt;/span&gt; &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;soft&lt;/span&gt; &lt;span class="na"&gt;constraint&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;e.g.&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;prefers&lt;/span&gt; &lt;span class="na"&gt;functional&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Next step&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;the&lt;/span&gt; &lt;span class="na"&gt;single&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="na"&gt;thing&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;incoming&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt; &lt;span class="na"&gt;should&lt;/span&gt; &lt;span class="na"&gt;do&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Context files&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;list&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;file&lt;/span&gt; &lt;span class="na"&gt;paths&lt;/span&gt; &lt;span class="na"&gt;or&lt;/span&gt; &lt;span class="na"&gt;artifacts&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt; &lt;span class="na"&gt;should&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt; &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

Do NOT include chat pleasantries, tool errors, or anything the next assistant doesn't strictly need. Be ruthless.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is usually 200-400 tokens. That's it. That's your entire context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Decisions are explicit.&lt;/strong&gt; The "Decisions made" section acts like an immune system against re-litigation. The next model sees "we chose Postgres, not DynamoDB" and won't suggest otherwise unless you explicitly ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State is concrete, not narrative.&lt;/strong&gt; "Implemented the user auth endpoint, tests passing, see &lt;code&gt;api/auth.py&lt;/code&gt;" beats "We've been working on the auth stuff and it's mostly done I think."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The next step is pre-committed.&lt;/strong&gt; Instead of the new model deciding what to do, it inherits a specific instruction. Momentum is preserved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open questions surface.&lt;/strong&gt; The old model often knows it's blocked on something. Writing it down means the new model can ask the human directly instead of stumbling into the same wall.&lt;/p&gt;

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

&lt;p&gt;Here's a handoff I generated yesterday, switching from a small model (design phase) to a bigger one (implementation phase):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Handoff: Build a CLI tool that syncs markdown notes to a SQLite FTS5 index&lt;/span&gt;

&lt;span class="gu"&gt;## Goal&lt;/span&gt;
A Python CLI &lt;span class="sb"&gt;`notesync`&lt;/span&gt; that indexes all .md files in a directory into SQLite FTS5, supports search, and handles incremental updates.

&lt;span class="gu"&gt;## Current state&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Requirements gathered
&lt;span class="p"&gt;-&lt;/span&gt; Schema designed (see below)
&lt;span class="p"&gt;-&lt;/span&gt; No code written yet

&lt;span class="gu"&gt;## Decisions made (do not re-litigate)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Python 3.11+, stdlib sqlite3 only, no ORMs
&lt;span class="p"&gt;-&lt;/span&gt; FTS5 table with columns: path, title, body, mtime
&lt;span class="p"&gt;-&lt;/span&gt; Incremental sync via mtime comparison
&lt;span class="p"&gt;-&lt;/span&gt; CLI uses argparse, not click (user preference)
&lt;span class="p"&gt;-&lt;/span&gt; Search output: path + 1-line snippet, ranked by bm25

&lt;span class="gu"&gt;## Open questions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; None currently

&lt;span class="gu"&gt;## Constraints&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Must work on macOS and Linux
&lt;span class="p"&gt;-&lt;/span&gt; No external dependencies beyond Python stdlib
&lt;span class="p"&gt;-&lt;/span&gt; Single file preferred (notesync.py)

&lt;span class="gu"&gt;## Next step&lt;/span&gt;
Write notesync.py with three commands: &lt;span class="sb"&gt;`init`&lt;/span&gt;, &lt;span class="sb"&gt;`sync`&lt;/span&gt;, &lt;span class="sb"&gt;`search`&lt;/span&gt;. Start with &lt;span class="sb"&gt;`init`&lt;/span&gt; (create schema).

&lt;span class="gu"&gt;## Context files&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; /Users/nova/projects/notesync/SCHEMA.md
&lt;span class="p"&gt;-&lt;/span&gt; /Users/nova/projects/notesync/REQUIREMENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new model reads that in one pass and starts coding. No "let me understand the requirements first." No re-asking about Click vs argparse. No re-exploring the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model switch mid-task&lt;/strong&gt; (cheap → expensive or vice versa)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ending a session you'll resume tomorrow&lt;/strong&gt; (future-you is another model, basically)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delegating a subtask to a separate agent&lt;/strong&gt; (parallel work, clean context)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging a long thread that's gone off the rails&lt;/strong&gt; (handoff cuts the garbage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The handoff prompt is one of those techniques that sounds obvious once you've seen it, but I spent months awkwardly pasting chat logs before I started writing them explicitly. Try it once on a task you're about to switch models on — the difference is stark.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; How do you currently transfer context between AI tools or sessions? Got a better template than this one? I'd genuinely love to see what other people use.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>productivity</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Why Your AI Code Review Misses Real Bugs (and the 3-Prompt Fix)</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Fri, 10 Apr 2026 12:02:13 +0000</pubDate>
      <link>https://dev.to/novaelvaris/why-your-ai-code-review-misses-real-bugs-and-the-3-prompt-fix-3j6o</link>
      <guid>https://dev.to/novaelvaris/why-your-ai-code-review-misses-real-bugs-and-the-3-prompt-fix-3j6o</guid>
      <description>&lt;p&gt;I used to have one prompt for code review. Something like: "Review this diff, find bugs, suggest improvements." It gave me back a confident list of nitpicks — naming suggestions, "consider extracting this function", occasional style comments — while happily missing the actual null-pointer waiting to crash in production.&lt;/p&gt;

&lt;p&gt;Here's why that happens, and the 3-prompt pipeline I use now instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one-shot code review fails
&lt;/h2&gt;

&lt;p&gt;A single "review this code" prompt forces the model to do three completely different jobs at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Understand what the code is supposed to do&lt;/strong&gt; (intent)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find where it doesn't do that&lt;/strong&gt; (bugs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggest how to fix it&lt;/strong&gt; (improvements)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each job uses different reasoning. Mashing them together means the model takes the path of least resistance: surface-level style nits, because those are easy to spot and sound authoritative. The hard bugs — the ones that require actually tracing execution paths — get skipped because the model already has enough to say.&lt;/p&gt;

&lt;p&gt;This isn't a prompting skill issue. It's a task-structure issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-prompt pipeline
&lt;/h2&gt;

&lt;p&gt;Split the review into three isolated prompts. Each one gets focused context and a narrow job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt 1: Intent extraction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reading a git diff. Do NOT review it yet.

For each changed function or block, answer:
1. What is this code trying to do? (one sentence)
2. What preconditions does it assume? (bulleted list)
3. What postconditions should hold after it runs?

Diff:
&amp;lt;paste diff&amp;gt;

Output as JSON: {"blocks": [{"name": ..., "intent": ..., "preconditions": [...], "postconditions": [...]}]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompt does nothing but extract understanding. No bug hunting. No suggestions. Just: "what is this code supposed to be doing?"&lt;/p&gt;

&lt;p&gt;Save the output. You'll need it in prompts 2 and 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt 2: Bug hunting (guided by intent)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;You are hunting for bugs in a git diff. Here is the AUTHOR'S INTENT for each block (extracted separately):
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&amp;lt;paste output from prompt 1&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;Here is the diff:
&lt;/span&gt;&amp;lt;paste diff&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;For each block, answer:
1. Does the code actually satisfy the stated postconditions? If not, where does it fail?
2. Are the preconditions checked? If not, what input breaks this?
3. What edge cases (null, empty, off-by-one, concurrent access, unicode, timezone) are unhandled?
4. Are there any silent failures (swallowed exceptions, default fallbacks, retries without limit)?
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;For each bug, output: {severity: high|medium|low, location, bug, concrete failing input}.
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;If a block has no bugs, say "no bugs found" explicitly. Do NOT suggest style changes.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The magic is that the model now has something to compare the code against. "Does the code satisfy the postconditions?" is a concrete, checkable question. Much better than "find bugs," which is an open invitation to hallucinate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt 3: Fix suggestions (only for real bugs)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here are confirmed bugs in a diff:
&amp;lt;paste output from prompt 2&amp;gt;

For each bug marked high or medium, propose:
1. The minimal fix (diff-style if possible)
2. A test case that would have caught this bug
3. Whether this needs a broader refactor or can be patched in place

Do NOT propose fixes for low-severity bugs unless the fix is one line.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By isolating the fix step, the model stops bundling "here's a bug" with a 40-line rewrite you'd never actually accept.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this catches that one-shot misses
&lt;/h2&gt;

&lt;p&gt;Real examples from the last two weeks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cache lookup that silently fell back to &lt;code&gt;null&lt;/code&gt; when the key was missing, without logging. Prompt 1 surfaced that the postcondition was "returns user data." Prompt 2 noticed the code returned &lt;code&gt;null&lt;/code&gt; on cache miss. One-shot review had called out variable naming.&lt;/li&gt;
&lt;li&gt;An async function that awaited inside a loop but didn't handle partial failures. Prompt 1 extracted "all items must be processed." Prompt 2 noticed a thrown exception mid-loop would leave the remainder unprocessed.&lt;/li&gt;
&lt;li&gt;A SQL query built with string interpolation inside a helper that looked safe. The one-shot review missed it because "this is a helper, nothing weird here" is easy to infer. Prompt 2 caught it because it explicitly asked "what input breaks this?"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The cost
&lt;/h2&gt;

&lt;p&gt;Yes, this is 3x the tokens. For any non-trivial diff, it's worth it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-shot finds maybe 30% of real bugs and ~5 nitpicks&lt;/li&gt;
&lt;li&gt;3-prompt finds ~70% of real bugs and zero nitpicks (because you never asked for them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a hot code path or a release candidate, I run all three. For a trivial refactor PR, I skip to prompt 2 alone with a short intent note.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why splitting helps
&lt;/h2&gt;

&lt;p&gt;The deeper principle: &lt;strong&gt;LLMs are better at checking claims than generating them.&lt;/strong&gt; When you give the model a specific claim to verify ("does this code meet postcondition X?"), it becomes a much sharper critic. When you ask it to generate a freeform review, it defaults to pattern-matching on what reviews usually look like — which is mostly nits.&lt;/p&gt;

&lt;p&gt;Every good multi-step LLM workflow I've built has this shape: generate claims cheaply, then verify them carefully in a separate step.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; What's the worst bug an AI code reviewer ever missed for you? I'm collecting examples — the more embarrassing, the better.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Prompt Contracts for Teams: Sharing AI Specs Without the Merge Hell</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Fri, 10 Apr 2026 11:48:57 +0000</pubDate>
      <link>https://dev.to/novaelvaris/prompt-contracts-for-teams-sharing-ai-specs-without-the-merge-hell-1ef7</link>
      <guid>https://dev.to/novaelvaris/prompt-contracts-for-teams-sharing-ai-specs-without-the-merge-hell-1ef7</guid>
      <description>&lt;p&gt;If you've been writing Prompt Contracts for a while, you know they work. One page, clear inputs, clear outputs, clear error cases, and suddenly your AI assistant stops drifting mid-task.&lt;/p&gt;

&lt;p&gt;Then your teammate opens yours, tweaks three lines, and everyone on the team has a slightly different version floating around in a Notion doc, a Slack thread, and somebody's &lt;code&gt;~/prompts/&lt;/code&gt; folder. Now you're back to the chaos Prompt Contracts were supposed to fix.&lt;/p&gt;

&lt;p&gt;Here's the workflow I landed on after the third week of reconciling "which contract is current?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with shared prompts
&lt;/h2&gt;

&lt;p&gt;Prompts are code. But most teams treat them like docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No version control&lt;/li&gt;
&lt;li&gt;No review process&lt;/li&gt;
&lt;li&gt;No ownership&lt;/li&gt;
&lt;li&gt;No tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a prompt lives in a shared doc, every edit is a silent breaking change. Your teammate adds "respond in YAML" to fix one task and breaks the downstream script that expected JSON. Nobody notices for three days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The team contract layout
&lt;/h2&gt;

&lt;p&gt;I keep team prompts in a dedicated repo (or subfolder) with this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompts/
â”œâ”€â”€ contracts/
â”‚   â”œâ”€â”€ code-review.md
â”‚   â”œâ”€â”€ bug-triage.md
â”‚   â””â”€â”€ release-notes.md
â”œâ”€â”€ fixtures/
â”‚   â”œâ”€â”€ code-review/
â”‚   â”‚   â”œâ”€â”€ input-valid.json
â”‚   â”‚   â””â”€â”€ expected-output.json
â”‚   â””â”€â”€ ...
â”œâ”€â”€ tests/
â”‚   â””â”€â”€ run-contract-tests.sh
â””â”€â”€ CHANGELOG.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each contract file is the spec. Fixtures are the test cases. Tests prove the contract still works against a real model. Changelog tracks breaking changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The contract template
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Contract: Code Review&lt;/span&gt;

&lt;span class="gs"&gt;**Version:**&lt;/span&gt; 1.3.0
&lt;span class="gs"&gt;**Owner:**&lt;/span&gt; @nova
&lt;span class="gs"&gt;**Last verified:**&lt;/span&gt; 2026-04-09

&lt;span class="gu"&gt;## Purpose&lt;/span&gt;
Review a git diff and return actionable feedback in a structured format.

&lt;span class="gu"&gt;## Inputs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`diff`&lt;/span&gt;: unified git diff (string, required)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`language`&lt;/span&gt;: programming language (string, optional)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`focus`&lt;/span&gt;: one of [bugs, style, security, all] (default: bugs)

&lt;span class="gu"&gt;## Output schema&lt;/span&gt;
Return JSON matching:
{
  "summary": string,
  "findings": [{"severity": "high|medium|low", "file": string, "line": number, "issue": string, "suggestion": string}],
  "blocking": boolean
}

&lt;span class="gu"&gt;## Error modes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; If diff is empty â†’ return {"summary": "empty diff", "findings": [], "blocking": false}
&lt;span class="p"&gt;-&lt;/span&gt; If diff &amp;gt; 2000 lines â†’ return {"error": "diff too large, split into chunks"}

&lt;span class="gu"&gt;## Non-goals&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Do NOT rewrite code
&lt;span class="p"&gt;-&lt;/span&gt; Do NOT flag style issues when focus=bugs
&lt;span class="p"&gt;-&lt;/span&gt; Do NOT suggest library swaps

&lt;span class="gu"&gt;## Changelog&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; 1.3.0: Added &lt;span class="sb"&gt;`focus`&lt;/span&gt; parameter
&lt;span class="p"&gt;-&lt;/span&gt; 1.2.0: Added &lt;span class="sb"&gt;`blocking`&lt;/span&gt; boolean
&lt;span class="p"&gt;-&lt;/span&gt; 1.1.0: Switched from markdown to JSON output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The review process
&lt;/h2&gt;

&lt;p&gt;Treat contract changes like any other PR:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a PR against the prompt repo&lt;/li&gt;
&lt;li&gt;Bump the version in the contract header (semver: breaking = major, additive = minor, wording = patch)&lt;/li&gt;
&lt;li&gt;Add a fixture if the change introduces new behavior&lt;/li&gt;
&lt;li&gt;Run the test script â€” it replays fixtures against the model and diffs the output&lt;/li&gt;
&lt;li&gt;Get one approval before merging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The test script is dumb but effective:&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;#!/bin/bash&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;contract &lt;span class="k"&gt;in &lt;/span&gt;contracts/&lt;span class="k"&gt;*&lt;/span&gt;.md&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$contract&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; .md&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;fixture &lt;span class="k"&gt;in &lt;/span&gt;fixtures/&lt;span class="nv"&gt;$name&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.json&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$contract&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$fixture&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | llm &lt;span class="nt"&gt;-m&lt;/span&gt; claude-4 &lt;span class="nt"&gt;--no-stream&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fixtures/&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;/expected-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="nv"&gt;$fixture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;diff &amp;lt;&lt;span class="o"&gt;(&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;$output&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-S&lt;/span&gt; .&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;jq &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt; / &lt;/span&gt;&lt;span class="nv"&gt;$fixture&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
  done
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not deterministic (LLMs never are), but it catches the obvious regressions: wrong schema, missing fields, breaking format changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ownership matters
&lt;/h2&gt;

&lt;p&gt;Every contract needs exactly one owner. Not a team, not a channel â€” one name. The owner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Approves breaking changes&lt;/li&gt;
&lt;li&gt;Responds when the contract fails in production&lt;/li&gt;
&lt;li&gt;Deprecates old versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without ownership, contracts rot the same way docs rot.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this fixes
&lt;/h2&gt;

&lt;p&gt;After a month of this setup on a team of four:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero "which prompt should I use?" questions in Slack&lt;/li&gt;
&lt;li&gt;Two caught regressions before deploy (both were additive changes that accidentally broke JSON output)&lt;/li&gt;
&lt;li&gt;One deprecation handled cleanly (v0.9 â†’ v1.0 with a migration note in the changelog)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The contract model isn't new. Treating prompts like shared API specs is. Once you flip that mental switch, half the ambient prompt pain goes away.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Question for you:&lt;/strong&gt; If you're on a team using AI tools, where do your prompts live right now? Shared doc? Personal folder? A repo? I'm curious how many teams have actually committed to treating prompts as code vs. just talking about it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Token Budgets for Real Projects: How I Keep AI Costs Under $50/Month</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Tue, 07 Apr 2026 12:37:48 +0000</pubDate>
      <link>https://dev.to/novaelvaris/token-budgets-for-real-projects-how-i-keep-ai-costs-under-50month-375d</link>
      <guid>https://dev.to/novaelvaris/token-budgets-for-real-projects-how-i-keep-ai-costs-under-50month-375d</guid>
      <description>&lt;p&gt;AI coding assistants are useful. They're also expensive if you're not paying attention. I was spending $120/month before I started tracking. Now I spend under $50 for the same (honestly, better) output.&lt;/p&gt;

&lt;p&gt;Here's the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Invisible Costs
&lt;/h2&gt;

&lt;p&gt;Most developers don't track AI token usage. They paste code, get results, paste more code. Each interaction costs money, but the feedback loop is delayed — you see the bill at the end of the month.&lt;/p&gt;

&lt;p&gt;The biggest cost drivers aren't the prompts. &lt;strong&gt;They're the context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A typical AI coding session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System prompt: ~500 tokens&lt;/li&gt;
&lt;li&gt;Your context (project files, examples): ~2,000-8,000 tokens&lt;/li&gt;
&lt;li&gt;Your actual question: ~200 tokens&lt;/li&gt;
&lt;li&gt;AI response: ~500-2,000 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That context window is 80% of your bill. And most of it is the same information you send every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Token Budget System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Rule 1: Set a Daily Cap
&lt;/h3&gt;

&lt;p&gt;I budget &lt;strong&gt;$2/day&lt;/strong&gt; for AI coding assistance. That's ~$50/month with weekends off. When I hit the cap, I code without AI for the rest of the day. (Spoiler: I'm still productive.)&lt;/p&gt;

&lt;p&gt;Most API dashboards let you set hard limits. Do it. Knowing you have a budget forces better prompting habits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 2: Measure Your Context-to-Output Ratio
&lt;/h3&gt;

&lt;p&gt;For every AI interaction, roughly track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context tokens sent: ~4,000
Useful output tokens: ~300
Ratio: 13:1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your ratio is above 10:1, you're overpaying for context. Trim it.&lt;/p&gt;

&lt;p&gt;My target ratio: &lt;strong&gt;5:1 or better.&lt;/strong&gt; For every token of context I send, I want at least 1/5th of a token of useful output back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 3: Cache Your Context
&lt;/h3&gt;

&lt;p&gt;Instead of pasting your whole project context every time, create a &lt;strong&gt;context kit&lt;/strong&gt; (3-4 small files that describe your project). Reuse it across sessions.&lt;/p&gt;

&lt;p&gt;This alone cut my context costs by 40%. I went from sending 6,000 tokens of context per prompt to ~1,500 tokens of pre-written, optimized context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 4: Use the Right Model for the Job
&lt;/h3&gt;

&lt;p&gt;Not every task needs GPT-4 or Claude Opus. Here's my decision tree:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Autocomplete, boilerplate&lt;/td&gt;
&lt;td&gt;Copilot / small model&lt;/td&gt;
&lt;td&gt;Fast, cheap, good enough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unit tests, type definitions&lt;/td&gt;
&lt;td&gt;GPT-4o-mini / Haiku&lt;/td&gt;
&lt;td&gt;Well-defined tasks, doesn't need reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex logic, architecture&lt;/td&gt;
&lt;td&gt;GPT-4 / Claude Sonnet&lt;/td&gt;
&lt;td&gt;Worth the cost for accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging production issues&lt;/td&gt;
&lt;td&gt;Claude Opus / o1&lt;/td&gt;
&lt;td&gt;Needs deep reasoning, rare use&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I use the expensive models maybe 2-3 times per day. Everything else runs on cheaper alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rule 5: Stop the Iteration Tax
&lt;/h3&gt;

&lt;p&gt;Every follow-up message in a conversation includes the entire conversation history. Message 1 costs X. Message 5 costs ~5X because of accumulated context.&lt;/p&gt;

&lt;p&gt;My rule: &lt;strong&gt;If you're on turn 4 and still not done, start a new conversation with a better prompt.&lt;/strong&gt; It's cheaper and usually produces better results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Monthly Breakdown
&lt;/h2&gt;

&lt;p&gt;Here's what my $50/month actually looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Copilot (flat fee)&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;          &lt;span class="s"&gt;$10/month&lt;/span&gt;
&lt;span class="na"&gt;API calls (GPT-4o-mini)&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;$8/month   (~60% of interactions)&lt;/span&gt;
&lt;span class="na"&gt;API calls (Claude Sonnet)&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;$18/month  (~30% of interactions)&lt;/span&gt;
&lt;span class="na"&gt;API calls (Opus/o1)&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;$12/month  (~10% of interactions)&lt;/span&gt;
&lt;span class="na"&gt;Buffer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                      &lt;span class="s"&gt;$2/month&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I Stopped Doing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stopped using AI for code I can write in under 2 minutes.&lt;/strong&gt; The overhead of prompting + reviewing &amp;gt; just typing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stopped pasting entire files "for context."&lt;/strong&gt; I send interfaces, types, and function signatures instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stopped multi-turn debugging sessions.&lt;/strong&gt; If the AI doesn't find the bug in 2 turns, I debug manually. It's faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stopped using expensive models for simple tasks.&lt;/strong&gt; A $0.002 API call does the same job as a $0.05 call for 80% of my work.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Track It
&lt;/h2&gt;

&lt;p&gt;You can't optimize what you don't measure. Spend 10 minutes setting up a simple token tracking spreadsheet or use your API provider's dashboard. Check it weekly.&lt;/p&gt;

&lt;p&gt;Most developers I've talked to are surprised by how much they spend on AI. The ones who track it spend 40-60% less.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your monthly AI spend? And do you actually know, or are you guessing? Tracking it is the first step to controlling it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Your AI Code Review Misses Logic Bugs (and a 4-Step Fix)</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Tue, 07 Apr 2026 12:26:06 +0000</pubDate>
      <link>https://dev.to/novaelvaris/why-your-ai-code-review-misses-logic-bugs-and-a-4-step-fix-2na2</link>
      <guid>https://dev.to/novaelvaris/why-your-ai-code-review-misses-logic-bugs-and-a-4-step-fix-2na2</guid>
      <description>&lt;p&gt;You added AI to your code review workflow. It catches unused imports, suggests better variable names, and flags missing null checks. But it keeps missing the bugs that actually matter: &lt;strong&gt;logic bugs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's why, and a four-step prompt strategy that fixes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI Misses Logic Bugs
&lt;/h2&gt;

&lt;p&gt;AI code review tools analyze code &lt;strong&gt;locally.&lt;/strong&gt; They see the diff. They see the file. Sometimes they see a few related files. But they don't understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the feature is &lt;em&gt;supposed&lt;/em&gt; to do (business logic)&lt;/li&gt;
&lt;li&gt;What the previous behavior was (regression risk)&lt;/li&gt;
&lt;li&gt;How this code interacts with the rest of the system (integration bugs)&lt;/li&gt;
&lt;li&gt;What the user expects to happen (UX implications)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this context, AI reviews optimize for &lt;strong&gt;code quality&lt;/strong&gt; — clean syntax, good patterns, consistent style. That's useful, but it's not where production bugs live.&lt;/p&gt;

&lt;p&gt;Production bugs live in the gap between what the code does and what it &lt;em&gt;should&lt;/em&gt; do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4-Step Fix
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Give the AI the Spec, Not Just the Code
&lt;/h3&gt;

&lt;p&gt;Before the diff, provide a 2-3 sentence description of what this change is supposed to accomplish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This PR adds rate limiting to the /api/upload endpoint.
Expected behavior: max 10 uploads per user per hour.
If exceeded, return 429 with a Retry-After header.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, the AI reviews &lt;em&gt;how&lt;/em&gt; you wrote the code. With this, it can review &lt;em&gt;whether&lt;/em&gt; the code does the right thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Ask for Specific Bug Categories
&lt;/h3&gt;

&lt;p&gt;Generic "review this code" prompts get generic reviews. Instead, ask for specific failure modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this diff for:
1. Cases where the rate limit could be bypassed
2. Race conditions in the counter increment
3. Edge cases: what happens at exactly 10 requests? At counter reset?
4. What happens if Redis is down?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces the AI to think about &lt;em&gt;behavior&lt;/em&gt;, not just &lt;em&gt;style.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Include a Failing Scenario
&lt;/h3&gt;

&lt;p&gt;Give the AI a concrete scenario to trace through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trace this scenario through the code:
- User uploads file #10 at 14:59:59
- User uploads file #11 at 15:00:01
- The hourly window resets at 15:00:00

Does the counter reset correctly? Can the user upload at 15:00:01?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scenario tracing catches timing bugs, off-by-one errors, and boundary conditions that pattern-matching reviews miss completely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Ask "What Could Go Wrong in Production?"
&lt;/h3&gt;

&lt;p&gt;This is the highest-value question, and most people never ask it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assuming this code is deployed to production with 10,000 concurrent users:
- What could break?
- What could be slow?
- What could be exploited?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shifts the AI from "does this code look correct?" to "will this code survive the real world?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It Together
&lt;/h2&gt;

&lt;p&gt;Here's the full review prompt template:&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;## Context&lt;/span&gt;
[2-3 sentence description of the change]

&lt;span class="gu"&gt;## Diff&lt;/span&gt;
[your code diff]

&lt;span class="gu"&gt;## Review Focus&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Does this implementation match the expected behavior above?
&lt;span class="p"&gt;2.&lt;/span&gt; [2-3 specific failure modes to check]
&lt;span class="p"&gt;3.&lt;/span&gt; Trace this scenario: [concrete test case]
&lt;span class="p"&gt;4.&lt;/span&gt; What could go wrong in production at scale?

&lt;span class="gu"&gt;## Out of Scope&lt;/span&gt;
Don't comment on: style, naming, formatting (our linter handles that).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "out of scope" line is important. It prevents the AI from spending its attention budget on things your linter already catches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Since switching to this structured review approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logic bugs caught in review:&lt;/strong&gt; went from ~1/week to ~4/week&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time per review:&lt;/strong&gt; increased by ~3 minutes (for writing the context)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-deploy bugs:&lt;/strong&gt; dropped noticeably&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three extra minutes of context saves hours of debugging. That's the trade.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's the worst bug AI missed in your code review? I'll start: a race condition in a payment flow that the AI called "clean and well-structured."&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>codequality</category>
    </item>
    <item>
      <title>The 3-File Context Kit: Everything Your AI Needs to Understand Your Project</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Tue, 07 Apr 2026 12:16:24 +0000</pubDate>
      <link>https://dev.to/novaelvaris/the-3-file-context-kit-everything-your-ai-needs-to-understand-your-project-hhc</link>
      <guid>https://dev.to/novaelvaris/the-3-file-context-kit-everything-your-ai-needs-to-understand-your-project-hhc</guid>
      <description>&lt;p&gt;Every time you start a new AI coding session, you re-explain your project. The stack, the conventions, the folder structure, the gotchas. It takes 10 minutes. Every. Single. Time.&lt;/p&gt;

&lt;p&gt;Here's how I fixed it with three files that take 15 minutes to set up once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;AI assistants have no memory between sessions. Each conversation starts from zero. So you either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dump your entire codebase (wasteful, confusing)&lt;/li&gt;
&lt;li&gt;Re-explain everything each time (tedious, inconsistent)&lt;/li&gt;
&lt;li&gt;Just wing it and hope for the best (chaotic)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these work well. Option 3 is why your AI keeps suggesting Express when you use Fastify.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-File Kit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File 1: &lt;code&gt;PROJECT.md&lt;/code&gt; — The Identity Card
&lt;/h3&gt;

&lt;p&gt;This tells the AI &lt;em&gt;what&lt;/em&gt; your project is. Keep it under 50 lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project: invoice-api&lt;/span&gt;

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Runtime: Node.js 22 + TypeScript 5.4
&lt;span class="p"&gt;-&lt;/span&gt; Framework: Fastify
&lt;span class="p"&gt;-&lt;/span&gt; Database: PostgreSQL 16 via Drizzle ORM
&lt;span class="p"&gt;-&lt;/span&gt; Auth: JWT (access + refresh tokens)
&lt;span class="p"&gt;-&lt;/span&gt; Testing: Vitest

&lt;span class="gu"&gt;## Structure&lt;/span&gt;
src/
  routes/       # Fastify route handlers
  services/     # Business logic
  db/           # Drizzle schema + migrations
  middleware/   # Auth, validation, logging
  types/        # Shared TypeScript types

&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Errors: throw HttpError (from src/errors.ts), don't return error objects
&lt;span class="p"&gt;-&lt;/span&gt; Logging: use req.log (Pino), never console.log
&lt;span class="p"&gt;-&lt;/span&gt; IDs: UUIDv7 (time-sortable)
&lt;span class="p"&gt;-&lt;/span&gt; Dates: always UTC, stored as timestamptz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File 2: &lt;code&gt;PATTERNS.md&lt;/code&gt; — The Style Guide
&lt;/h3&gt;

&lt;p&gt;This tells the AI &lt;em&gt;how&lt;/em&gt; you write code. Include real examples from your codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Code Patterns&lt;/span&gt;

&lt;span class="gu"&gt;## Route Handler&lt;/span&gt;
Always use schema validation. Always return typed responses.

// GOOD:
app.post('/invoices', {
  schema: { body: CreateInvoiceSchema, response: { 201: InvoiceSchema } },
  handler: async (req, reply) =&amp;gt; {
    const invoice = await invoiceService.create(req.body);
    return reply.code(201).send(invoice);
  }
});

&lt;span class="gu"&gt;## Service Layer&lt;/span&gt;
Services take plain objects, return plain objects. No Fastify types.

&lt;span class="gu"&gt;## Error Handling&lt;/span&gt;
throw new HttpError(404, 'Invoice not found');
// NOT: return { error: 'not found' }

&lt;span class="gu"&gt;## Tests&lt;/span&gt;
One describe block per function. Use factories for test data.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File 3: &lt;code&gt;BOUNDARIES.md&lt;/code&gt; — The Guardrails
&lt;/h3&gt;

&lt;p&gt;This tells the AI what &lt;em&gt;not&lt;/em&gt; to do. This file prevents the most common AI mistakes.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="gu"&gt;## Don't&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Don't add dependencies without asking
&lt;span class="p"&gt;-&lt;/span&gt; Don't use classes unless the existing code uses classes
&lt;span class="p"&gt;-&lt;/span&gt; Don't create abstractions for single-use code
&lt;span class="p"&gt;-&lt;/span&gt; Don't change the database schema without explicit instruction
&lt;span class="p"&gt;-&lt;/span&gt; Don't use console.log (use req.log or the logger from src/logger.ts)
&lt;span class="p"&gt;-&lt;/span&gt; Don't add try/catch in route handlers (the error middleware handles it)

&lt;span class="gu"&gt;## When Unsure&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Ask before changing folder structure
&lt;span class="p"&gt;-&lt;/span&gt; Ask before adding new patterns not in PATTERNS.md
&lt;span class="p"&gt;-&lt;/span&gt; If a task is ambiguous, list your assumptions before coding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Use Them
&lt;/h2&gt;

&lt;p&gt;At the start of every AI session, paste all three files. That's it. Total context: ~150 lines, usually under 2K tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Here's my project context:

[paste PROJECT.md]
[paste PATTERNS.md]
[paste BOUNDARIES.md]

Now, help me implement [your actual task].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; The AI follows the same conventions every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less editing:&lt;/strong&gt; Output matches your style from the first attempt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer hallucinations:&lt;/strong&gt; Explicit boundaries prevent the AI from inventing patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding:&lt;/strong&gt; New team members can use the same files to get AI help that matches your codebase.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Maintenance
&lt;/h2&gt;

&lt;p&gt;Update these files when you change conventions. I review mine monthly — it takes 5 minutes. The 15-minute setup pays for itself within two sessions.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What would you put in your context kit? I'm betting most projects need fewer than 100 lines of context to get dramatically better AI output.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Tracked Every AI Suggestion for a Week — Here's What I Actually Shipped</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Tue, 07 Apr 2026 12:02:53 +0000</pubDate>
      <link>https://dev.to/novaelvaris/i-tracked-every-ai-suggestion-for-a-week-heres-what-i-actually-shipped-5fm4</link>
      <guid>https://dev.to/novaelvaris/i-tracked-every-ai-suggestion-for-a-week-heres-what-i-actually-shipped-5fm4</guid>
      <description>&lt;p&gt;Last week I ran an experiment: I logged every AI-generated code suggestion I received and tracked which ones made it to production unchanged, which ones needed edits, and which ones I threw away entirely.&lt;/p&gt;

&lt;p&gt;The results surprised me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duration:&lt;/strong&gt; 5 working days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; Claude and GPT for code generation, Copilot for autocomplete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project:&lt;/strong&gt; A medium-sized TypeScript backend (REST API, ~40 endpoints)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracking:&lt;/strong&gt; Simple markdown file, one entry per suggestion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;Percentage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shipped unchanged&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shipped with edits&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;47%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thrown away&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total suggestions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;66&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only &lt;strong&gt;18%&lt;/strong&gt; of AI suggestions shipped without changes. Almost half needed editing. And over a third were useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Got Shipped Unchanged
&lt;/h2&gt;

&lt;p&gt;The 12 suggestions that shipped as-is had something in common: they were &lt;strong&gt;small and well-specified.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit tests for pure functions (given a clear function signature)&lt;/li&gt;
&lt;li&gt;Type definitions from a schema description&lt;/li&gt;
&lt;li&gt;Utility functions with obvious behavior (slugify, debounce, date formatting)&lt;/li&gt;
&lt;li&gt;Regex patterns with clear requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pattern: &lt;strong&gt;The more constrained the task, the better the output.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Needed Edits
&lt;/h2&gt;

&lt;p&gt;The 31 "shipped with edits" suggestions fell into predictable categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wrong error handling (14 cases):&lt;/strong&gt; AI almost always generates optimistic code. Try/catch blocks that log and continue instead of throwing. Missing null checks on database results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong abstraction level (9 cases):&lt;/strong&gt; AI tends to over-abstract. Creating a class where a function would do. Adding config options nobody asked for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subtle logic bugs (8 cases):&lt;/strong&gt; Off-by-one errors, incorrect date comparisons, missing edge cases in conditionals.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Got Thrown Away
&lt;/h2&gt;

&lt;p&gt;The 23 rejected suggestions shared patterns too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinated APIs (7 cases):&lt;/strong&gt; Functions that don't exist in the library version I'm using.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong architecture (6 cases):&lt;/strong&gt; Solutions that technically work but violate project conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overcomplicated (5 cases):&lt;/strong&gt; A 40-line solution for a 5-line problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Just wrong (5 cases):&lt;/strong&gt; Logic that doesn't match the requirement at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Real Insight
&lt;/h2&gt;

&lt;p&gt;I spent roughly &lt;strong&gt;45 minutes per day&lt;/strong&gt; on AI-assisted coding. My estimate of time saved (vs. writing everything manually): &lt;strong&gt;about 90 minutes per day.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Net gain: ~45 minutes/day, or about &lt;strong&gt;3.5 hours/week.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's real, but it's not the 10x productivity boost people claim. And it requires active review effort — the "savings" assume you catch the bugs before they ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Changed After This Experiment
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stopped using AI for complex logic.&lt;/strong&gt; If I need to think hard about the algorithm, I write it myself. AI is best for boilerplate and well-defined transformations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Started writing specs before prompting.&lt;/strong&gt; Even a 2-line spec ("takes X, returns Y, handles Z") dramatically improved the "shipped unchanged" rate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set a 3-minute rule.&lt;/strong&gt; If I'm spending more than 3 minutes editing AI output, I delete it and write from scratch. It's faster.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Track your AI suggestions for one week. Just a simple log: accepted / edited / rejected. You might be surprised how much time you're spending on the "editing" step.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your accept rate? I'd guess most developers ship less than 25% of AI output unchanged — but I'd love to see other people's data.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>The AI Pair Programming Anti-Patterns: 5 Habits That Slow You Down</title>
      <dc:creator>Nova Elvaris</dc:creator>
      <pubDate>Tue, 07 Apr 2026 11:52:40 +0000</pubDate>
      <link>https://dev.to/novaelvaris/the-ai-pair-programming-anti-patterns-5-habits-that-slow-you-down-goh</link>
      <guid>https://dev.to/novaelvaris/the-ai-pair-programming-anti-patterns-5-habits-that-slow-you-down-goh</guid>
      <description>&lt;p&gt;You’re using AI to write code. It feels fast. But is it actually saving you time?&lt;/p&gt;

&lt;p&gt;After six months of daily AI-assisted coding, I noticed five habits that &lt;em&gt;felt&lt;/em&gt; productive but were quietly eating hours. Here’s what they are and how I fixed each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The “Just Generate It” Trap
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; Asking the AI to generate an entire feature from a vague description, then spending 45 minutes fixing the output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Write a 3-sentence spec first. What does the function take? What does it return? What edge cases matter?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad prompt:&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a user authentication system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Better prompt:&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a login function that takes email + password,
returns { success: boolean, token?: string, error?: string },
and handles: invalid email format, wrong password (max 3 attempts),
and expired accounts.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time saved per task: ~20 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Context Dump
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; Pasting your entire file (or multiple files) into the prompt "for context."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Give the AI only the interface it needs. If you’re fixing a function, provide that function plus its type signatures. Not the whole module.&lt;/p&gt;

&lt;p&gt;I started using a simple rule: &lt;strong&gt;if the context is longer than the expected output, you’re overfeeding.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Infinite Iteration Loop
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; Going back and forth with the AI 8+ times, tweaking the same output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; If the third attempt isn’t close, the prompt is wrong — not the model. Stop iterating and rewrite your request from scratch.&lt;/p&gt;

&lt;p&gt;I now enforce a &lt;strong&gt;3-turn rule&lt;/strong&gt;: if I don’t have something usable after 3 exchanges, I step back and rethink the approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Review Skip
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; AI output looks right at a glance, so you commit without reading it line by line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Read every line like you’re reviewing a junior developer’s PR. AI is confident, not correct. I’ve caught subtle bugs in "perfect-looking" code that would have shipped to production.&lt;/p&gt;

&lt;p&gt;My checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are there hardcoded values that should be config?&lt;/li&gt;
&lt;li&gt;Does error handling actually handle errors (or just log and continue)?&lt;/li&gt;
&lt;li&gt;Are there imports for things that aren’t used?&lt;/li&gt;
&lt;li&gt;Does the logic match the spec, not just the happy path?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. The “AI Knows Best” Defer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; Accepting architectural suggestions from the AI because "it’s seen more code than me."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; AI optimizes for local correctness, not system coherence. It doesn’t know your deployment constraints, your team’s conventions, or why you chose that database.&lt;/p&gt;

&lt;p&gt;Use AI for implementation. Keep architecture decisions human.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Meta-Lesson
&lt;/h2&gt;

&lt;p&gt;Every anti-pattern has the same root cause: &lt;strong&gt;treating AI like a senior developer instead of a fast junior.&lt;/strong&gt; Juniors are great at writing code quickly. They’re terrible at knowing &lt;em&gt;what&lt;/em&gt; to write.&lt;/p&gt;

&lt;p&gt;Your job didn’t change. You’re still the architect, the reviewer, the one who owns the outcome. AI just made the typing faster.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Which of these habits are you guilty of? I’d bet at least two of them. Drop a comment — I’m curious which ones hurt the most.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
