<?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: Papan Sarkar</title>
    <description>The latest articles on DEV Community by Papan Sarkar (@papansarkar101).</description>
    <link>https://dev.to/papansarkar101</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F484187%2F90c599ad-5923-4126-bc31-b511f2532f3f.PNG</url>
      <title>DEV Community: Papan Sarkar</title>
      <link>https://dev.to/papansarkar101</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/papansarkar101"/>
    <language>en</language>
    <item>
      <title>The AI Productivity Paradox: More Starts, Fewer Finishes</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:30:09 +0000</pubDate>
      <link>https://dev.to/papansarkar101/the-ai-productivity-paradox-more-starts-fewer-finishes-3gk1</link>
      <guid>https://dev.to/papansarkar101/the-ai-productivity-paradox-more-starts-fewer-finishes-3gk1</guid>
      <description>&lt;p&gt;AI didn't give developers more free time. It gave us more starts.&lt;/p&gt;

&lt;p&gt;I'm a senior full-stack engineer and I use coding agents every day. Our capacity to implement ideas has grown much faster than our capacity to think them through. The numbers show it too. In Faros AI's telemetry from more than 10,000 developers, high-AI teams merged 98% more pull requests, but PR review time rose 91% and delivery at the company level didn't improve (&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I think that's the real shift, and it's a management problem, not a tooling one.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cheap implementation removed the old filter.&lt;/strong&gt; When a feature took a month, the cost made you choose. Now a prototype takes an afternoon, so nothing makes you choose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The data backs this up.&lt;/strong&gt; In Faros AI's telemetry, developers on high-AI teams touched 47% more pull requests a day, and PR review time rose 91% (&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;). A Berkeley study found that AI intensified work instead of reducing it (&lt;a href="https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it" rel="noopener noreferrer"&gt;HBR&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better tools won't fix it.&lt;/strong&gt; Google's DORA research found friction and burnout "unaffected by AI" (&lt;a href="https://jellyfish.co/blog/2025-dora-report/" rel="noopener noreferrer"&gt;Jellyfish on DORA 2025&lt;/a&gt;). A tool can't decide what's worth doing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three rules I'd protect:&lt;/strong&gt; one thing in progress per product, a written "done" before any code, and a weekly review of what to kill.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why does AI make developers busier instead of freer?
&lt;/h2&gt;

&lt;p&gt;Before coding agents, the cost of building did your prioritisation for you. If a feature took three weeks, you argued about it first. You wrote it down, cut scope and said no to the other four ideas, because you could see what they would cost. Most bad ideas died in that conversation, before anyone wrote code.&lt;/p&gt;

&lt;p&gt;That filter is gone. Starting something now costs a prompt and a coffee. Finishing it costs what it always did: review, tests, edge cases, deployment, docs, support and, above all, the decisions. Every thing you start keeps a claim on your attention. It might be an open branch, a prototype that half works, or an agent waiting for an answer.&lt;/p&gt;

&lt;p&gt;In practice it looks like this. You have three agent sessions open. None of them needs you all the time, but each one periodically needs a decision, a review or an answer. Every one of those is a context switch. A new model ships, the ideas come faster, you start more, and a few weeks later the review queue and the switching catch up with you.&lt;/p&gt;

&lt;p&gt;Simon Willison described this pattern in February. He often runs two or three projects in parallel and gets a lot done, but his mental energy is mostly gone after an hour or two (&lt;a href="https://simonwillison.net/2026/Feb/9/ai-intensifies-work/" rel="noopener noreferrer"&gt;Simon Willison&lt;/a&gt;). That isn't a complaint about the tools. It's what happens when the number of open loops goes up and the person holding them stays the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the research says about AI and workload
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The work got more intense, not smaller.&lt;/strong&gt; Aruna Ranganathan and Xingqi Maggie Ye of Berkeley Haas spent April to December 2025 studying about 200 employees at a US tech company where AI use was optional (&lt;a href="https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it" rel="noopener noreferrer"&gt;HBR&lt;/a&gt;). People took on a wider range of tasks, and work spilled into more hours of the day. Engineers spent more time reviewing and cleaning up colleagues' AI-generated output (&lt;a href="https://www.thestar.com.my/tech/tech-news/2026/02/18/ai-promised-to-save-time-researchers-find-its-doing-the-opposite" rel="noopener noreferrer"&gt;The Star, via Inc.&lt;/a&gt;). The authors describe "a growing number of open tasks" and "a sense of always juggling, even as the work felt productive" (&lt;a href="https://simonwillison.net/2026/Feb/9/ai-intensifies-work/" rel="noopener noreferrer"&gt;Simon Willison, quoting HBR&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;People produced more, but companies didn't deliver more.&lt;/strong&gt; Faros AI analysed telemetry from more than 10,000 developers across 1,255 teams (&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;). Here is what changed on teams with high AI adoption:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric (high-AI teams)&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tasks completed&lt;/td&gt;
&lt;td&gt;+21%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull requests merged&lt;/td&gt;
&lt;td&gt;+98%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tasks touched per developer per day&lt;/td&gt;
&lt;td&gt;+9%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PRs touched per developer per day&lt;/td&gt;
&lt;td&gt;+47%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR review time&lt;/td&gt;
&lt;td&gt;+91%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average PR size&lt;/td&gt;
&lt;td&gt;+154%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bugs per developer&lt;/td&gt;
&lt;td&gt;+9%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Faros's conclusion: "no significant correlation between AI adoption and improvements at the company level" (&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;). Read the table as one story. People started more, touched more and opened bigger changes. Then all of it queued up for the same few reviewers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This was visible before agents.&lt;/strong&gt; In 2024, 77% of employees who use AI told the Upwork Research Institute the tools had added to their workload, and 39% pointed to time spent reviewing or moderating AI content (&lt;a href="https://www.upwork.com/press/releases/upwork-study-finds-employee-workloads-rising-despite-increased-c-suite-investment-in-artificial-intelligence" rel="noopener noreferrer"&gt;Upwork&lt;/a&gt;). In Atlassian's 2025 survey of 3,500 developers and managers, 68% said AI saved them more than 10 hours a week, while 50% lost 10 or more hours a week, mostly to organisational inefficiency (&lt;a href="https://www.atlassian.com/blog/developer/developer-experience-report-2025" rel="noopener noreferrer"&gt;Atlassian&lt;/a&gt;). Saving time on typing doesn't help if the system around you can't take in what you produce.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switching costs aren't new either.&lt;/strong&gt; Gerald Weinberg's rule of thumb, as Johanna Rothman summarised it: a person on two tasks spends about 40% of their time on each and wastes 20%, and a person on four tasks spends 10% on each and wastes 60% (&lt;a href="https://ayeconference.com/multiprojecting-the-illusion-of-progress.html" rel="noopener noreferrer"&gt;Rothman&lt;/a&gt;). Weinberg meant those as estimates, not measurements. A 2017 study in an educational setting measured a smaller but real cost: developers on two or more projects spent about 17% of their effort on cross-project interruptions (&lt;a href="https://neverworkintheory.org/2021/09/19/impact-of-task-switching-and-work-interruptions.html" rel="noopener noreferrer"&gt;Tregubov et al., via Never Work in Theory&lt;/a&gt;). Gloria Mark's lab found that interrupted people work faster to compensate, but report more stress, frustration and time pressure (&lt;a href="https://www.ics.uci.edu/~gmark/chi08-mark.pdf" rel="noopener noreferrer"&gt;Mark et al., CHI 2008&lt;/a&gt;). That describes running five agents at once pretty well.&lt;/p&gt;

&lt;h2&gt;
  
  
  The case that this is fine
&lt;/h2&gt;

&lt;p&gt;I want to be fair to the other side. The 2025 DORA findings are more positive than the anecdotes. Individual effectiveness rose the most with AI adoption, throughput and time on valuable work improved, and burnout didn't get worse on average (&lt;a href="https://jellyfish.co/blog/2025-dora-report/" rel="noopener noreferrer"&gt;Jellyfish on DORA 2025&lt;/a&gt;). I'll add my own experience: the work is more fun without the boilerplate.&lt;/p&gt;

&lt;p&gt;I agree with all of that, and it supports my point. DORA's headline is that AI is "an amplifier," magnifying an organisation's existing strengths and weaknesses (&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA 2025&lt;/a&gt;). If you already had a filter, AI makes you faster at the things that pass it. If cost was your only filter, AI took it away and gave you nothing in its place.&lt;/p&gt;

&lt;p&gt;DORA's own follow-up says this plainly. Two of its seven AI capabilities are working in small batches and keeping a user-centric focus. As DORA puts it, "Speed is irrelevant if you are moving in the wrong direction" (&lt;a href="https://cloud.google.com/blog/products/ai-machine-learning/from-adoption-to-impact-putting-the-dora-ai-capabilities-model-to-work" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  It's a management problem, not a tooling one
&lt;/h2&gt;

&lt;p&gt;The common response to "I'm drowning in agent output" is more tooling: an orchestrator, a dashboard of sessions, an agent that manages your agents. Every one of those makes starting even cheaper, so you end up with more starts.&lt;/p&gt;

&lt;p&gt;What's scarce is attention and judgement, so manage them the way teams have always managed scarce capacity: limit work in progress. The Kanban Guide's rule is that you "must explicitly control the number of work items in a workflow from started to finished" (&lt;a href="https://kanbanguides.org/english/" rel="noopener noreferrer"&gt;Kanban Guide&lt;/a&gt;). Basecamp's Shape Up makes the same point about scope: "Estimates start with a design and end with a number. Appetites start with a number and end with a design" (&lt;a href="https://basecamp.com/shapeup/1.2-chapter-03" rel="noopener noreferrer"&gt;Shape Up, ch. 3&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Here's how I think about it. For years, the cost of building did three jobs we never had to do on purpose. Now each one needs a rule.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the cost of building used to do&lt;/th&gt;
&lt;th&gt;What it looks like now&lt;/th&gt;
&lt;th&gt;The rule that replaces it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Forced you to pick one idea&lt;/td&gt;
&lt;td&gt;Five prototypes in a week&lt;/td&gt;
&lt;td&gt;One thing in progress per product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forced you to think before building&lt;/td&gt;
&lt;td&gt;The agent builds before you've decided&lt;/td&gt;
&lt;td&gt;A written "done" before any code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Killed weak ideas before they started&lt;/td&gt;
&lt;td&gt;Weak ideas live on as stale branches&lt;/td&gt;
&lt;td&gt;A weekly review of what to kill&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Rule 1: One thing in progress per product
&lt;/h2&gt;

&lt;p&gt;"In progress" means it has a branch, an agent session waiting on you, or a PR that isn't merged. Each product gets one of those at a time. It's one per product, not one per person, because most of us (me included) work across several codebases. The point is that every product has a single lane.&lt;/p&gt;

&lt;p&gt;Agents can still run in parallel inside that lane. One writes tests, one drafts the migration and one updates the docs, all for the same feature. What the rule stops is five agents building five different features that all land on your review queue on Thursday.&lt;/p&gt;

&lt;p&gt;New ideas go on a list, not into a branch. A list costs nothing to keep. A branch costs attention every time you see it.&lt;/p&gt;

&lt;p&gt;There are two exceptions. A production incident overrides everything. A spike (a short experiment to answer a question) is allowed, but it gets a time box, a label, and by default it's thrown away when the time runs out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 2: A written "done" before any code
&lt;/h2&gt;

&lt;p&gt;Two lines is enough. If you can't write them, you don't understand the work yet, and an agent will happily build the wrong thing very fast. This is the thinking that the cost of building used to force on you. Now you have to do it on purpose.&lt;/p&gt;

&lt;p&gt;I keep a short file at the root of the branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# DONE.md: checkout-retry
Done when: a failed card payment retries once after 24 hours and the
           customer gets exactly one email, not three.
Not doing: dunning sequences, SMS, admin UI changes.
Appetite: 2 days. Not merged by Friday = cut scope or kill it. No extensions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Not doing" is the line that matters most. It keeps the agent from gold-plating, and it keeps me from "while I'm in here" detours. The "Done when" line goes straight into the agent prompt, which is the same habit I covered in &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;Use AI Coding Agents Like a Pro&lt;/a&gt;. The appetite line comes from Shape Up: you decide how much the work is worth before you see the design.&lt;/p&gt;

&lt;p&gt;Do the thinking away from the LLM. Write the done on paper or in a plain file before you open the agent. Once a chat session is open, it pulls you toward starting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 3: A weekly look at what you started and should kill
&lt;/h2&gt;

&lt;p&gt;Every Friday I spend 20 minutes listing everything open: branches, draft PRs, prototypes, agent threads, and anything I called a "quick experiment". Each item gets one of three verdicts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Finish it next week.&lt;/strong&gt; It moves to the single in-progress slot, or waits for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Park it.&lt;/strong&gt; Write one paragraph on what you learned, then delete the branch. The paragraph is what you were actually keeping anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kill it.&lt;/strong&gt; This is the default.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The default comes from Shape Up's "circuit breaker": "If they don't finish, by default the project doesn't get an extension" (&lt;a href="https://basecamp.com/shapeup/2.2-chapter-08" rel="noopener noreferrer"&gt;Shape Up, ch. 8&lt;/a&gt;). Basecamp's reasoning is that one runaway project should never freeze newer projects that could matter more. With AI that matters even more, because restarting is cheap. A killed idea that turns out to be good costs you an afternoon to rebuild, and it'll be better the second time because you'll write the done first.&lt;/p&gt;

&lt;p&gt;To get the list, I run this in each repo:&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;# Local branches with no commits in the last 7 days, oldest first&lt;/span&gt;
git &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="nt"&gt;-each-ref&lt;/span&gt; &lt;span class="nt"&gt;--sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;committerdate refs/heads/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%(committerdate:short) %(refname:short)'&lt;/span&gt; |
  &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;cutoff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-v-7d&lt;/span&gt; +%F 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'7 days ago'&lt;/span&gt; +%F&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'$1 &amp;lt; cutoff'&lt;/span&gt;

&lt;span class="c"&gt;# Your open pull requests (GitHub CLI)&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--author&lt;/span&gt; &lt;span class="s2"&gt;"@me"&lt;/span&gt; &lt;span class="nt"&gt;--state&lt;/span&gt; open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;date&lt;/code&gt; fallback covers both macOS and Linux. Anything that shows up two Fridays in a row doesn't get a third.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you start the next thing
&lt;/h2&gt;

&lt;p&gt;Ask yourself these before you open a new branch or agent session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is something already in progress on this product? Finish it or kill it first.&lt;/li&gt;
&lt;li&gt;Can I write "done when" in two lines, with a "not doing" line?&lt;/li&gt;
&lt;li&gt;What's the appetite, and what happens when it runs out?&lt;/li&gt;
&lt;li&gt;Who reviews this, and do they have room this week?&lt;/li&gt;
&lt;li&gt;If this took a month instead of an afternoon, would I still build it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last question is my favourite. It puts back the filter that cost used to provide, without the cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;AI made implementation cheap and left judgement as expensive as ever. If you don't decide what not to build, you end up with a pile of half-finished work and a tired team. Shipping fast still matters, but speed without a filter just turns into a longer to-do list.&lt;/p&gt;

&lt;p&gt;If you're a founder planning an MVP and you want speed that turns into shipped features, this is how I run my projects: one lane per product, a written done for every feature, and a weekly cut. I build React/Next.js and Node.js products for clients. &lt;a href="https://papansarkar.com/contact/" rel="noopener noreferrer"&gt;Get in touch&lt;/a&gt;. If you're a developer, the agent-side habits are in &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;Use AI Coding Agents Like a Pro&lt;/a&gt;, and my two-agent review loop is in &lt;a href="https://papansarkar.com/blog/claude-code-vs-codex-use-both/" rel="noopener noreferrer"&gt;Claude Code vs Codex: How I Use Both on One Repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI: The AI Productivity Paradox Research Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hbr.org/2026/02/ai-doesnt-reduce-work-it-intensifies-it" rel="noopener noreferrer"&gt;Harvard Business Review: AI Doesn't Reduce Work—It Intensifies It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2026/Feb/9/ai-intensifies-work/" rel="noopener noreferrer"&gt;Simon Willison: AI intensifies work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.thestar.com.my/tech/tech-news/2026/02/18/ai-promised-to-save-time-researchers-find-its-doing-the-opposite" rel="noopener noreferrer"&gt;The Star (Inc./TNS): AI promised to save time. Researchers find it's doing the opposite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.upwork.com/press/releases/upwork-study-finds-employee-workloads-rising-despite-increased-c-suite-investment-in-artificial-intelligence" rel="noopener noreferrer"&gt;Upwork: Employee workloads rising despite C-suite investment in AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/blog/developer/developer-experience-report-2025" rel="noopener noreferrer"&gt;Atlassian: State of Developer Experience 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA: 2025 State of AI-assisted Software Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jellyfish.co/blog/2025-dora-report/" rel="noopener noreferrer"&gt;Jellyfish: AI as Amplifier, the 2025 DORA Report with Nathen Harvey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/blog/products/ai-machine-learning/from-adoption-to-impact-putting-the-dora-ai-capabilities-model-to-work" rel="noopener noreferrer"&gt;Google Cloud: Putting the DORA AI Capabilities Model to work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kanbanguides.org/english/" rel="noopener noreferrer"&gt;The Kanban Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://basecamp.com/shapeup/1.2-chapter-03" rel="noopener noreferrer"&gt;Shape Up, Chapter 3: Set Boundaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://basecamp.com/shapeup/2.2-chapter-08" rel="noopener noreferrer"&gt;Shape Up, Chapter 8: The Betting Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ayeconference.com/multiprojecting-the-illusion-of-progress.html" rel="noopener noreferrer"&gt;Johanna Rothman: Multiprojecting, the Illusion of Progress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neverworkintheory.org/2021/09/19/impact-of-task-switching-and-work-interruptions.html" rel="noopener noreferrer"&gt;Never Work in Theory: Impact of Task Switching and Work Interruptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ics.uci.edu/~gmark/chi08-mark.pdf" rel="noopener noreferrer"&gt;Mark, Gudith and Klocke: The Cost of Interrupted Work, CHI 2008&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://papansarkar.com/blog/ai-productivity-paradox-more-starts/" rel="noopener noreferrer"&gt;papansarkar.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Claude Code vs Codex: How I Use Both on One Repo</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:10:04 +0000</pubDate>
      <link>https://dev.to/papansarkar101/claude-code-vs-codex-how-i-use-both-on-one-repo-57gh</link>
      <guid>https://dev.to/papansarkar101/claude-code-vs-codex-how-i-use-both-on-one-repo-57gh</guid>
      <description>&lt;p&gt;Claude Code leads the coding-agent tools in Stack Overflow's 2026 survey at 66%, ahead of GitHub Copilot at 59% (&lt;a href="https://survey.stackoverflow.co/2026/ai" rel="noopener noreferrer"&gt;Stack Overflow 2026&lt;/a&gt;). Codex passed 5 million weekly active users in June, by OpenAI's own count (&lt;a href="https://constellationr.com/insights/news/openai-touts-broadening-codex-usage-5-million-weekly-active-users" rel="noopener noreferrer"&gt;Constellation Research&lt;/a&gt;). Most "Claude Code vs Codex" posts try to name a winner. I run both on the same repo, and I've found it more useful to ask which job goes to which agent, and how to keep the two from drifting apart.&lt;/p&gt;

&lt;p&gt;This post covers what each tool does better as of late October 2026, one instruction file both of them read, and the loop where one agent writes and the other reviews. The general habits (context, prompts, model choice) are in &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;Use AI Coding Agents Like a Pro&lt;/a&gt;, so I won't repeat them here.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same entry price, different defaults.&lt;/strong&gt; Both are included in their vendor's $20/month individual plan (&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;, &lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;Codex pricing&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code drives my interactive work.&lt;/strong&gt; You can switch permission modes mid-session, hooks enforce hard rules, and its review runs in the background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex is my second opinion and my scripted worker.&lt;/strong&gt; It sandboxes at the OS level by default, its scripted mode starts read-only, and its GitHub reviews flag only P0 and P1 issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One AGENTS.md serves both.&lt;/strong&gt; Codex reads it natively. Claude Code reads it too, or imports it from CLAUDE.md with one line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have the agent that didn't write the code review it.&lt;/strong&gt; Models favour their own output, and that bias does the most damage when the model got it wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Claude Code vs Codex at a glance
&lt;/h2&gt;

&lt;p&gt;I checked every row against both vendors' docs on 30 October 2026. Both products ship changes weekly, so confirm a detail on the linked page before you rely on it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;th&gt;Codex&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;Terminal, VS Code, JetBrains, desktop app, web (&lt;a href="https://code.claude.com/docs/en/overview" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;CLI, IDE extension, ChatGPT desktop, web and mobile, Codex Cloud (&lt;a href="https://learn.chatgpt.com/docs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cheapest plan with it&lt;/td&gt;
&lt;td&gt;Pro: $20/month, or $17/month billed annually (&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Included from ChatGPT Free upward; Go is $8/month, Plus $20/month (&lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy-use tier&lt;/td&gt;
&lt;td&gt;Max, from $100/month (&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Pro, from $100/month, currently with no five-hour limit (&lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruction file&lt;/td&gt;
&lt;td&gt;CLAUDE.md; reads AGENTS.md if there's no CLAUDE.md (&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;AGENTS.md, merged from the repo root down to your folder (&lt;a href="https://learn.chatgpt.com/docs/agent-configuration/agents-md" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safety default&lt;/td&gt;
&lt;td&gt;Auto mode, where a classifier checks actions; the OS-level Bash sandbox is opt-in (&lt;a href="https://code.claude.com/docs/en/permission-modes" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;OS-level sandbox in &lt;code&gt;workspace-write&lt;/code&gt; mode (&lt;a href="https://learn.chatgpt.com/docs/sandboxing" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scripted mode&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;claude -p&lt;/code&gt; (&lt;a href="https://code.claude.com/docs/en/headless" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;codex exec&lt;/code&gt;, read-only by default (&lt;a href="https://learn.chatgpt.com/docs/non-interactive-mode" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local review&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/code-review&lt;/code&gt;, on any plan (&lt;a href="https://code.claude.com/docs/en/code-review-local" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/review&lt;/code&gt;, or &lt;code&gt;codex review --base main&lt;/code&gt; (&lt;a href="https://learn.chatgpt.com/docs/code-review" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub PR review&lt;/td&gt;
&lt;td&gt;Managed Code Review, Team and Enterprise plans only (&lt;a href="https://code.claude.com/docs/en/code-review" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@codex review&lt;/code&gt; or automatic reviews (&lt;a href="https://learn.chatgpt.com/docs/third-party/github" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;CLI is Apache-2.0 (&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I left benchmark scores and model names out on purpose. Both lineups have changed several times this year, and published comparisons disagree with each other by wide margins. Test both on a real ticket from your own codebase instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Both are safe bets now
&lt;/h2&gt;

&lt;p&gt;If you're a founder or CTO deciding which one your team should pay for, the market data says neither is a fringe pick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;73% of respondents in Stack Overflow's 2026 survey use coding assistants and agents daily (&lt;a href="https://survey.stackoverflow.co/2026/ai" rel="noopener noreferrer"&gt;Stack Overflow 2026&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Anthropic said in February that Claude Code's run-rate revenue had passed $2.5 billion and that weekly users had doubled since January 1 (&lt;a href="https://www.anthropic.com/news/anthropic-raises-30-billion-series-g-funding-380-billion-post-money-valuation" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;OpenAI said in June that Codex had more than 5 million weekly active users, up more than 6x since its desktop app launched in February (&lt;a href="https://constellationr.com/insights/news/openai-touts-broadening-codex-usage-5-million-weekly-active-users" rel="noopener noreferrer"&gt;Constellation Research&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The open-source Codex CLI repo has more than 130,000 GitHub stars (&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both companies report their own numbers, and they measure different things (revenue versus weekly users), so don't read them as a head-to-head. The point is simpler: both tools will be around, so choose by how your team works, not by which vendor might fold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Claude Code wins for me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Steering while it works.&lt;/strong&gt; &lt;code&gt;Shift+Tab&lt;/code&gt; cycles permission modes mid-session: manual approval, auto-accept edits, and plan (&lt;a href="https://code.claude.com/docs/en/permission-modes" rel="noopener noreferrer"&gt;permission modes&lt;/a&gt;). On code I don't know yet, I start in plan mode, read the plan, then let it edit. That back-and-forth is where Claude Code feels best.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules that are actually enforced.&lt;/strong&gt; An instruction file is a suggestion. Anthropic's docs say it plainly: Claude treats CLAUDE.md "as context, not enforced configuration," and to block an action no matter what, you use a PreToolUse hook (&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;memory docs&lt;/a&gt;). "Never edit the migrations folder" belongs in a hook, not in a paragraph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review that doesn't flood the session.&lt;/strong&gt; &lt;code&gt;/code-review&lt;/code&gt; runs as a background subagent with its own context window, so the findings arrive without filling your conversation (&lt;a href="https://code.claude.com/docs/en/code-review-local" rel="noopener noreferrer"&gt;code review docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One config across surfaces.&lt;/strong&gt; The terminal, IDE, desktop and web surfaces share one engine, so the same CLAUDE.md, settings and MCP servers work in all of them (&lt;a href="https://code.claude.com/docs/en/overview" rel="noopener noreferrer"&gt;overview&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Codex wins for me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sandbox first.&lt;/strong&gt; Codex enforces its sandbox at the OS level: Seatbelt on macOS, bubblewrap on Linux and WSL2, and a native sandbox on Windows. The default mode lets it edit files and run routine commands inside the workspace, and nothing outside it (&lt;a href="https://learn.chatgpt.com/docs/sandboxing" rel="noopener noreferrer"&gt;sandboxing&lt;/a&gt;). Since I was handed a Next.js repo &lt;a href="https://papansarkar.com/blog/npm-malware-hidden-in-tailwind-config/" rel="noopener noreferrer"&gt;wired to run malware on every &lt;code&gt;npm run dev&lt;/code&gt;&lt;/a&gt;, I want an agent that runs unfamiliar code inside an OS boundary from the start. Claude Code can do this too with &lt;code&gt;/sandbox&lt;/code&gt;; it just doesn't start that way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safe scripting by default.&lt;/strong&gt; &lt;code&gt;codex exec&lt;/code&gt; starts in a read-only sandbox unless you pass &lt;code&gt;--sandbox workspace-write&lt;/code&gt;, and &lt;code&gt;--output-schema&lt;/code&gt; makes it return JSON that matches a schema you give it (&lt;a href="https://learn.chatgpt.com/docs/non-interactive-mode" rel="noopener noreferrer"&gt;non-interactive mode&lt;/a&gt;). That makes it a good fit for CI jobs like triage reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quiet PR reviews.&lt;/strong&gt; On GitHub, Codex flags only P0 and P1 issues (&lt;a href="https://learn.chatgpt.com/docs/third-party/github" rel="noopener noreferrer"&gt;Codex GitHub docs&lt;/a&gt;). Reviews with less noise are reviews people actually read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A cheap way in for teams already on ChatGPT.&lt;/strong&gt; Every ChatGPT plan from Free upward includes Codex, and Business costs $25 per user per month billed monthly (&lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;Codex pricing&lt;/a&gt;). If a client's team already pays for ChatGPT Business, trying Codex costs them nothing extra.&lt;/p&gt;

&lt;h2&gt;
  
  
  One AGENTS.md for both agents
&lt;/h2&gt;

&lt;p&gt;The fastest way to get inconsistent code from two agents is to give them two sets of rules. You don't need two copies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Codex reads &lt;code&gt;AGENTS.md&lt;/code&gt; files from the repo root down to your working folder, one file per folder. Files closer to you override earlier ones, and the combined size caps at 32 KiB by default (&lt;a href="https://learn.chatgpt.com/docs/agent-configuration/agents-md" rel="noopener noreferrer"&gt;Codex AGENTS.md docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Claude Code reads &lt;code&gt;AGENTS.md&lt;/code&gt; when there is no &lt;code&gt;CLAUDE.md&lt;/code&gt;. If both exist, it reads &lt;strong&gt;only&lt;/strong&gt; &lt;code&gt;CLAUDE.md&lt;/code&gt;, unless &lt;code&gt;CLAUDE.md&lt;/code&gt; imports the other file (&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;Claude Code memory docs&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That second rule is how most repos drift: someone adds a &lt;code&gt;CLAUDE.md&lt;/code&gt; and Claude quietly stops reading the shared rules. My setup keeps &lt;code&gt;AGENTS.md&lt;/code&gt; as the source of truth and makes &lt;code&gt;CLAUDE.md&lt;/code&gt; a thin wrapper.&lt;/p&gt;

&lt;p&gt;The shape of a good &lt;code&gt;AGENTS.md&lt;/code&gt; (commands, non-obvious conventions, "done means") is in &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;my habits post&lt;/a&gt;. The part that matters for two agents is a review section. Codex's GitHub reviews look for a &lt;code&gt;## Code Review Rules&lt;/code&gt; heading in the nearest &lt;code&gt;AGENTS.md&lt;/code&gt; (&lt;a href="https://learn.chatgpt.com/docs/third-party/github" rel="noopener noreferrer"&gt;Codex GitHub docs&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Code Review Rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Flag any API route that skips the auth middleware
&lt;span class="p"&gt;-&lt;/span&gt; Flag money math done in floats; amounts are integer cents
&lt;span class="p"&gt;-&lt;/span&gt; Flag new env vars that aren't added to src/env.ts
&lt;span class="p"&gt;-&lt;/span&gt; Ignore formatting and import order; the linter owns those
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the whole &lt;code&gt;CLAUDE.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;@AGENTS.md

&lt;span class="gu"&gt;## Claude Code only&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; For schema changes, use the /db-migration skill instead of editing models by hand
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude reads the imported file first, then the lines below it (&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;memory docs&lt;/a&gt;). The import also works on older Claude Code versions that can't read &lt;code&gt;AGENTS.md&lt;/code&gt; directly. Claude's &lt;code&gt;/code-review&lt;/code&gt; follows your &lt;code&gt;CLAUDE.md&lt;/code&gt; (&lt;a href="https://code.claude.com/docs/en/code-review-local" rel="noopener noreferrer"&gt;docs&lt;/a&gt;), so with the import, both reviewers check the same rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop: one agent writes, the other reviews
&lt;/h2&gt;

&lt;p&gt;In the habits post I argued for reviewing in a fresh context. Here I go one step further and use a different vendor's model.&lt;/p&gt;

&lt;p&gt;The research reason: Panickssery, Bowman and Feng found that LLM evaluators recognise and favour their own outputs, and that the stronger the self-recognition, the stronger the bias (&lt;a href="https://arxiv.org/abs/2404.13076" rel="noopener noreferrer"&gt;arXiv 2404.13076&lt;/a&gt;). A 2025 follow-up complicates this. For stronger models, most of that self-preference turned out to be justified, because their answers really were better. The harmful kind persisted when the model was wrong, and "stronger models struggle more to recognize when they are wrong" (&lt;a href="https://arxiv.org/abs/2504.03846" rel="noopener noreferrer"&gt;arXiv 2504.03846&lt;/a&gt;). You need a review for exactly the times the writer is wrong. Neither paper tested coding agents reviewing diffs, so take this as a good reason to try the loop, not as proof that it works.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code writes&lt;/strong&gt; the feature on a branch, interactively, starting in plan mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheap checks run first.&lt;/strong&gt; Typecheck and tests. An agent review is not a test suite, and I don't pay an agent to find type errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex reviews the branch&lt;/strong&gt; against &lt;code&gt;main&lt;/code&gt; without changing the working tree (&lt;a href="https://learn.chatgpt.com/docs/code-review" rel="noopener noreferrer"&gt;Codex code review&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The findings go back to Claude&lt;/strong&gt; with a triage prompt (below).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swap roles&lt;/strong&gt; when Codex wrote the branch: Claude's &lt;code&gt;/code-review&lt;/code&gt; runs non-interactively with &lt;code&gt;claude -p&lt;/code&gt; (&lt;a href="https://code.claude.com/docs/en/headless" rel="noopener noreferrer"&gt;headless docs&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The script I keep in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Usage: scripts/cross-review.sh [codex|claude] [base-branch]&lt;/span&gt;
&lt;span class="c"&gt;# Ask the agent that did NOT write this branch to review it. Neither command edits files.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;reviewer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;codex&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Cheap checks first; an agent review is not a test suite.&lt;/span&gt;
pnpm tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
pnpm vitest run

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$reviewer&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in
  &lt;/span&gt;codex&lt;span class="p"&gt;)&lt;/span&gt;
    codex review &lt;span class="nt"&gt;--base&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;;;&lt;/span&gt;
  claude&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# dontAsk denies anything that would need approval, so the review can read but not write.&lt;/span&gt;
    claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"/code-review &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...HEAD"&lt;/span&gt; &lt;span class="nt"&gt;--permission-mode&lt;/span&gt; dontAsk
    &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"reviewer must be codex or claude"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;codex review&lt;/code&gt; takes exactly one target: &lt;code&gt;--base&lt;/code&gt;, &lt;code&gt;--commit&lt;/code&gt;, &lt;code&gt;--uncommitted&lt;/code&gt;, or a custom prompt (&lt;a href="https://learn.chatgpt.com/docs/developer-commands?surface=cli" rel="noopener noreferrer"&gt;Codex CLI reference&lt;/a&gt;). On the Claude side, &lt;code&gt;dontAsk&lt;/code&gt; mode denies every call that would otherwise prompt, but reads and read-only commands still run (&lt;a href="https://code.claude.com/docs/en/headless" rel="noopener noreferrer"&gt;headless docs&lt;/a&gt;). Without &lt;code&gt;--fix&lt;/code&gt;, &lt;code&gt;/code-review&lt;/code&gt; only reports.&lt;/p&gt;

&lt;p&gt;The triage prompt I paste into the writing agent with the findings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Another reviewer flagged the issues below on this branch.
For each one, either fix it or reply in one line explaining why it is not a bug.
Don't change code the findings don't mention.
When you're done, run the typecheck and tests and show me the output.

&amp;lt;findings&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "explain why it isn't a bug" clause is what makes this work. Without it, the writer accepts every finding and the code bloats. With it, I read a short list of rejections and make the call myself.&lt;/p&gt;

&lt;p&gt;On GitHub, the same idea applies at team scale. Claude's managed Code Review starts with an &lt;code&gt;@claude review&lt;/code&gt; comment (&lt;a href="https://code.claude.com/docs/en/code-review" rel="noopener noreferrer"&gt;Claude Code Review&lt;/a&gt;), and Codex starts with &lt;code&gt;@codex review&lt;/code&gt; (&lt;a href="https://learn.chatgpt.com/docs/third-party/github" rel="noopener noreferrer"&gt;Codex GitHub docs&lt;/a&gt;). Don't turn both on for every PR. That doubles the noise. Ask for a review from the agent that didn't write the PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which agent for which job
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;My first pick&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;Exploring code I don't know yet&lt;/td&gt;
&lt;td&gt;Claude Code in plan mode&lt;/td&gt;
&lt;td&gt;Reads and plans before any edit; &lt;code&gt;Shift+Tab&lt;/code&gt; to switch modes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feature work I want to steer&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Mode switching, hooks for hard rules, background review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Running an unfamiliar repo or script&lt;/td&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;OS-level sandbox from the first command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI jobs: triage, reports, lint fixes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;codex exec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read-only by default; schema-checked JSON output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A well-scoped ticket I want back as a PR&lt;/td&gt;
&lt;td&gt;Either&lt;/td&gt;
&lt;td&gt;Both run tasks in the cloud: Codex Cloud and Claude Code on the web&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second-opinion review&lt;/td&gt;
&lt;td&gt;Whichever didn't write it&lt;/td&gt;
&lt;td&gt;Different model, different blind spots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team PR review on GitHub&lt;/td&gt;
&lt;td&gt;The one you already pay for&lt;/td&gt;
&lt;td&gt;Claude Code Review needs a Team or Enterprise plan; Codex reviews run through the ChatGPT Codex connector&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What running both costs
&lt;/h2&gt;

&lt;p&gt;At entry level, Claude Pro plus ChatGPT Plus comes to $40 per developer per month, or $37 with Claude billed annually (&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;, &lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;Codex pricing&lt;/a&gt;). Heavy users hit limits sooner, and both vendors' next tier starts at $100 a month (&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;, &lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;Codex pricing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The cost that matters more for client work is data. Running two agents means two vendors see the code. Codex Cloud and Claude Code on the web run on vendor infrastructure, and Claude's managed Code Review isn't available to organisations with Zero Data Retention enabled (&lt;a href="https://code.claude.com/docs/en/code-review" rel="noopener noreferrer"&gt;Claude Code Review&lt;/a&gt;). Check the client's contract before you add a second vendor, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I don't bother with two agents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small, obvious changes.&lt;/strong&gt; If I can describe the diff in one sentence, one agent and the test suite are enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No tests.&lt;/strong&gt; Two agents agreeing is not verification. In Stack Overflow's 2026 survey, 48% of respondents said they trust AI when they can easily validate its answers (&lt;a href="https://survey.stackoverflow.co/2026/ai" rel="noopener noreferrer"&gt;Stack Overflow 2026&lt;/a&gt;). Make validation easy first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code the client won't share with a second vendor.&lt;/strong&gt; Use one agent and a fresh-context review from that same vendor. My reading of the 2025 self-preference paper is that this gets you most of the benefit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Pick one agent to drive and use the other as the reviewer. Keep &lt;code&gt;AGENTS.md&lt;/code&gt; as the single source of truth, run your tests before any agent review, and make the writing agent justify every finding it rejects.&lt;/p&gt;

&lt;p&gt;If you're planning a product and want it built with this kind of review loop, I build React/Next.js and Node.js products for clients. &lt;a href="https://papansarkar.com/contact/" rel="noopener noreferrer"&gt;Get in touch&lt;/a&gt;. To keep either agent accurate and cheap, start with &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;Use AI Coding Agents Like a Pro&lt;/a&gt;. If you're on Copilot, see &lt;a href="https://papansarkar.com/blog/using-ai-agents-in-vscode/" rel="noopener noreferrer"&gt;Using AI Agents in VS Code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://survey.stackoverflow.co/2026/ai" rel="noopener noreferrer"&gt;Stack Overflow Developer Survey 2026: AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://constellationr.com/insights/news/openai-touts-broadening-codex-usage-5-million-weekly-active-users" rel="noopener noreferrer"&gt;Constellation Research: OpenAI touts broadening Codex usage with 5 million weekly active users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/news/anthropic-raises-30-billion-series-g-funding-380-billion-post-money-valuation" rel="noopener noreferrer"&gt;Anthropic: Series G announcement (Claude Code run-rate revenue)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;GitHub: openai/codex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/pricing" rel="noopener noreferrer"&gt;Codex docs: Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/overview" rel="noopener noreferrer"&gt;Claude Code docs: Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/permission-modes" rel="noopener noreferrer"&gt;Claude Code docs: Permission modes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;Claude Code docs: How Claude remembers your project (CLAUDE.md and AGENTS.md)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/headless" rel="noopener noreferrer"&gt;Claude Code docs: Run Claude Code programmatically&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/code-review-local" rel="noopener noreferrer"&gt;Claude Code docs: Review locally with /code-review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/code-review" rel="noopener noreferrer"&gt;Claude Code docs: Code Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs" rel="noopener noreferrer"&gt;Codex docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/sandboxing" rel="noopener noreferrer"&gt;Codex docs: Sandboxing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/non-interactive-mode" rel="noopener noreferrer"&gt;Codex docs: Non-interactive mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/code-review" rel="noopener noreferrer"&gt;Codex docs: Code review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/developer-commands?surface=cli" rel="noopener noreferrer"&gt;Codex docs: Command line options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/third-party/github" rel="noopener noreferrer"&gt;Codex docs: Use Codex in GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/agent-configuration/agents-md" rel="noopener noreferrer"&gt;Codex docs: Custom instructions with AGENTS.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2404.13076" rel="noopener noreferrer"&gt;Panickssery, Bowman and Feng: LLM Evaluators Recognize and Favor Their Own Generations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2504.03846" rel="noopener noreferrer"&gt;Chen et al.: Do LLM Evaluators Prefer Themselves for a Reason?&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://papansarkar.com/blog/claude-code-vs-codex-use-both/" rel="noopener noreferrer"&gt;papansarkar.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Use AI Coding Agents Like a Pro: Fewer Tokens, Better Code</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Sun, 01 Nov 2026 11:07:32 +0000</pubDate>
      <link>https://dev.to/papansarkar101/use-ai-coding-agents-like-a-pro-fewer-tokens-better-code-4j36</link>
      <guid>https://dev.to/papansarkar101/use-ai-coding-agents-like-a-pro-fewer-tokens-better-code-4j36</guid>
      <description>&lt;p&gt;Most developers who complain that coding agents are expensive and sloppy are making the same mistake: they treat the agent like a chat window and let one session grow all day. In the &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;2025 Stack Overflow survey&lt;/a&gt;, 66% of developers named "AI solutions that are almost right, but not quite" as their top frustration. In my experience, "almost right" and "expensive" usually have the same root cause: too much of the wrong context.&lt;/p&gt;

&lt;p&gt;This post is the workflow I use across Claude Code, OpenAI Codex, Cursor and GitHub Copilot. It is tool-agnostic on purpose. If you want the VS Code setup walkthrough, I covered that in &lt;a href="https://papansarkar.com/blog/using-ai-agents-in-vscode/" rel="noopener noreferrer"&gt;Using AI Agents in VS Code&lt;/a&gt;. This one is about habits.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context is the budget, not the prompt.&lt;/strong&gt; Every turn re-sends the whole conversation, so a bloated session costs more and gets dumber at the same time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One task per session.&lt;/strong&gt; Clear between unrelated tasks. After two failed corrections, start over with a better prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep your instruction file short.&lt;/strong&gt; AGENTS.md / CLAUDE.md should hold only what the agent can't figure out from the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give the agent a check it can run.&lt;/strong&gt; Tests, a build, a linter. Without one, you are the test suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push noisy work out of the main context.&lt;/strong&gt; Subagents, filtered command output, CLI tools instead of piles of MCP servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match the model and reasoning effort to the task.&lt;/strong&gt; The biggest model on every typo fix is how bills explode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why context is the whole game
&lt;/h2&gt;

&lt;p&gt;Three pieces of research explain almost every agent failure I see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance drops as context grows.&lt;/strong&gt; Chroma tested 18 models and found that "performance grows increasingly unreliable as input length grows," even on simple retrieval tasks (&lt;a href="https://www.trychroma.com/research/context-rot" rel="noopener noreferrer"&gt;Chroma, Context Rot&lt;/a&gt;). In one test, models did much better on focused prompts of about 300 tokens than on the full 113k-token version (&lt;a href="https://www.trychroma.com/research/context-rot" rel="noopener noreferrer"&gt;Chroma&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Position matters.&lt;/strong&gt; The "Lost in the Middle" paper showed models use information at the start and end of a long context better than information buried in the middle (&lt;a href="https://arxiv.org/abs/2307.03172" rel="noopener noreferrer"&gt;Liu et al., TACL&lt;/a&gt;). Your carefully written rule from 90 minutes ago is now in the middle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tokens are an attention budget.&lt;/strong&gt; Anthropic's engineering team frames good context engineering as finding "the smallest possible set of high-signal tokens" that gets the result you want (&lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic, Effective context engineering&lt;/a&gt;). Their Claude Code docs put it bluntly: the context window "is the most important resource to manage" (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;Claude Code best practices&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The cost side follows directly. Claude Code "sends your full conversation with every request," so a one-line question in a session open all day still pays for the whole history (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;). Prompt caching softens this, since cache reads bill at a fraction of the normal input price (&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic prompt caching&lt;/a&gt;), but the cache has a lifetime. Come back after a break and you pay to reprocess everything.&lt;/p&gt;

&lt;p&gt;Simple arithmetic: asking the same question in a fresh 20k-token session versus a stale 150k-token session is 7.5x the input tokens, and the stale session is more likely to answer wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do agents actually make you faster?
&lt;/h2&gt;

&lt;p&gt;Short answer: yes for most people now, but not automatically. Here is the honest picture.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;METR's randomised trial found experienced open-source developers took 19% longer with early-2025 AI tools, while believing they were 20% faster (&lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;METR, July 2025&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;METR's follow-up says that result is now outdated and speedups "seem likely," but its new data is too biased by developers refusing to work without AI to give a reliable number (&lt;a href="https://metr.org/blog/2026-02-24-uplift-update/" rel="noopener noreferrer"&gt;METR, February 2026&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Google's DORA 2025 report calls AI "an amplifier" of a team's existing strengths and weaknesses (&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA 2025&lt;/a&gt;). Throughput went up, but delivery instability kept rising (&lt;a href="https://www.infoq.com/news/2025/09/dora-state-of-ai-in-dev-2025" rel="noopener noreferrer"&gt;InfoQ on DORA 2025&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Trust is still low: 46% of developers distrust AI accuracy and only 33% trust it (&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My read: the gap between "agent made me slower" and "agent made me faster" is mostly workflow. The habits below are what close it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 1: Keep the instruction file short and boring
&lt;/h2&gt;

&lt;p&gt;Every agent now reads a project instruction file: &lt;code&gt;CLAUDE.md&lt;/code&gt; for Claude Code, &lt;code&gt;AGENTS.md&lt;/code&gt; for Codex, Cursor and many others, &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt; for Copilot. AGENTS.md has become the shared format, now stewarded by the Agentic AI Foundation under the Linux Foundation (&lt;a href="https://agents.md/" rel="noopener noreferrer"&gt;agents.md&lt;/a&gt;), and Copilot reads AGENTS.md and CLAUDE.md as well (&lt;a href="https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This file loads on every session, so every line is a recurring tax. All the vendors say the same thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anthropic: "Aim to keep CLAUDE.md under 200 lines," and "Bloated CLAUDE.md files cause Claude to ignore your actual instructions!" (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;, &lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;OpenAI: "A short, accurate AGENTS.md is more useful than a long file full of vague rules" (&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;Codex best practices&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Cursor: "Start simple. Add rules only when you notice Agent making the same mistake repeatedly" (&lt;a href="https://cursor.com/docs/context/rules" rel="noopener noreferrer"&gt;Cursor rules&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test for every line: would removing it cause a mistake? If not, cut it. Here is the shape I use for a Next.js + Node project:&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;# AGENTS.md&lt;/span&gt;

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Install: pnpm install
&lt;span class="p"&gt;-&lt;/span&gt; Dev: pnpm dev
&lt;span class="p"&gt;-&lt;/span&gt; Test one file: pnpm vitest run path/to/file.test.ts
&lt;span class="p"&gt;-&lt;/span&gt; Typecheck: pnpm tsc --noEmit
&lt;span class="p"&gt;-&lt;/span&gt; Lint: pnpm lint

&lt;span class="gu"&gt;## Conventions the code won't tell you&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Server actions live in app/(actions)/, never inside components
&lt;span class="p"&gt;-&lt;/span&gt; All DB access goes through lib/db/&lt;span class="err"&gt;*&lt;/span&gt;.ts; no raw queries in routes
&lt;span class="p"&gt;-&lt;/span&gt; Money is stored as integer paise, never floats

&lt;span class="gu"&gt;## Don't&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Don't edit files in migrations/ by hand; generate them
&lt;span class="p"&gt;-&lt;/span&gt; Don't add dependencies without asking

&lt;span class="gu"&gt;## Done means&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Typecheck, lint and the relevant tests pass
&lt;span class="p"&gt;-&lt;/span&gt; Show me the command output, not a summary of it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No "write clean code," no folder-by-folder tour, no API docs pasted in. The agent can read the code. Put workflow-specific knowledge (how to do a release, how to write a migration) in on-demand files: skills in Claude Code, "Apply Intelligently" or file-scoped rules in Cursor, task-specific markdown files referenced from AGENTS.md in Codex. Those load only when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 2: One task, one session
&lt;/h2&gt;

&lt;p&gt;The most expensive pattern is what Anthropic calls "the kitchen sink session": you start one task, ask something unrelated, then go back (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;). OpenAI says the same: "Keep one chat per coherent unit of work," because long single-project chats lead to "bloated context and worse results over time" (&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;Codex best practices&lt;/a&gt;).&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;New task, new session.&lt;/strong&gt; In Claude Code, &lt;code&gt;/clear&lt;/code&gt; costs nothing, while &lt;code&gt;/compact&lt;/code&gt; reads the whole conversation to summarise it, so it is itself a large request (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two strikes and restart.&lt;/strong&gt; If I've corrected the agent twice on the same thing, the context is full of failed attempts. I clear and write a better first prompt that includes what I learned. Anthropic recommends exactly this (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compact with instructions when you must keep going.&lt;/strong&gt; &lt;code&gt;/compact Focus on the API changes and the failing test&lt;/code&gt; keeps what matters instead of a generic summary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side questions go elsewhere.&lt;/strong&gt; A quick "what does this flag do?" in the middle of a feature pollutes the context. Ask it in a separate window.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Habit 3: Plan only when the plan is worth it
&lt;/h2&gt;

&lt;p&gt;Planning prevents the most expensive failure: a correct implementation of the wrong thing. Both Claude Code and Codex have a plan mode (&lt;code&gt;Shift+Tab&lt;/code&gt;, or &lt;code&gt;/plan&lt;/code&gt; in Codex) (&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;Codex best practices&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But planning costs tokens too. Anthropic's rule of thumb is the best one I know: "If you could describe the diff in one sentence, skip the plan" (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Use a plan when the change touches several files, when you're unsure of the approach, or when you don't know this part of the codebase. For larger features, flip it around: have the agent interview you, write a &lt;code&gt;SPEC.md&lt;/code&gt;, then start a &lt;strong&gt;fresh&lt;/strong&gt; session to implement from the spec. The implementation session starts clean with a written contract instead of 40 turns of back-and-forth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 4: Write prompts with a "done when"
&lt;/h2&gt;

&lt;p&gt;Vague prompts cause broad scanning, and scanning burns tokens. "Improve this codebase" makes the agent read everything; "add input validation to the login function in auth.ts" doesn't (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;OpenAI's Codex guide recommends four parts: goal, context, constraints, and a "Done when" condition (&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;Codex best practices&lt;/a&gt;). My template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal: Users get logged out after a session timeout instead of a silent token refresh.
Context: Auth flow is in src/auth/. Token refresh is in src/auth/refresh.ts.
         Follow the error-handling pattern in src/auth/login.ts.
Constraints: No new dependencies. Don't change the public API of useSession().
Done when: A failing test reproduces the bug, the fix makes it pass,
           and `pnpm vitest run src/auth` plus `pnpm tsc --noEmit` are green.
           Paste the output.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pointing to files with paths (or &lt;code&gt;@file&lt;/code&gt; in Claude Code and Cursor) saves the agent from searching. Pointing to an existing pattern ("follow login.ts") gets you code that looks like the rest of your codebase instead of a generic tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 5: Give the agent a check it can run
&lt;/h2&gt;

&lt;p&gt;This is the single biggest quality lever. An agent "stops when the work looks done," and without a check it can run, you become the verification loop (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;). With a test, build or linter, the agent runs it, reads the failure, and fixes it before you ever see the diff.&lt;/p&gt;

&lt;p&gt;Three rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ask for evidence, not claims.&lt;/strong&gt; "Show the test output" beats "it should work now."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run one test, not the suite.&lt;/strong&gt; A full test run dumps thousands of lines of passing output into context. Point the agent at the relevant file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the check deterministic when it matters.&lt;/strong&gt; Claude Code hooks and Stop hooks run a script every time, unlike instructions in CLAUDE.md, which are advisory (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Habit 6: Keep noisy work out of the main context
&lt;/h2&gt;

&lt;p&gt;Logs, test output, documentation pages and codebase exploration are the biggest context fillers. Three ways to keep them out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subagents for investigation.&lt;/strong&gt; A subagent explores in its own context window and returns a summary, often 1,000-2,000 tokens (&lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic, Effective context engineering&lt;/a&gt;). "Use a subagent to find how we handle token refresh and whether we already have OAuth utilities" keeps 30 file reads out of your implementation session. Note that subagents still cost tokens; they save &lt;em&gt;context&lt;/em&gt;, and you can put them on a cheaper model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter output before the agent sees it.&lt;/strong&gt; Anthropic's example is a hook that greps a 10,000-line log for errors so the agent reads hundreds of tokens instead of tens of thousands (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;). Even without hooks, you can just ask for it:&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;# Instead of letting the agent read the whole run:&lt;/span&gt;
pnpm vitest run 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 5 &lt;span class="s1"&gt;'(FAIL|Error)'&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prefer CLI tools over stacks of MCP servers.&lt;/strong&gt; Anthropic's own measurements show loading tool definitions and passing intermediate results through the model can be brutal: one workflow went from 150,000 tokens to 2,000 when the agent wrote code to call tools instead (&lt;a href="https://www.anthropic.com/engineering/code-execution-with-mcp" rel="noopener noreferrer"&gt;Anthropic, Code execution with MCP&lt;/a&gt;). Claude Code now defers MCP tool definitions by default, but its docs still say CLIs like &lt;code&gt;gh&lt;/code&gt;, &lt;code&gt;aws&lt;/code&gt; and &lt;code&gt;gcloud&lt;/code&gt; "are still more context-efficient than MCP servers" (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;). Disable servers you aren't using in this task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 7: Match the model and effort to the task
&lt;/h2&gt;

&lt;p&gt;Running the largest model at maximum reasoning on a rename is the fastest way to burn a budget. Prices differ a lot: on Anthropic's current list, Opus 5.5 output costs twice what Sonnet 5.5 does (&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;), and Haiku 5.5 is far cheaper again (&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Claude pricing&lt;/a&gt;). Thinking tokens are billed as output tokens (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;How I split it:&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 tier&lt;/th&gt;
&lt;th&gt;Reasoning effort&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rename, typo, add a log line, small CRUD endpoint&lt;/td&gt;
&lt;td&gt;Mid or small&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feature across 3-6 files with tests&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging a flaky race condition, architecture change&lt;/td&gt;
&lt;td&gt;Top&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subagent doing file search or log summarising&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAI's Codex guidance lines up: low effort "for faster, well-scoped tasks," medium or high "for more complex changes or debugging," extra high for long, reasoning-heavy work (&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;Codex best practices&lt;/a&gt;). In Claude Code, &lt;code&gt;/model&lt;/code&gt; and &lt;code&gt;/effort&lt;/code&gt; switch both mid-session (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code costs&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Habit 8: Review with fresh eyes
&lt;/h2&gt;

&lt;p&gt;An agent reviewing code it just wrote is biased toward its own reasoning. A reviewer in a fresh context sees only the diff and your criteria (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;). I use a second session or subagent with a narrow brief: "Review this diff against SPEC.md. Report only gaps that affect correctness or stated requirements."&lt;/p&gt;

&lt;p&gt;That last sentence matters. A reviewer asked to find problems will always find some, and chasing every nitpick leads to over-engineered code (&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;best practices&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The token-waste cheat sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent ignores a rule you wrote&lt;/td&gt;
&lt;td&gt;Instruction file too long; rule lost in noise&lt;/td&gt;
&lt;td&gt;Prune to essentials; move workflows to on-demand skills or rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage spikes on a simple question&lt;/td&gt;
&lt;td&gt;Session open for hours&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/clear&lt;/code&gt; or a new chat per task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same mistake after corrections&lt;/td&gt;
&lt;td&gt;Context full of failed attempts&lt;/td&gt;
&lt;td&gt;Restart with a better first prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent reads half the repo&lt;/td&gt;
&lt;td&gt;Vague prompt&lt;/td&gt;
&lt;td&gt;Name files, point to a pattern, add "done when"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Huge turns after running tests&lt;/td&gt;
&lt;td&gt;Full test output in context&lt;/td&gt;
&lt;td&gt;Run one file; filter to failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow, pricey answers on easy tasks&lt;/td&gt;
&lt;td&gt;Top model and max effort by default&lt;/td&gt;
&lt;td&gt;Drop model tier and effort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"It works" but it doesn't&lt;/td&gt;
&lt;td&gt;No runnable check&lt;/td&gt;
&lt;td&gt;Require test or build output as evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When not to reach for an agent
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You can't verify the result.&lt;/strong&gt; If there's no test, no type system and no way to run it, a plausible diff is a liability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The change is two lines you already know.&lt;/strong&gt; Typing it is faster than writing the prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The task is mostly a judgment call.&lt;/strong&gt; Pricing logic, security boundaries, data deletion. Use the agent to explore options, then decide yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Treat the agent like a strong engineer who forgets everything between sessions: short onboarding doc, one clear task, a definition of done, a test to run, and a fresh pair of eyes at the end. That is what uses fewer tokens, and it is also what produces code you can ship.&lt;/p&gt;

&lt;p&gt;If you're planning a product and want someone who builds this way, I ship React/Next.js and Node.js products with AI in the loop for clients. &lt;a href="https://papansarkar.com/contact/" rel="noopener noreferrer"&gt;Get in touch&lt;/a&gt;. If you're wiring LLMs into your own backend, start with my &lt;a href="https://papansarkar.com/blog/llm-integration-django-backend/" rel="noopener noreferrer"&gt;LLM integration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow Developer Survey 2025: AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.trychroma.com/research/context-rot" rel="noopener noreferrer"&gt;Chroma Research: Context Rot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2307.03172" rel="noopener noreferrer"&gt;Liu et al., Lost in the Middle: How Language Models Use Long Contexts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Anthropic: Effective context engineering for AI agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;Claude Code docs: Best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Claude Code docs: Manage costs effectively&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;Anthropic docs: Prompt caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic docs: Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/engineering/code-execution-with-mcp" rel="noopener noreferrer"&gt;Anthropic: Code execution with MCP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;METR: Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://metr.org/blog/2026-02-24-uplift-update/" rel="noopener noreferrer"&gt;METR: We are Changing our Developer Productivity Experiment Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA: 2025 State of AI-assisted Software Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.infoq.com/news/2025/09/dora-state-of-ai-in-dev-2025" rel="noopener noreferrer"&gt;InfoQ: DORA 2025 report coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://agents.md/" rel="noopener noreferrer"&gt;AGENTS.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/guides/best-practices" rel="noopener noreferrer"&gt;OpenAI Codex: Best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cursor.com/docs/context/rules" rel="noopener noreferrer"&gt;Cursor docs: Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions" rel="noopener noreferrer"&gt;GitHub Docs: Adding repository custom instructions for Copilot&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://papansarkar.com/blog/use-ai-coding-agents-like-a-pro/" rel="noopener noreferrer"&gt;papansarkar.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>LLM Prices Just Dropped Up to 80%: How to Re-plan Your App's AI Costs</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Fri, 30 Oct 2026 12:55:41 +0000</pubDate>
      <link>https://dev.to/papansarkar101/llm-prices-just-dropped-up-to-80-how-to-re-plan-your-apps-ai-costs-3ck0</link>
      <guid>https://dev.to/papansarkar101/llm-prices-just-dropped-up-to-80-how-to-re-plan-your-apps-ai-costs-3ck0</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; OpenAI and Anthropic have cut LLM prices by up to 80% since July 2026. Before you celebrate, check which line of your bill actually moved. For agent-style workloads, cached input dominates spend, small models now handle most "AI feature" work for pennies, and the safest architecture is one that lets you switch models with a config change. Here's how I'd re-plan an app's AI costs this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;Max Woolf published a &lt;a href="https://minimaxir.com/2026/10/cheap-llms/" rel="noopener noreferrer"&gt;clear breakdown of the recent price cuts&lt;/a&gt; on 25 October. The short version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI's small "Luna" tier dropped about 80% in July, then halved again with GPT-6 Luna in September.&lt;/li&gt;
&lt;li&gt;Anthropic made a Sonnet 5 launch discount permanent, cut cache-read pricing hard on Fable 5.1, and cut Opus 5.5 by 40–60% overall compared to Opus 5.&lt;/li&gt;
&lt;li&gt;OpenAI's flagship "Sol" models got cheaper in steps through August and September, with GPT-6.1 Sol halving cache reads again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;His explanation is competition: open-weight models and dozens of inference providers sell near-identical quality, so price is the lever left. Whatever the cause, it changes the maths for a lot of features that were "too expensive" in the spring.&lt;/p&gt;

&lt;p&gt;But the headline number hides the part that matters for your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Find out which tokens you're actually paying for
&lt;/h2&gt;

&lt;p&gt;Most of us look at the input and output price and stop there. The same write-up points out that in agentic coding, &lt;strong&gt;cache reads are 96–99% of token spend&lt;/strong&gt;. Agents re-send the same system prompt, tool definitions and file context on every turn, and almost all of it is a cache hit.&lt;/p&gt;

&lt;p&gt;So for an agent, a 75% cut on cache reads matters more than a 20% cut on output. For a one-shot summariser with no shared prefix, the reverse is true.&lt;/p&gt;

&lt;p&gt;Before deciding anything, split your usage into those buckets. Both major APIs return usage per request. A tiny logger is enough to start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// usage-log.ts&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;inputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;outputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cacheReadTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cacheWriteTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Swap console for your DB or analytics later.&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log it per &lt;em&gt;feature&lt;/em&gt;, not just per model. "The AI bill" is useless. "The ticket-triage feature costs X per 1,000 tickets" is something you can make decisions about.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Structure prompts so the cache actually hits
&lt;/h2&gt;

&lt;p&gt;If cache reads are now very cheap, the win is making sure your requests are cacheable in the first place. The rule is simple: &lt;strong&gt;stable content first, changing content last&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With Anthropic's Messages API, you mark the end of the stable prefix with &lt;code&gt;cache_control&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Anthropic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@anthropic-ai/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;answerWithDocs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_MODEL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// keep model IDs in config&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You answer questions using only the provided docs.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// large, rarely changes -&amp;gt; cache it&lt;/span&gt;
        &lt;span class="na"&gt;cache_control&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ephemeral&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;// changes every call&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenAI applies prompt caching automatically on long prompts, but the same ordering rule applies: anything that changes per request (timestamps, user names, the question) belongs at the end. A single &lt;code&gt;Today is ${new Date()}&lt;/code&gt; at the top of your system prompt quietly breaks the cache for everything after it.&lt;/p&gt;

&lt;p&gt;Things that commonly bust the cache:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic values in the system prompt&lt;/li&gt;
&lt;li&gt;Tool definitions generated in a different order each time&lt;/li&gt;
&lt;li&gt;Re-serialising JSON context with unstable key order&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Route by task, not by habit
&lt;/h2&gt;

&lt;p&gt;Lots of products send everything to the flagship model because that's what the prototype used. Now the small tiers cost cents per million tokens, so it's worth being deliberate.&lt;/p&gt;

&lt;p&gt;A simple router covers most apps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// llm-router.ts&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;extract&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;summarize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reason&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MODEL_FOR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_SMALL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_SMALL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_SMALL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_LARGE&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_LARGE&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pickModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;MODEL_FOR&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then measure. Run a few hundred real inputs through the small model and compare with the large one on the cases you care about. If the small model is right often enough, ship it. If not, you've lost an afternoon, not a quarter.&lt;/p&gt;

&lt;p&gt;I'd keep one honest caveat here: cheaper models are not automatically good enough. A specialised, boring approach (a regex, a classic classifier, a database query) still beats an LLM for plenty of tasks. Price cuts don't change that.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Put the provider behind one function
&lt;/h2&gt;

&lt;p&gt;The other side of commoditisation: if quality is close and prices keep moving, switching providers becomes a normal operation. Make it cheap.&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;# llm.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLMResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;output_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;LLMResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LLM_PROVIDER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# "anthropic" | "openai" | ...
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.providers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic_complete&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;anthropic_complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.providers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;openai_complete&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;openai_complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown provider: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing clever here, and that's the point. Your app code calls &lt;code&gt;complete()&lt;/code&gt;. Model IDs, providers and fallbacks live in config. When the next price change lands, you change an environment variable and re-run your evals.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Re-check the features you shelved
&lt;/h2&gt;

&lt;p&gt;This is where the price cuts can make actual product money. Go back through the AI ideas you dropped for cost and price each one at today's rates:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Which tier does it really need?&lt;/td&gt;
&lt;td&gt;Small-model pricing changes most features from "no" to "yes"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How much of the prompt is a stable prefix?&lt;/td&gt;
&lt;td&gt;Cheap cache reads reward long, shared context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does it cost per user per month?&lt;/td&gt;
&lt;td&gt;Compare against what that user pays you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it still work at 2x today's price?&lt;/td&gt;
&lt;td&gt;Prices can move in either direction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is my rule of thumb. If a feature only makes sense at this quarter's prices, build it so you can swap models or switch it off without a migration. If it still makes sense at double the price, it's a real feature, so build it properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would not do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't jump to the most expensive model just because it's cheaper than last month.&lt;/strong&gt; Measure first. Bigger isn't always better for narrow tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't hard-code a model ID in twenty places.&lt;/strong&gt; You will want to change it, probably soon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't assume subscription plans follow API prices.&lt;/strong&gt; Woolf notes he cut his own subscription quota, and he expects plan allowances may shrink before API prices rise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The price cuts are real, and they make a lot of AI features newly viable. The developers who benefit most will be the ones who know which tokens they pay for, keep their prompts cache-friendly, and can switch models without a rewrite.&lt;/p&gt;

&lt;p&gt;Which line of your LLM bill surprised you most when you finally broke it down: input, output or cache?&lt;/p&gt;




&lt;p&gt;I build web and AI products for clients; more about my work at &lt;a href="https://papansarkar.com" rel="noopener noreferrer"&gt;papansarkar.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>llm</category>
      <category>openai</category>
      <category>ai</category>
    </item>
    <item>
      <title>8 Habits to Stop Burning Tokens with AI Coding Tools</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Sun, 25 Oct 2026 00:45:16 +0000</pubDate>
      <link>https://dev.to/papansarkar101/8-habits-to-stop-burning-tokens-with-ai-coding-tools-32f4</link>
      <guid>https://dev.to/papansarkar101/8-habits-to-stop-burning-tokens-with-ai-coding-tools-32f4</guid>
      <description>&lt;p&gt;Most developers burn AI tokens the same way they used to burn cloud credits: by not paying attention.&lt;/p&gt;

&lt;p&gt;Every message you send to an AI coding tool also sends the context with it: the earlier chat history, the files it has read, and the tool output. When usage grows, it's rarely because of one huge prompt. It's because of context piling up quietly in the background.&lt;/p&gt;

&lt;p&gt;Here are the habits that cut my usage the most without slowing me down.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. One task per session
&lt;/h2&gt;

&lt;p&gt;When a task is done, clear the context before you start the next one. A long chat re-sends old history with every turn, so you keep paying for a bug you fixed an hour ago.&lt;/p&gt;

&lt;p&gt;In Claude Code, &lt;code&gt;/clear&lt;/code&gt; does this. In other tools, just start a new chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Write a project rules file once
&lt;/h2&gt;

&lt;p&gt;Put your stack, conventions, folder layout, and common commands in a rules file: &lt;code&gt;CLAUDE.md&lt;/code&gt; for Claude Code, &lt;code&gt;.cursorrules&lt;/code&gt; or project rules for Cursor, or your tool's equivalent.&lt;/p&gt;

&lt;p&gt;Keep it short. It loads into every session, so a bloated rules file costs you tokens on every single request.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Point to files, don't paste them
&lt;/h2&gt;

&lt;p&gt;Compare these two prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Fix the null check in &lt;code&gt;auth/session.ts&lt;/code&gt; around line 40"&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;pastes three files&lt;/em&gt; "something's wrong with login"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one gives the agent a target. The second one invites it to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Plan first, then execute
&lt;/h2&gt;

&lt;p&gt;Ask for a short plan and approve it before the agent writes any code. Claude Code has a dedicated plan mode for this. A wrong direction caught at the plan stage costs a few hundred tokens. Caught after implementation, it costs you a full rewrite loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Match the model to the task
&lt;/h2&gt;

&lt;p&gt;Renames, boilerplate, test scaffolding, and formatting don't need your most expensive model. Switch to a smaller or faster model for routine work, and save the big one for architecture decisions and hard debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Give precise errors, not vibes
&lt;/h2&gt;

&lt;p&gt;Paste the exact stack trace, the failing command, and what you expected to happen. "It's broken" makes the agent read through half your repo trying to reproduce the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Keep noise out of reach
&lt;/h2&gt;

&lt;p&gt;Build output, lockfiles, generated code, and large fixtures waste context when they get read. Cursor supports &lt;code&gt;.cursorignore&lt;/code&gt;. In Claude Code, you can deny reads to specific paths in your settings permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Summarize, then reset
&lt;/h2&gt;

&lt;p&gt;When a session gets long but the work isn't finished, ask for a summary of the decisions made and the current state. Then start fresh and paste the summary in. Claude Code's &lt;code&gt;/compact&lt;/code&gt; does a version of this for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real point
&lt;/h2&gt;

&lt;p&gt;Token efficiency isn't about being cheap. It's about context hygiene. A clean, focused context is cheaper, and it also gives you better output, because the model isn't sorting through stale or irrelevant information.&lt;/p&gt;

&lt;p&gt;What's your biggest token-waster? Let me know in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How a Clean Next.js Repo Ran Malware on Every npm run dev</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Tue, 20 Oct 2026 21:44:19 +0000</pubDate>
      <link>https://dev.to/papansarkar101/the-npm-malware-hiding-in-tailwindconfigjs-1lmm</link>
      <guid>https://dev.to/papansarkar101/the-npm-malware-hiding-in-tailwindconfigjs-1lmm</guid>
      <description>&lt;p&gt;A codebase I got through Fiverr looked like an ordinary Next.js invoice app. It wasn't.&lt;/p&gt;

&lt;p&gt;Two dependencies deep, gated behind an npm auth token committed in the project's own &lt;code&gt;.npmrc&lt;/code&gt;, sat a private package carrying roughly 180 KB of heavily obfuscated JavaScript — wired to execute every time the dev server starts.&lt;/p&gt;

&lt;p&gt;I caught it before running it. Here is the short version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every standard check passed
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt; scripts held only &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;lint&lt;/code&gt;. No &lt;code&gt;preinstall&lt;/code&gt;, no &lt;code&gt;postinstall&lt;/code&gt;, no &lt;code&gt;prepare&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A grep for the usual suspects came back empty:&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rnE&lt;/span&gt; &lt;span class="s2"&gt;"eval&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;|new Function|child_process|execSync|spawn&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;|atob&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;|fromCharCode|base64"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.js &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.mjs &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.cjs &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.ts &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.jsx &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.tsx &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A long-line grep, which is how whitespace-padded payloads usually surface, matched only SVG path data and Tailwind class strings.&lt;/p&gt;

&lt;p&gt;The repo &lt;em&gt;was&lt;/em&gt; clean. The malicious code was never in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things that didn't add up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The project shipped an npm auth token.&lt;/strong&gt;&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .npmrc
//registry.npmjs.org/:_authToken&lt;span class="o"&gt;=&lt;/span&gt;npm_HIswo…[redacted]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An npm access token carries &lt;a href="https://docs.npmjs.com/about-access-tokens" rel="noopener noreferrer"&gt;"the right to install and/or publish your modules"&lt;/a&gt;, including read access to private packages that account can see. A stranger's deliverable has no reason to include one. Its only function here was to let &lt;code&gt;npm install&lt;/code&gt; fetch something you otherwise could not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A Tailwind plugin I'd never heard of.&lt;/strong&gt; &lt;code&gt;devDependencies&lt;/code&gt; had &lt;code&gt;"tailwind-animationlab": "^2.0.6"&lt;/code&gt;. The real ones cluster around similar names — &lt;code&gt;tailwindcss-animate&lt;/code&gt;, &lt;code&gt;tailwindcss-animated&lt;/code&gt;, &lt;code&gt;tailwind-animations&lt;/code&gt;. At the bottom of &lt;code&gt;tailwind.config.js&lt;/code&gt;:&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="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwind-animationlab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)({&lt;/span&gt;
    &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500ms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;iterationCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing about that looks wrong — and that's the point. &lt;a href="https://v3.tailwindcss.com/docs/configuration" rel="noopener noreferrer"&gt;Tailwind's own docs&lt;/a&gt; register plugins exactly this way, with &lt;code&gt;require()&lt;/code&gt; inside the &lt;code&gt;plugins&lt;/code&gt; array. The config file was padded with friendly comments explaining unused theme values, which made one more &lt;code&gt;require&lt;/code&gt; easy to skim past.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The timestamps.&lt;/strong&gt; Nearly every file was dated Sep 13, 13:29. Three were not: &lt;code&gt;.npmrc&lt;/code&gt; (Sep 13, 14:15), &lt;code&gt;tailwind.config.js&lt;/code&gt; (Sep 28, 09:49), &lt;code&gt;package.json&lt;/code&gt; (Sep 28, 09:50). Exactly the three files needed to authorize, inject and execute a dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following the chain
&lt;/h2&gt;

&lt;p&gt;From my home directory, so the project's token wasn't picked up:&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="nb"&gt;cd&lt;/span&gt; ~ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm view tailwind-animationlab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One version, numbered 2.0.6 — new packages don't start at 2.0.6; it was chosen to satisfy the &lt;code&gt;^2.0.6&lt;/code&gt; already in the project. Registry creation date 2026-09-28, the same day those config files were edited. npm maintainer &lt;code&gt;adriannamrr&lt;/code&gt;, but author and homepage pointing at &lt;code&gt;sericpieap&lt;/code&gt;. And one dependency I didn't recognise: &lt;code&gt;@jasperquinn/postcss-motion-helpers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I unpacked the decoy without executing it. Clean. It was built to survive a code review, because that's the layer a careful developer actually inspects.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view @jasperquinn/postcss-motion-helpers
&lt;span class="c"&gt;# npm error 404 Not Found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;public&lt;/strong&gt; package depending on a &lt;strong&gt;private&lt;/strong&gt; one. Private npm packages &lt;a href="https://docs.npmjs.com/about-private-packages" rel="noopener noreferrer"&gt;"always have a scope"&lt;/a&gt; and are readable only by the owner and granted collaborators. So for anyone else on earth, installing &lt;code&gt;tailwind-animationlab&lt;/code&gt; fails. It resolves only on a machine holding the attacker's token — which is to say, on a victim's machine, supplied through that &lt;code&gt;.npmrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the token, inside a throwaway Codespace on a burner GitHub account, still executing nothing, the private tarball's &lt;code&gt;src/config.js&lt;/code&gt; was a wall of machine-generated obfuscation: an encoded blob, &lt;code&gt;_0x&lt;/code&gt; hex identifiers, a large &lt;code&gt;switch&lt;/code&gt;-based dispatch loop, heavy &lt;code&gt;Proxy&lt;/code&gt; and &lt;code&gt;Reflect&lt;/code&gt; use. A PostCSS helper has no reason to look like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;--ignore-scripts&lt;/code&gt; wouldn't have helped
&lt;/h2&gt;

&lt;p&gt;Most npm hardening advice is about install hooks. But npm's config reference is explicit that &lt;code&gt;npm run&lt;/code&gt; and &lt;code&gt;npm start&lt;/code&gt; &lt;a href="https://docs.npmjs.com/cli/v11/using-npm/config" rel="noopener noreferrer"&gt;"will still run their intended script if &lt;code&gt;ignore-scripts&lt;/code&gt; is set"&lt;/a&gt; — they only skip pre- and post-scripts.&lt;/p&gt;

&lt;p&gt;This attack never wanted an install hook. Tailwind v3 loads &lt;code&gt;tailwind.config.js&lt;/code&gt; whenever it generates CSS, so that &lt;code&gt;require()&lt;/code&gt; evaluates on every &lt;code&gt;npm run dev&lt;/code&gt; and every &lt;code&gt;npm run build&lt;/code&gt;. The trigger was the developer doing their job.&lt;/p&gt;

&lt;p&gt;Same logic covers a neighbouring trick: VS Code's &lt;code&gt;runOn: folderOpen&lt;/code&gt; means &lt;a href="https://code.visualstudio.com/docs/debugtest/tasks" rel="noopener noreferrer"&gt;"the task will be run when the containing folder is opened"&lt;/a&gt;. Clicking &lt;em&gt;Trust&lt;/em&gt; on a stranger's folder is a code-execution decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this a known campaign?
&lt;/h2&gt;

&lt;p&gt;The tradecraft matches Contagious Interview. Socket counted more than 338 malicious npm packages with over 50,000 cumulative downloads in a single wave, tied to more than 180 fake maintainer personas, attributed to &lt;a href="https://socket.dev/blog/north-korea-contagious-interview-campaign-338-malicious-npm-packages" rel="noopener noreferrer"&gt;"North Korean state-sponsored actors"&lt;/a&gt; — and its package list includes names impersonating &lt;code&gt;tailwindcss&lt;/code&gt;, &lt;code&gt;vite&lt;/code&gt;, &lt;code&gt;eslint&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt;. &lt;a href="https://www.elastic.co/security-labs/threat-command/contagious-interview-malware-svg-steganography" rel="noopener noreferrer"&gt;Elastic documented&lt;/a&gt; a tampered Next.js e-commerce template carrying a credential and wallet stealer plus a Socket.IO RAT.&lt;/p&gt;

&lt;p&gt;To be precise: &lt;strong&gt;I have not confirmed this sample is Contagious Interview.&lt;/strong&gt; My delivery channel was a paid Fiverr gig, not a fake job interview, and I didn't reverse the payload. What matches is the playbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I check now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ls -la&lt;/code&gt; — &lt;code&gt;.npmrc&lt;/code&gt; with an &lt;code&gt;_authToken&lt;/code&gt;, a custom &lt;code&gt;registry=&lt;/code&gt;, a &lt;code&gt;.vscode/tasks.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripts&lt;/code&gt; in &lt;em&gt;every&lt;/em&gt; &lt;code&gt;package.json&lt;/code&gt;, not just the root one&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*.config.js&lt;/code&gt; for Tailwind, PostCSS, Next, ESLint, Vite — any &lt;code&gt;require()&lt;/code&gt; you don't recognise&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm view &amp;lt;pkg&amp;gt;&lt;/code&gt; run from &lt;code&gt;~&lt;/code&gt;: single version, starting at 2.x+, published recently, maintainer ≠ author&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm view &amp;lt;pkg&amp;gt; dependencies&lt;/code&gt;: unknown scoped packages, or a 404 on the public registry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ls -la&lt;/code&gt; again, for a handful of config files edited separately from everything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two rules carry most of the weight: &lt;strong&gt;read unknown code in a disposable environment with no real credentials&lt;/strong&gt;, and &lt;strong&gt;treat any &lt;code&gt;.npmrc&lt;/code&gt; you didn't write as hostile&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status as of writing
&lt;/h2&gt;

&lt;p&gt;I reported both packages and both maintainer accounts to npm, the seller to Fiverr, and the GitHub account to GitHub. The &lt;code&gt;sericpieap&lt;/code&gt; GitHub account and its homepage now return 404. But &lt;code&gt;tailwind-animationlab@2.0.6&lt;/code&gt; is still installable from the public registry, and &lt;code&gt;@jasperquinn/postcss-motion-helpers&lt;/code&gt; still 404s publicly — the delivery mechanism is intact.&lt;/p&gt;

&lt;p&gt;Indicators: &lt;code&gt;tailwind-animationlab@2.0.6&lt;/code&gt;, shasum &lt;code&gt;9636e080056e59024e3e0d70f998d8f80e9129a9&lt;/code&gt;, maintainer &lt;code&gt;adriannamrr&lt;/code&gt;, author/homepage &lt;code&gt;sericpieap&lt;/code&gt;, created 2026-09-28. Private dependency &lt;code&gt;@jasperquinn/postcss-motion-helpers@1.0.3&lt;/code&gt;, referenced as &lt;code&gt;^1.0.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you've seen these package names in a dataset, I'd like to hear about it.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
    </item>
    <item>
      <title>Prototyping just went from "Hours" to "Minutes." ⚡️</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Fri, 05 Dec 2025 17:19:32 +0000</pubDate>
      <link>https://dev.to/papansarkar101/prototyping-just-went-from-hours-to-minutes-2e72</link>
      <guid>https://dev.to/papansarkar101/prototyping-just-went-from-hours-to-minutes-2e72</guid>
      <description>&lt;p&gt;I remember when setting up a clean, responsive dashboard meant wrestling with boilerplate code for half a day.&lt;/p&gt;

&lt;p&gt;Today, I challenged Google AI Studio to build a fully functional Personal Finance Dashboard using React, Tailwind CSS, and Recharts.&lt;/p&gt;

&lt;p&gt;The result? A stunning, dark-mode UI with "Bento Grid" layout and glassmorphism effects—generated in under 120 seconds. 🤯&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmd5cy9ctj54g3obj21bc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmd5cy9ctj54g3obj21bc.png" alt="Dashboard UI" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why this matters for developers: It's not about AI replacing us. It's about "Velocity to V1." Instead of spending 4 hours on the UI shell, you spend 2 minutes generating it, and the next 3 hours and 58 minutes on the actual logic and backend architecture.&lt;/p&gt;

&lt;p&gt;The Reality Check: Yes, this is a frontend prototype. It still needs a secure backend, auth, and database. But the visual heavy lifting? Done.&lt;/p&gt;

&lt;p&gt;I shared the full breakdown and code in my latest YouTube Short.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygr0aqam94khscp7zvq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygr0aqam94khscp7zvq2.png" alt="Prompt" width="480" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you see here is a Frontend Prototype (the interface). It looks great, but to turn this into a real, working app, you still need: A Backend (Logic to handle transactions). A Database (To actually save user data). Authentication (Secure login/signup). &lt;/p&gt;

&lt;p&gt;The Reality: AI is an amazing tool to speed up the design and boilerplate code, but you still need to understand programming to connect the pieces and make it secure! Use this to prototype fast, not to skip learning the basics.&lt;/p&gt;

&lt;p&gt;🚀 Need to turn your idea into a working product fast? Check out how we build high-performance MVPs at &lt;a href="https://yestoideas.com/" rel="noopener noreferrer"&gt;Yestoideas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>🚀 Supabase Connection Scaling: The Essential Guide for FastAPI Developers</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Fri, 14 Nov 2025 18:24:55 +0000</pubDate>
      <link>https://dev.to/papansarkar101/supabase-connection-scaling-the-essential-guide-for-fastapi-developers-348o</link>
      <guid>https://dev.to/papansarkar101/supabase-connection-scaling-the-essential-guide-for-fastapi-developers-348o</guid>
      <description>&lt;p&gt;Building a scalable FastAPI backend requires mastering database connections. When using Supabase (PostgreSQL), choosing the wrong connection method is the fastest way to crash your server under load. This guide clarifies the critical difference between Transaction Mode and Session Mode to help you choose the right path for high performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xzntn4uqgj6ddebnkqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xzntn4uqgj6ddebnkqh.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔒 The Connection Pooler: Your Database’s Gatekeeper
&lt;/h2&gt;

&lt;p&gt;Every Supabase project includes a Connection Pooler (Supavisor/PgBouncer). Its job is to efficiently manage traffic between your many client applications and your limited database resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The “Lobby” (Max Client Connections): This is the high limit (e.g., 200 on Nano). It’s the total number of clients that can connect to the pooler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The “Tellers” (Pool Size / Backend Connections): This is the low, resource-intensive limit (e.g., 15–20 on Nano). It’s the number of actual PostgreSQL processes available to run queries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core challenge is enabling hundreds of clients in the Lobby to efficiently share just 20 Tellers.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Transaction Mode: Lightning-Fast Exchange (Port 6543) ⚡
&lt;/h2&gt;

&lt;p&gt;Transaction Mode is the mandatory choice for scalable, high-concurrency web APIs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How it Works: A client (your FastAPI endpoint) borrows a Teller only for the duration of a single transaction or query. The moment the transaction commits, the Teller is immediately released back to the pool for the next waiting client.&lt;/li&gt;
&lt;li&gt;    Analogy: The Express Lane at a bank. You quickly finish your one task, and the Teller is free instantly.&lt;/li&gt;
&lt;li&gt;    Advantages: Maximizes throughput and concurrency. A few connections can handle a high volume of requests because no connection is ever held idle.&lt;/li&gt;
&lt;li&gt;    When to Use: Default mode for all general-purpose web traffic, serverless functions, and short-lived tasks.&lt;/li&gt;
&lt;li&gt;    Supabase Port: 6543.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Session Mode: The Dedicated Teller (Port 5432) 🔑
&lt;/h2&gt;

&lt;p&gt;Session Mode is a stateful mode designed for compatibility and long-running tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How it Works: A client connection permanently holds a specific backend connection (Teller) for the entire duration of the client’s session, even when the client is idle. The connection is only returned when the client disconnects.&lt;/li&gt;
&lt;li&gt;    Analogy: The Personal Banker. You keep the banker until your entire long meeting is over, making them unavailable to others.&lt;/li&gt;
&lt;li&gt;    Advantages: Provides Full PostgreSQL Compatibility for features that require persistent state.&lt;/li&gt;
&lt;li&gt;    When to Use: Database migrations, admin tools, debugging, or complex background jobs that rely on setting session variables (SET TIME ZONE) or using temporary tables.&lt;/li&gt;
&lt;li&gt;    Supabase Port: 5432 (the default PostgreSQL port).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛑 The Critical Pitfall: Running FastAPI in Session Mode
&lt;/h2&gt;

&lt;p&gt;If your FastAPI backend connects on Port 5432, your entire application operates in Session Mode, leading to three major stability risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rapid Limit Exhaustion: Your application effectively ignores the 200 client limit and is capped by the 20 Pool Size. If 21 instances or users connect, the 21st is blocked, even if the first 20 are idle.&lt;/li&gt;
&lt;li&gt;    Memory Overload: Holding 20+ persistent connections on a small instance (like Nano) quickly exhausts the server’s limited RAM, forcing the database into a read-only state to prevent a crash.&lt;/li&gt;
&lt;li&gt;    Connection Leakage: Any connection not cleanly closed by FastAPI will remain stuck, eventually using up all 20 backend connections permanently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠️ The Essential Code Fix: Disable Prepared Statements
&lt;/h2&gt;

&lt;p&gt;The migration to Transaction Mode (Port 6543) requires a vital code change because it breaks a common optimization feature: Prepared Statements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    The Conflict: Prepared statements are an efficiency feature that involves storing a pre-compiled query plan on a specific session (backend connection). When Transaction Mode swaps the connection, the new connection cannot find the stored plan, causing the frequent and fatal prepared statement “…” does not exist error.&lt;/li&gt;
&lt;li&gt;    The Solution: You must configure your Python database driver or ORM (like SQLAlchemy with asyncpg) to explicitly disable prepared statements by setting the cache size to zero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Python/FastAPI Configuration (SQLAlchemy + Asyncpg)&lt;/p&gt;

&lt;p&gt;This code snippet is the necessary modification when pointing your FastAPI backend to Port 6543.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.pool import NullPool 

# ⚠️ Change port to 6543
DATABASE_URL = "postgresql+asyncpg://user:pass@host.supabase.co:6543/postgres" 

engine = create_async_engine(
    DATABASE_URL,
    # Use NullPool: Let the external pooler (Supavisor) manage connections, not the app.
    poolclass=NullPool, 
    connect_args={
        # CRITICAL: Disables statement caching, fixing the Transaction Mode conflict
        "statement_cache_size": 0, 

        # Ensures asyncpg also respects the cache being disabled
        "prepared_statement_cache_size": 0, 
    },
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: If using the pure psycopg3 driver, you would typically pass prepare_threshold=None to the connection pool configuration.&lt;br&gt;
Conclusion&lt;/p&gt;

&lt;p&gt;For a scalable FastAPI application on Supabase, always start with Transaction Mode (Port 6543) as your default for all API traffic. This choice maximizes concurrency and efficiency. Reserve Session Mode (Port 5432) only for specialized, stateful tasks like migrations or admin scripts. The main takeaway: Enable Port 6543 and disable prepared statements to unlock optimal scalability and prevent stability issues.&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>supabase</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dynamic Serializers in Django</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Wed, 17 Apr 2024 18:24:08 +0000</pubDate>
      <link>https://dev.to/papansarkar101/dynamic-serializers-in-django-e7b</link>
      <guid>https://dev.to/papansarkar101/dynamic-serializers-in-django-e7b</guid>
      <description>&lt;p&gt;Dynamic serializers are extremely useful to make flexible APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we need dynamic serializers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: It provides flexibility. We often run into issues, where we need a serializer but not all the fields from that serializer. In that case dynamic serializers are especially useful to use subsets of data. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Reusability&lt;/strong&gt;: No need to write multiple serializers anymore, a single dynamic serializer can achieve various needs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: If we only pick the fields we need, it will immensely improve the overall performance. &lt;/p&gt;

&lt;p&gt;While it has good advantages, it comes with few complexities as well. It can make debugging a little difficult and we can come across with errors if we do not follow good practices and test all kind of edge cases. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DynamicSerializer(ModelSerializer): 

    """
    A ModelSerializer that takes an additional 'fields' 
    argument that controls which fields should be displayed. 
    """


    def __init__(self, *args, **kwargs): 

        fields = kwargs.pop('fields', None) 

        # Instantiate the superclass normally 

        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) 

        if fields is not None: 

            # Drop any fields that are not specified in the `fields` argument. 

            allowed = set(fields) 
            existing = set(self.fields.keys()) 
            for field_name in existing - allowed: 
                self.fields.pop(field_name)


# Example usage in a view 
class UserSerializer(DynamicFieldsModelSerializer): 
    class Meta: 
        model = User 
        fields = '__all__' `


# In your view 
serializer = UserSerializer(user, fields=('id', 'username', 'email')) 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conclusion: &lt;/p&gt;

&lt;p&gt;Dynamic serializer is powerful tool in Django, especially for large and complex projects.  &lt;/p&gt;

&lt;p&gt;Proper implementation and thorough testing are important to achieve good and optimised results.  &lt;/p&gt;

</description>
      <category>django</category>
      <category>webdev</category>
      <category>programmers</category>
      <category>developers</category>
    </item>
    <item>
      <title>Don't write queries inside serializers in Django!</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Sat, 13 Apr 2024 14:36:06 +0000</pubDate>
      <link>https://dev.to/papansarkar101/dont-write-queries-inside-serializers-in-django-5d25</link>
      <guid>https://dev.to/papansarkar101/dont-write-queries-inside-serializers-in-django-5d25</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nmsuy89phhworxbdjdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nmsuy89phhworxbdjdc.png" alt="Don't Do it" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It should focus data conversion and validations only. Don't write database logic on this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not efficient and bad performance. It will create lots of queries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can not reuse it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Very hard to test&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Readability is gone&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I can share the alternatives if you want! Let me know&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Do's and Don'ts in Django</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Fri, 12 Apr 2024 17:34:42 +0000</pubDate>
      <link>https://dev.to/papansarkar101/dos-and-donts-in-django-59ii</link>
      <guid>https://dev.to/papansarkar101/dos-and-donts-in-django-59ii</guid>
      <description>&lt;h2&gt;
  
  
  Do’s
&lt;/h2&gt;

&lt;p&gt;Use meaningful variables: We should use clear, concise, and self-explanatory variables, functions, and classes name. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DRY:&lt;/strong&gt; Don’t Repeat Yourself. We should reuse code as much as possible. Once you are done with the code, take 10 minutes to think what the possibilities are to improve it further and make it optimal. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Django features:&lt;/strong&gt; On daily basis, we receive unique requirements which is consist of unique business logic for those cases we often write flexible code to solve a problem, which is fine but again it might not be the optimal solution. So again, take 10 minutes extra to research how could you have done this differently keeping a standard approach and solution.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick related note:&lt;/strong&gt; It is very normal to think of a custom solution first, however it helps or comes to your head. No one solves a problem in the first go with the best possible solution and standards. It is always the next set of iteration which makes the difference. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do a security check:&lt;/strong&gt; Always do a security check once you are done with a task.  Think of edge cases which can eventually create a problem. If needed get on a call with someone and share your thoughts and understanding, you will get more clarity with another set of eyes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow PEP8:&lt;/strong&gt; Since so many people are working on the same code, and we are trying to make it more readable and understandable. It is especially important that we make use PEP 8 style guide for Python code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Don’ts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do not write Complex Queries on serializers:&lt;/strong&gt; Avoid writing complex queries on serializers or any serializer methods. Prefetch data in views instead. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t write generic views all the time:&lt;/strong&gt; Generic views are super useful and powerful but do not use it when it is not required. If the requirement is simple and straightforward write Functional views instead. &lt;/p&gt;

&lt;p&gt;**Don’t keep unlimited access to endpoints (Rate Limiting): **Implement rate limiting to protect APIs.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t write nested serializers:&lt;/strong&gt; Nested serializers can produce inefficient queries and effect performance. Create different endpoints for these cases or change the data structure. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t write business logic inside views or serializers:&lt;/strong&gt; It is one of most important things to consider when building a huge project consists of lots of business logic. Business logic should be written in service layer, model property methods etc. &lt;/p&gt;

</description>
      <category>django</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Take a Ten Minute Walk: A Codewars kata solution By Papan Sarkar</title>
      <dc:creator>Papan Sarkar</dc:creator>
      <pubDate>Wed, 07 Oct 2020 08:41:24 +0000</pubDate>
      <link>https://dev.to/papansarkar101/take-a-ten-minute-walk-a-codewars-kata-solution-by-papan-sarkar-4mf0</link>
      <guid>https://dev.to/papansarkar101/take-a-ten-minute-walk-a-codewars-kata-solution-by-papan-sarkar-4mf0</guid>
      <description>&lt;p&gt;Take a Ten Minute Walk: A Codewars kata&amp;nbsp;solution&amp;nbsp;&lt;br&gt;
In this article, I'll explain a kata solution from Codewars. This kata(problem) is authored by JKphobic. And here is the kata &lt;br&gt;
link:&lt;a href="https://www.codewars.com/kata/54da539698b8a2ad76000228/train/python" rel="noopener noreferrer"&gt;https://www.codewars.com/kata/54da539698b8a2ad76000228/train/python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Problem:&lt;br&gt;
You live in the city of Cartesian where all roads are laid out in a perfect grid. You arrived ten minutes too early to an appointment, so you decided to take the opportunity to go for a short walk. The city provides its citizens with a Walk Generating App on their phones -- every time you press the button it sends you an array of one-letter strings representing directions to walk (eg. ['n', 's', 'w', 'e']). You always walk only a single block for each letter (direction) and you know it takes you one minute to traverse one city block, so create a function that will return true if the walk the app gives you will take you exactly ten minutes (you don't want to be early or late!) and will, of course, return you to your starting point. Return false otherwise.&lt;/p&gt;

&lt;p&gt;Note: you will always receive a valid array containing a random assortment of direction letters ('n', 's', 'e', or 'w' only). It will never give you an empty array (that's not a walk, that's standing still!).&lt;/p&gt;

&lt;p&gt;First of all, we need to understand the problem. Then we will see what it's input and of course what kind of output it wants from us.&lt;/p&gt;

&lt;p&gt;If you read the problem twice or thrice, you'll see a few things like what things we need to keep in our minds. Like&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;The walk has to be for 10 minutes.&lt;br&gt;
You need to return to the starting point&amp;nbsp;&lt;br&gt;
Every list item (each letter) or single block represents one minute&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Let's convert these instructions into code and make small segments of the whole solution code:&lt;br&gt;
So,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if len(walk) == 10 //True
else // False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll create two variable and initialize to 0 to track our walk, ns (North-South) and ew (East-West) -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ns = 0
ew = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For every single block we walk, respectively we'll increment and decrement with 1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if we move in n direction then ns += 1
if we move in s direction (coming back) then ns -= 1
if we move in e direction then ew += 1
if we move in w direction (coming back) then ew -= 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then finally we will check we returned to our same position or not&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if ns == 0 and ew == 0 //True
else //False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's combine all this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Python Solution
def is_valid_walk(walk):
    ns, ew = 0, 0
    if len(walk) == 10:
        for i in walk:
            if i == 'n': ns+=1
            if i == 's': ns-=1
            if i == 'w': ew+=1
            if i == 'e': ew-=1
    else:
        return False
    return ns == 0 and ew == 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Javascript solution
function isValidWalk(walk) {
    let ns = 0, ew = 0; 
    if(walk.length === 10){
      for (let i of walk) { 
        if (i == 'n') ns += 1; 
        if (i == 's') ns -= 1; 
        if (i == 'e') ew += 1; 
        if (i == 'w') ew -= 1; 
      } 
    }
    else
      return false
      return ns === 0 &amp;amp;&amp;amp; ew === 0; 
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to some other best and clever solutions:&lt;br&gt;
Most upvoted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def isValidWalk(walk):
    return len(walk) == 10 and walk.count('n') == walk.count('s') and walk.count('e') == walk.count('w')

Second one:
def isValidWalk(walk):
    if (walk.count('n') == walk.count('s') and 
        walk.count('e') == walk.count('w') and
        len(walk) == 10):
            return True
    return False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope it was helpful and useful. Please let me know your thoughts. Thank You for reading.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>codewars</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
