Claude Code in Production: Where It Earns Its Place and Where It Does Not
Where an agentic coding tool earns its place in real engineering work, where it does not and why the reviewer is now the constraint. Claude Code as the worked example, with the tradeoffs named.
The bottleneck moved, and most teams have not repriced their process around it. Writing the first draft of a change used to be the expensive part. Put Claude Code in production engineering work on anything past a toy repo and the expensive part becomes deciding whether the diff in front of you is correct, about code you did not write. Different skill. Slower than people expect. Not in anyone's sprint plan.
What follows is where an agentic coding tool earns its keep, where it costs more than it saves and which practices move its output from plausible to shippable. Claude Code is the worked example because its behaviour is documented in enough detail to argue about mechanisms. Most of it transfers to Cursor, to GitHub Copilot's agent mode and to anything running the same loop.
Reconnaissance, mechanical breadth and the tests nobody wrote
Claude Code builds no vector index of your repository. No embedding step, no stale index. It searches the way you would: glob for filenames, regex through contents, read what matched, run commands, read git history. Two consequences follow. It works on a repository it has never seen with zero setup. And every file it reads costs context, which is why an unscoped "investigate this" fills the window with files that turned out not to matter.
Reconnaissance on unfamiliar code is the use I would defend hardest. Ask it what you would ask the engineer who has been there five years. How does logging work here. What edge cases does this onboarding class actually handle. Read the git history of this file and tell me how the API ended up like this. That last one is the good trick, because commit messages are where reasons hide when nobody wrote a doc. Do the reading in a subagent: subagents run in a separate context window and return a summary, so forty file reads land outside your budget.
Mechanical refactors across many files are the second place it pays, and the property that makes them safe deserves naming. The correctness criterion is mechanical. A rename, a changed signature, a helper moved to a shared module: a compiler, a type checker or an existing suite can tell you whether it worked. Migration sweeps are the same shape at scale. Claude Code will fan a change across 5 to 30 subagents, each in its own git worktree opening its own pull request, and you can drive the same pattern yourself with a shell loop over `claude -p` and `--allowedTools`. Run it on two or three files first, fix the prompt on what went wrong, then run the set. Your prompt is the migration script. Debug it like one.
Test writing is real and has a trap in it. Generating tests for a module that has none is the cheapest net you can put under legacy code before you touch it. The failure mode I keep meeting is a suite written by reading the implementation, so it asserts what the code does instead of what it should do, and goes green on the bug. When you are fixing something, make it write the failing test first, from the bug report, and watch it fail before anything gets fixed.

It is a pull request from a competent stranger: fluent in the language, has read your codebase, present for none of your incidents.
The decision made two years ago that nobody wrote down
The model reads your code, your tests, your docs and your git history. It cannot read the 3am incident that produced the retry with the strange backoff, the contract that froze a field name that is wrong in every other respect or the vendor firmware bug the sleep is there to survive.
The shape I keep meeting is a controller that polls where it obviously should subscribe. Every instinct says event-driven. The refactor is clean, the tests pass, and on the floor it fails at shift change because the device drops subscriptions under a load pattern that appears only when several lines start together. Nothing in the repository says that. The agent removed the fence because no evidence available to it explained the fence, which is correct reasoning on the evidence it had.
The correction is not a better prompt. It is writing the reason down, near the code, in a form the agent loads. The uncomfortable part is that the reason was missing before the agent existed. The agent did not create that debt, it calls it in faster and at a worse moment.
The other boundary is work whose requirement is genuinely unsettled. If you cannot state what correct means, you get a confident implementation of one interpretation and you spend the review arguing with an answer to a question you never resolved. That is a specification failure wearing a diff.
Practices that change the output, not the prompt style
CLAUDE.md loads at the start of every session, which is why it should be short. Anthropic's guidance is to target under 200 lines and to test each line by asking whether removing it would cause a mistake. A bloated file does not make the agent better informed, it makes your real rules harder to find. Run `/context` to confirm it loaded at all. Put sometimes-relevant material in `.claude/rules/` with a `paths` frontmatter block so it loads only when the agent touches matching files.
The distinction most people miss: CLAUDE.md is context, not enforcement. The documentation says it plainly, the agent treats it as advice with no guarantee of compliance. If something must happen every time, write a hook. A PreToolUse hook can block writes to your migrations directory outright. A Stop hook runs your check as a script and refuses to let the turn end until it passes, though Claude Code overrides it after eight consecutive blocks rather than looping. Anything you cannot afford to have skipped belongs in a hook, not a bullet point.
Give it a check it can run. Without one, "looks done" is the only stopping signal and you become the verification loop personally, so every mistake waits for you to notice it. With a test suite or a build exit code, the loop closes on its own. Ask for the evidence too: the command and its output, not an assurance that tests pass.
Keep diffs reviewable. Plan mode separates exploration from execution and lets you edit the plan before any file changes, which earns its overhead when a change spans several files, and does not when you could describe the diff in one sentence. One gotcha: checkpoints snapshot files before the agent's editing tools touch them, but changes made through Bash are not captured. If it ran a `sed` sweep, that work is outside the rewind. Commit before you hand over anything with breadth.
Then the framing that changes how you read the result. It is a pull request from a competent stranger: fluent in the language, has read your codebase, present for none of your incidents, optimising for the task exactly as stated. That tells you where to look. Not syntax. Intent, scope creep and the assumptions it invented because you did not supply them.
Reviewing generated code is a different skill from writing it
When you write code, review happens as a by-product. By the time the function is done you have rejected four other versions and you hold the reason for every branch. Reading a diff you did not write, you have the text and none of that. You are reverse-engineering intent from result, which is harder, and which most engineers have never had to do at volume.
The failure class is specific: plausible. Naming is right. Structure matches the surrounding code. Tests pass. The error is one layer down. An off-by-one at a boundary no test covers. An exception swallowed to make a test green. A new helper duplicating one already in your utils module, because the agent optimised for the local task and does not know your shared code by heart unless told to look.
It shows up in survey data. In Stack Overflow's 2025 developer survey the top frustration with AI tooling, at 66%, was solutions that are almost right but not quite, and 45% said debugging AI-generated code takes more time. More developers actively distrust the accuracy of the output, 46%, than trust it, 33%.
What works in practice: read the diff against the intent rather than line by line, ask what the change cannot do, grep every caller of what changed, search for error-masking (a broadened except clause, a widened type, a default hiding a missing value) and look for a new function that should have been an import. Then review in a fresh context. A subagent seeing only the diff and your criteria is not biased toward code it just wrote, and the bundled `/code-review` does this for correctness. One caveat from Anthropic's own docs: a reviewer told to find gaps will find some whether or not they exist. Tell it to flag correctness and stated requirements only.
Review does not parallelise inside one head. Accept three times the diffs and you need three times the review, and generated code reviews slower per line than a colleague's, because a colleague can tell you why.
Claude Code in production splits the senior and the junior job
For a senior engineer the trade is good, for an unglamorous reason. The tool automates what was already cheap for them, typing out a solution they had already decided on, and multiplies what was already their constraint, deciding what should exist. The gain is largest where their knowledge is thinnest: an unfamiliar service, a language they touch twice a year, a mechanical change across two hundred files nobody wants to make by hand.
Sit with the counterexample. METR ran a randomised controlled trial with 16 experienced open-source developers across 246 real tasks in repositories they knew deeply. With AI tools allowed they were 19% slower. They had forecast a 24% speedup and still believed afterwards they had been sped up by 20%. METR is careful about the limits: early-2025 tooling, one setting, no claim about developers in general. Two things I take from it. Your sense of your own speed is not evidence. And it measured the one condition where the tool has least to offer, an expert working in code they already hold in their head.
For a junior the same tool removes the part of the job that was the training. Judgement gets built by being wrong in a way that costs something and having to find out why. If the first draft is free and roughly right, that loop does not run. You get someone producing working code at a rate their understanding does not support, and the gap surfaces under pressure, at the moment the generated answer is wrong and there is no obvious next move.
Banning the tool for juniors is unenforceable and produces engineers who cannot work the way the industry works. The version I would try is inverting the apprenticeship: review before you generate. Five generated diffs with three real bugs in them, reviewed by a junior and checked by someone senior, teaches more per hour than writing the function did. It trains judgement instead of production, which is where the scarcity moved. I am not certain it works. Reviewing well seems to require having built the thing at least once, a bootstrapping problem I have no clean answer to.
The strongest argument against all of this
The counter-argument is not that the tool writes bad code. It is that first-draft velocity is easy to see and review debt is not, so teams optimise the visible one and meet the other in production.
DORA's 2025 report on AI-assisted development surveyed nearly 5,000 technology professionals. Adoption reached 90%, at a median of two hours a day. Unlike the previous year they found a positive relationship between AI adoption and both delivery throughput and product performance. They also found AI adoption still carries a negative relationship with delivery stability. Their explanation is the one I would give. Acceleration exposes weakness downstream, so without strong automated testing, mature version control and fast feedback, more change volume means more instability. Loosely coupled architectures gain. Tightly coupled ones with slow processes see little.
GitClear's numbers point the same way, with a caveat first. It is a vendor analysing git diffs, the relationship is correlational and they do not claim AI causes it. Across 623 million changes from 2023 to 2026 they report moved lines, their proxy for refactoring, falling from 21% in 2022 to 3.8% year to date, copy-paste rising from 9.4% to 15.7% and duplicated blocks up 81%. Whatever the cause, the direction matches what a per-task optimiser does: write the code rather than go find the existing helper.
The concession I will make. If throughput went up and your incident rate went up with it, you did not get faster, you moved work from before the merge to after it, where it costs more. And the second-order effect is worse than the bugs. A codebase accumulates a growing fraction of lines no human has read carefully. Review was never only a bug filter, it was the main channel by which knowledge about a system spread through a team. Rubber-stamping generated diffs keeps the filter and quietly removes the channel.
None of that is an argument against the tool. It is an argument for what DORA calls amplification. Tests, fast feedback, loose coupling and real discipline at the gate decide whether extra throughput becomes shipped value or accelerated mess. The tool supplies none of them.
What nobody can generate
The measure I would use is not how much code the team shipped this quarter. It is whether anyone can still answer why a given line exists.
That is the asymmetry underneath all of it. Generation went close to free. Reading did not. Explaining did not. An agent will write the fence, correctly, in the style of the surrounding fences, with tests. It cannot tell you what the fence was for. Neither can you, six months later, if the only record of the reasoning was a prompt in a session you cleared.
Tools referenced
Claude, reviewed here: Claude review.
Cursor, reviewed here: Cursor review.
GitHub Copilot, reviewed here: GitHub Copilot review.
Devin, reviewed here: Devin review.
Sources
Best practices for Claude Code, Anthropic documentation: https://code.claude.com/docs/en/best-practices
How Claude remembers your project: CLAUDE.md and auto memory, Anthropic documentation: https://code.claude.com/docs/en/memory
How Claude Code works: the agentic loop, tools and context, Anthropic documentation: https://code.claude.com/docs/en/how-claude-code-works
METR, Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity: https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/
DORA, State of AI-assisted Software Development 2025: https://dora.dev/dora-report-2025/
Google Cloud, Announcing the 2025 DORA Report: https://cloud.google.com/blog/products/ai-machine-learning/announcing-the-2025-dora-report
Stack Overflow 2025 Developer Survey, AI section: https://survey.stackoverflow.co/2025/ai
GitClear, The Maintainability Gap: 2026 AI Code Quality Research: https://www.gitclear.com/the_ai_code_quality_maintainability_gap
Frequently Asked Questions
What is Claude Code genuinely good at in a production codebase?
Four things it reliably earns its place on: reconnaissance in unfamiliar code, mechanical refactors across many files, migration sweeps and writing tests for modules that have none. The common property is that correctness is checkable by a machine. A rename, a changed call signature or a Python 2 to 3 sweep can be validated by a compiler, a type checker or an existing test suite. Where the correctness criterion lives only in human judgement, the tool produces something plausible and hands you the hard part.
Does Claude Code index my repository?
No. There is no embedding step and no vector index to build or keep fresh. Claude Code searches agentically: it globs for filenames, runs regex searches over contents, reads the files that matched, runs shell commands and reads git history. The practical upside is that it works on a repository it has never seen with zero setup. The practical cost is that every file it reads consumes context, so an unscoped investigation can fill the context window with files that turned out to be irrelevant. Delegating research to a subagent keeps that reading out of your main session.
What belongs in a CLAUDE.md file?
Facts Claude cannot derive from reading the code: build and test commands, conventions that differ from language defaults, repository etiquette, environment quirks and the non-obvious reasons behind decisions. Anthropic recommends targeting under 200 lines, because a long file makes real rules harder to find and reduces adherence. Test each line by asking whether removing it would cause a mistake. Run /context to confirm the file actually loaded. Instructions that only matter for part of the codebase belong in path-scoped rules under .claude/rules/ instead.
How do I stop an agentic coding tool from doing something I cannot afford?
Do not rely on CLAUDE.md. Anthropic's documentation is explicit that CLAUDE.md is context rather than enforced configuration, so the model may not comply. For anything that must happen every time, use a hook: a PreToolUse hook can block writes to a protected directory outright, and a Stop hook can run your check as a script and refuse to end the turn until it passes. Note also that checkpoints only capture changes made through Claude's file-editing tools, so anything done through a Bash command sits outside the rewind. Commit to git before handing over work with breadth.
Does AI coding assistance actually make experienced engineers faster?
Not automatically, and self-reported speed is unreliable. In METR's 2025 randomised controlled trial, 16 experienced open-source developers working on 246 real tasks in repositories they knew well were 19% slower when allowed to use AI tools, while estimating afterwards that they had been 20% faster. METR itself frames this as a snapshot of early-2025 tooling in one setting rather than a general result. The narrower lesson holds: the condition tested, an expert working in code they already hold in their head, is exactly where an agent has least to add.
How should junior engineers use agentic coding tools without stunting their judgement?
The risk is real. Judgement is built by being wrong in a costly way and having to find out why, and a free first draft skips that loop. Banning the tools does not work, since it produces engineers who cannot work the way their industry does. A better structure is to invert the apprenticeship and have juniors review generated diffs before they generate their own, with a senior checking the review. Finding three real bugs in five generated diffs trains judgement faster than writing the function did. The unresolved part is that reviewing well seems to require having built something at least once.
Read next
China's University Major Cuts Are AI Policy, and Nigeria Should Read the Fine Print
The latest analysis essay.
Working on something in this space?
If this analysis is close to a problem you're thinking about, say so. I read every message personally.
Start a conversation