<?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: Tony</title>
    <description>The latest articles on DEV Community by Tony (@thetonynotes).</description>
    <link>https://dev.to/thetonynotes</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%2F4205253%2F4988f6e5-0737-43ee-9de0-dab29922b4ab.jpg</url>
      <title>DEV Community: Tony</title>
      <link>https://dev.to/thetonynotes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thetonynotes"/>
    <language>en</language>
    <item>
      <title>If AI Can Write the Code, Where Do Software Developers Create Value?</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Fri, 30 Oct 2026 03:16:51 +0000</pubDate>
      <link>https://dev.to/thetonynotes/if-ai-can-write-the-code-where-do-software-developers-create-value-2c3j</link>
      <guid>https://dev.to/thetonynotes/if-ai-can-write-the-code-where-do-software-developers-create-value-2c3j</guid>
      <description>&lt;p&gt;I started writing code in 2009. Over the years, I've spent entire days solving problems, reading documentation, trying different approaches, and debugging until I finally understood what went wrong. Some systems took months to build and years to mature.&lt;/p&gt;

&lt;p&gt;Now, with AI coding agents, I can describe a requirement and get hundreds of lines of code back in minutes. Work that once took several days can sometimes reach a working first version in an afternoon. AI can also read a codebase, write tests, explain errors, and propose changes across multiple files.&lt;/p&gt;

&lt;p&gt;This has changed what it feels like to be a software developer. Skills that once took years to develop can now be applied with considerable assistance from AI. I suspect this is part of why some developers feel unsettled. When a large part of your professional work can suddenly be done much faster, where does that leave your value?&lt;/p&gt;

&lt;p&gt;I want to approach this question from the economics of the software industry, using a familiar concept from business strategy: the &lt;strong&gt;value chain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One thing worth remembering is that even before AI, writing code was only one stage of building and selling software. We spend years getting better at that stage, so it's understandable that we sometimes see the entire product through the work we do ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. How Does a Software Product Create Value?
&lt;/h2&gt;

&lt;p&gt;Imagine you're building inventory and sales management software for small retailers.&lt;/p&gt;

&lt;p&gt;Before writing anything, you need to understand the problems these businesses face. Maybe they manage inventory in spreadsheets, struggle to track which products are still in stock, or have trouble reconciling orders across multiple sales channels.&lt;/p&gt;

&lt;p&gt;You study how they operate, identify which problems matter most, decide what the software needs to do, and design a solution. Only then do you start coding.&lt;/p&gt;

&lt;p&gt;And when the code is written, there is still plenty of work left.&lt;/p&gt;

&lt;p&gt;The software needs testing, deployment, maintenance, and data protection. You need to find customers, help them get started, handle support requests, and improve the product based on how people actually use it.&lt;/p&gt;

&lt;p&gt;If you can't find customers, the product might never generate revenue. If users can't figure out how it works, even a feature-rich application can be abandoned. If the system constantly breaks, customers may leave despite the quality of its original implementation.&lt;/p&gt;

&lt;p&gt;Coding is an important link in a much longer chain.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvx5o1fy2mdq3m3ny8cvi.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvx5o1fy2mdq3m3ny8cvi.png" alt="Figure 1: The software value chain, from market research and design through development, distribution, operations, and customer retention. Coding is highlighted" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. The software value chain, from market research and design through development, distribution, operations, and customer retention. Coding is highlighted to show where it fits in the overall process.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Michael Porter's Value Chain framework, a business is understood through a set of connected activities, from creating a product and getting it to customers to providing service afterward. Competitive advantage comes from how a company organizes these activities, manages costs, and creates value that customers are willing to pay for.&lt;/p&gt;

&lt;p&gt;Applied to software, this helps separate three concepts that are often confused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use value&lt;/strong&gt; is the practical benefit the software provides. Good inventory management software might reduce losses, save employees time, and help a retailer make better purchasing decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Economic value created&lt;/strong&gt; concerns the benefits a solution produces relative to the resources required to deliver it. A piece of software might generate benefits far greater than its development cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Value captured by the business&lt;/strong&gt; is the portion of those benefits the company can turn into revenue and profit, accounting for costs, competition, and market conditions.&lt;/p&gt;

&lt;p&gt;These concepts are closely related, but they aren't interchangeable.&lt;/p&gt;

&lt;p&gt;An engineer might build an extremely sophisticated system that demonstrates exceptional technical skill. Yet if it doesn't solve an important problem or reach the right customers, the economic return may be small.&lt;/p&gt;

&lt;p&gt;Meanwhile, a simple application with only a handful of features can become a successful business if it solves the right problem, is easy to use, and has an effective way to reach customers.&lt;/p&gt;

&lt;p&gt;There are certainly products where deep technical capability is the main source of differentiation. Databases, infrastructure systems, security software, and applications with demanding reliability requirements are obvious examples.&lt;/p&gt;

&lt;p&gt;There is no universal formula for calculating what percentage of a software product's value comes from coding.&lt;/p&gt;

&lt;p&gt;What matters is recognizing that &lt;strong&gt;technical difficulty and the ability to capture economic value are separate things to evaluate&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Three Software Business Models, Three Ways to Create and Capture Value
&lt;/h2&gt;

&lt;p&gt;The software industry has many business models. I'll focus on three familiar ones: software outsourcing, software products, and Software as a Service (SaaS).&lt;/p&gt;

&lt;p&gt;All three require software development capabilities. But their revenue models, cost structures, and profit drivers differ considerably.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0qkq0f4ka0ufrcuqqmcc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0qkq0f4ka0ufrcuqqmcc.png" alt="Figure 2: The value chains of software outsourcing, software products, and SaaS. Different activities matter more for creating and capturing value in each model" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. The value chains of software outsourcing, software products, and SaaS. Different activities matter more for creating and capturing value in each model.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Software Outsourcing: Selling Delivery Capability
&lt;/h3&gt;

&lt;p&gt;In outsourcing, the customer usually already has a business need or a project they want delivered. A software company provides the people, expertise, and processes required to build the solution under a contract.&lt;/p&gt;

&lt;p&gt;Suppose a company takes on an $80,000 project to build an internal management system over six months.&lt;/p&gt;

&lt;p&gt;It needs to plan staffing, engineering costs, project management, testing, support, and potential risks.&lt;/p&gt;

&lt;p&gt;Coding may account for most of the direct engineering hours. But the company's profit also depends on winning the contract, negotiating a reasonable price, estimating the work accurately, controlling scope, allocating people effectively, and maintaining quality.&lt;/p&gt;

&lt;p&gt;A company can have excellent developers and still lose money if it consistently underestimates projects, fails to control changing requirements, or spends too much time fixing defects.&lt;/p&gt;

&lt;p&gt;In this model, programming expertise is an important production resource. The ability to organize that resource and deliver contracts effectively determines how much revenue the company can turn into profit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Software Product: Selling Software You Own
&lt;/h3&gt;

&lt;p&gt;In the software product model, a company researches, builds, owns, and commercializes its own software.&lt;/p&gt;

&lt;p&gt;Consider a company developing accounting software for small businesses. It needs to understand customer needs, build the right features, choose a pricing model, distribute the software, and provide support.&lt;/p&gt;

&lt;p&gt;Once the product is ready, the company can sell the same software to many customers without rebuilding it from scratch for every buyer.&lt;/p&gt;

&lt;p&gt;This is one of the important economic advantages of software products.&lt;/p&gt;

&lt;p&gt;The initial development cost may be high, but the cost of delivering another copy is often relatively low compared with physical goods. Operating, supporting, updating, and distributing the software still costs money, of course.&lt;/p&gt;

&lt;p&gt;Here, intellectual property ownership, product-market fit, brand, and distribution become especially important.&lt;/p&gt;

&lt;p&gt;You might own the source code for an excellent application, but that doesn't guarantee people will buy it. Customers still need to discover the product, trust it, and have a reason to choose it over available alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  SaaS: Selling Value Continuously
&lt;/h3&gt;

&lt;p&gt;SaaS shares many characteristics with the software product model, but its business depends more heavily on delivering an ongoing service, usually through subscriptions.&lt;/p&gt;

&lt;p&gt;Imagine a task management SaaS priced at $8 per month.&lt;/p&gt;

&lt;p&gt;With 1,000 paying customers, that produces $8,000 in monthly recurring revenue before adjustments.&lt;/p&gt;

&lt;p&gt;But maintaining that revenue requires reliable infrastructure, customer support, ongoing product improvements, and enough value to convince users to keep paying.&lt;/p&gt;

&lt;p&gt;If customers use the product for a month and then leave, the company may struggle even with a healthy number of new signups.&lt;/p&gt;

&lt;p&gt;If customers stay for years, the initial acquisition cost can be spread across a longer relationship, potentially improving the economics of the business.&lt;/p&gt;

&lt;p&gt;This is why SaaS companies pay close attention to metrics such as Customer Acquisition Cost (CAC), churn rate, Customer Lifetime Value (LTV), gross margin, and Net Revenue Retention (NRR).&lt;/p&gt;

&lt;p&gt;For SaaS, shipping the first working version is only the beginning of a much longer business process.&lt;/p&gt;

&lt;p&gt;Looking across all three models, coding capabilities are used in different ways. Yet revenue and profit depend on the entire chain of activities.&lt;/p&gt;

&lt;p&gt;That distinction matters when we consider how AI affects different software businesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. How Does AI Change the Value Curve?
&lt;/h2&gt;

&lt;p&gt;Another useful model for understanding the value chain is the &lt;em&gt;Smile Curve&lt;/em&gt;, which illustrates how value added may be distributed across different activities in an industry.&lt;/p&gt;

&lt;p&gt;In its typical form, activities near the beginning of the chain, such as research, design, and technology ownership, can generate substantial value. Activities near the end, including branding, distribution, and customer service, can also be valuable. Meanwhile, standardized production activities in the middle may face stronger price competition.&lt;/p&gt;

&lt;p&gt;I wanted to see what this perspective might suggest about software before and after AI.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkqd19x4uunyr85n391wr.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkqd19x4uunyr85n391wr.png" alt="Figure 3: A conceptual model of how differentiation and value capture may shift across the software value chain. The curves represent a strategic hypothesis, no" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. A conceptual model of how differentiation and value capture may shift across the software value chain. The curves represent a strategic hypothesis, not measured empirical data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before AI, turning requirements into working software generally required substantial specialized labor.&lt;/p&gt;

&lt;p&gt;A company building a product needed to hire or contract developers who could write code, design systems, test functionality, and deploy applications.&lt;/p&gt;

&lt;p&gt;Programming skills had a degree of scarcity, which gave people with those skills a meaningful advantage.&lt;/p&gt;

&lt;p&gt;AI is changing that.&lt;/p&gt;

&lt;p&gt;Someone who understands a product and knows how to work effectively with AI can build prototypes faster. Developers can use coding agents to generate initial implementations, add tests, refactor code, and understand unfamiliar codebases.&lt;/p&gt;

&lt;p&gt;Repetitive technical work that can be clearly specified is becoming easier to automate. In many situations, the cost of producing a unit of software output may fall.&lt;/p&gt;

&lt;p&gt;From an economic perspective, when a capability becomes easier to obtain, competitive advantages based mainly on its scarcity may weaken.&lt;/p&gt;

&lt;p&gt;This is especially visible in common features such as CRUD interfaces, basic dashboards, landing pages, admin forms, and relatively standard integrations.&lt;/p&gt;

&lt;p&gt;If many competitors can build similar features at a lower cost, customers gain more choices. It becomes harder for a business to justify high prices simply because implementation takes a lot of engineering time.&lt;/p&gt;

&lt;p&gt;However, we should distinguish &lt;strong&gt;the value of coding activity&lt;/strong&gt; from &lt;strong&gt;competitive advantage based on coding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AI may increase the total amount of software being produced. Ideas that were previously too expensive to pursue may become viable. Demand for reliable, secure, maintainable software doesn't automatically disappear.&lt;/p&gt;

&lt;p&gt;What faces greater pressure is the ability to charge a premium solely for programming tasks that tools and competitors can increasingly perform.&lt;/p&gt;

&lt;p&gt;Competitive advantage may therefore shift toward other capabilities.&lt;/p&gt;

&lt;p&gt;At the beginning of the chain, these include understanding an industry, identifying the right problems, designing solutions, and making appropriate architectural decisions.&lt;/p&gt;

&lt;p&gt;At the other end, they include data, ecosystems, distribution channels, customer relationships, and the ability to deliver business outcomes that users actually care about.&lt;/p&gt;

&lt;p&gt;AI also increases the need for verification. When code can be generated faster, companies need effective ways to ensure that systems behave correctly, remain secure, and can be maintained over time.&lt;/p&gt;

&lt;p&gt;I think this is a reasonable way to understand the possible shift in value, although the shape of the curve will vary considerably across different types of software.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. How Much More Productive Has AI Made Developers?
&lt;/h2&gt;

&lt;p&gt;If AI can generate code in seconds, does that mean software development tasks get completed proportionally faster?&lt;/p&gt;

&lt;p&gt;Research suggests the answer depends heavily on the task, the developer's experience, the tools involved, and the working environment.&lt;/p&gt;

&lt;p&gt;In 2023, a study by Sida Peng and colleagues found that developers using GitHub Copilot completed a JavaScript HTTP server programming task 55.8% faster than developers without it.&lt;/p&gt;

&lt;p&gt;That is a significant result, but it was measured on a particular task in an experimental setting.&lt;/p&gt;

&lt;p&gt;McKinsey also published research in 2023 showing that generative AI could substantially reduce the time required for certain development activities, including code generation, documentation, and refactoring. The improvements varied according to task complexity and developer experience.&lt;/p&gt;

&lt;p&gt;Then, in July 2025, METR published a controlled experiment involving 16 experienced developers working on 246 tasks in open-source projects they already knew well.&lt;/p&gt;

&lt;p&gt;The result was surprising: under the conditions of that experiment, developers allowed to use AI took approximately 19% longer to complete their tasks.&lt;/p&gt;

&lt;p&gt;Interestingly, those developers still felt that AI had made them faster.&lt;/p&gt;

&lt;p&gt;In February 2026, METR published a follow-up. The researchers observed signs that newer tools were improving productivity, but limitations involving participant selection and measurement prevented them from making a reliable estimate of the speedup.&lt;/p&gt;

&lt;p&gt;I don't think these findings contradict the experience of watching AI produce code incredibly quickly.&lt;/p&gt;

&lt;p&gt;They remind us that generating code is only one part of completing a software development task.&lt;/p&gt;

&lt;p&gt;A developer still needs to understand the existing system, evaluate the impact of a change, verify the logic, handle errors, integrate the implementation, and make sure it can be deployed safely.&lt;/p&gt;

&lt;p&gt;Google's 2025 DORA report, drawing on a survey of nearly 5,000 technology professionals and qualitative research, makes an important observation: AI tends to amplify an organization's existing capabilities.&lt;/p&gt;

&lt;p&gt;Teams with strong engineering practices, platforms, and processes are generally better positioned to make effective use of AI.&lt;/p&gt;

&lt;p&gt;In an analysis published in March 2026, DORA also highlighted how time saved during code creation can shift into reviewing, evaluating, and verifying the result.&lt;/p&gt;

&lt;p&gt;A change generated quickly but difficult to review, poorly tested, or likely to break production may not improve the efficiency of the development process as a whole.&lt;/p&gt;

&lt;p&gt;This is why I think we should measure the time from identifying a need to delivering a stable, valuable solution, rather than measuring code generation speed alone.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgac5wys27hplt27pihp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftgac5wys27hplt27pihp.png" alt="Figure 4: AI may reduce code generation time, but overall productivity also depends on verification, integration, deployment, and operations." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. AI may reduce code generation time, but overall productivity also depends on verification, integration, deployment, and operations.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Why Do Some Developers Feel Unsettled?
&lt;/h2&gt;

&lt;p&gt;Becoming proficient in software engineering takes years of work.&lt;/p&gt;

&lt;p&gt;From learning your first programming language to understanding data structures, frameworks, databases, and eventually designing complete systems, the process requires continuous practice and accumulated experience.&lt;/p&gt;

&lt;p&gt;When someone spends most of their working life solving coding problems, it's natural for programming to become central to their professional identity.&lt;/p&gt;

&lt;p&gt;Every difficult bug fixed, every complex query optimized, and every major system delivered reinforces that sense of competence.&lt;/p&gt;

&lt;p&gt;But along the way, I think it's easy to confuse three things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Difficult Work Does Not Always Have High Economic Value
&lt;/h3&gt;

&lt;p&gt;A difficult algorithm may require considerable expertise to implement. But if it solves a minor problem that few people care about, the economic value created may be limited.&lt;/p&gt;

&lt;p&gt;Meanwhile, something as simple as automated payment reminders could save a business significant manual work and improve its ability to collect outstanding payments.&lt;/p&gt;

&lt;p&gt;Technical difficulty and business benefit are sometimes connected, but they aren't always proportional.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Time Spent Does Not Necessarily Mean More Value
&lt;/h3&gt;

&lt;p&gt;A feature might have taken us three days to build in the past.&lt;/p&gt;

&lt;p&gt;If AI helps us build the same feature in three hours at the same level of quality, the customer may still receive essentially the same benefit.&lt;/p&gt;

&lt;p&gt;The amount of labor has decreased while the practical value remains.&lt;/p&gt;

&lt;p&gt;This is one of the ways technology creates productivity gains.&lt;/p&gt;

&lt;p&gt;What changes is the production cost and the way businesses can price the work.&lt;/p&gt;

&lt;p&gt;In a model that sells engineering hours, this creates direct pressure. In a model that sells products, lower development costs may allow a business to test more ideas or improve margins, depending on competition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Something Does Not Guarantee That the Market Will Pay for It
&lt;/h3&gt;

&lt;p&gt;This is something people with engineering backgrounds, myself included, need to keep reminding ourselves.&lt;/p&gt;

&lt;p&gt;We often feel a product is nearly finished when its main features are working reliably.&lt;/p&gt;

&lt;p&gt;But from a business perspective, it may still be at a very early stage.&lt;/p&gt;

&lt;p&gt;Does anyone actually need it? How are they solving the problem now? Are they willing to pay? How will we reach them? Is the product good enough for them to keep using it?&lt;/p&gt;

&lt;p&gt;Writing more code usually won't answer those questions.&lt;/p&gt;

&lt;p&gt;AI makes the differences between these three ideas more visible.&lt;/p&gt;

&lt;p&gt;As the time and effort required for many programming tasks decrease, we have another reason to reconsider how our work contributes to value across the whole system.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. How the Value Curve Changes for Outsourcing, Software Products, and SaaS
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3wpoznedl26h0kexjgx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3wpoznedl26h0kexjgx.png" alt="Figure 5: A conceptual comparison of how competitive advantage may shift across three software business models. These curves are analytical hypotheses and canno" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5. A conceptual comparison of how competitive advantage may shift across three software business models. These curves are analytical hypotheses and cannot be used to infer each activity's share of profit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;software outsourcing&lt;/strong&gt;, AI may allow the same team to complete more work.&lt;/p&gt;

&lt;p&gt;But if both the provider and the customer continue to price everything strictly by labor hours, greater productivity can create pricing challenges.&lt;/p&gt;

&lt;p&gt;Outsourcing companies need to consider how to turn productivity improvements into profit, higher-value services, or outcome-based contracts when results can be measured appropriately.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;software products&lt;/strong&gt;, lower initial development costs make it easier for more people to enter the market.&lt;/p&gt;

&lt;p&gt;This creates opportunities for small teams and independent developers, but also increases the number of competing products.&lt;/p&gt;

&lt;p&gt;When common features can be replicated quickly, owning a particular feature may offer less protection against competition.&lt;/p&gt;

&lt;p&gt;Understanding the market, building a brand, owning intellectual property, and reaching customers become increasingly important.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;SaaS&lt;/strong&gt;, AI can help companies build and improve products faster, including features that would previously have been too expensive to implement.&lt;/p&gt;

&lt;p&gt;But the business still needs to retain customers, maintain service quality, and operate with a sustainable cost structure.&lt;/p&gt;

&lt;p&gt;Costs related to AI models, inference, infrastructure, and agent operations may also change SaaS economics.&lt;/p&gt;

&lt;p&gt;I think AI increases both the opportunities and the competitive pressure across all three models.&lt;/p&gt;

&lt;p&gt;The ability to develop software faster doesn't guarantee that a company will make more money.&lt;/p&gt;

&lt;p&gt;The outcome depends on whether the company can turn that productivity into customer value and competitive advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Where Should Developers Go From Here?
&lt;/h2&gt;

&lt;p&gt;I don't think every developer needs to become a founder, product manager, or business specialist.&lt;/p&gt;

&lt;p&gt;We still need engineers with deep technical expertise, particularly for complex systems with demanding reliability requirements.&lt;/p&gt;

&lt;p&gt;But I do think we should broaden our understanding of the work happening before and after the part we're responsible for.&lt;/p&gt;

&lt;p&gt;Here are five areas worth developing.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Understand the Problem Before Choosing a Solution
&lt;/h3&gt;

&lt;p&gt;When you receive a development request, spend time understanding what users actually need.&lt;/p&gt;

&lt;p&gt;Suppose a customer asks for an order tracking dashboard.&lt;/p&gt;

&lt;p&gt;Before choosing a charting library, ask what decisions they need to make using that dashboard.&lt;/p&gt;

&lt;p&gt;Perhaps their real problem is identifying delayed deliveries.&lt;/p&gt;

&lt;p&gt;In that case, a timely alert system might be more useful than a complex dashboard.&lt;/p&gt;

&lt;p&gt;Understanding the underlying problem helps us avoid building things nobody really needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Go Deeper Into Systems Thinking and Architecture
&lt;/h3&gt;

&lt;p&gt;AI can generate code, but someone still needs to take responsibility for how the components of a system work together.&lt;/p&gt;

&lt;p&gt;It's worth developing a solid understanding of data modeling, transactions, concurrency, authorization, security, integrations, scalability, and operations.&lt;/p&gt;

&lt;p&gt;For example, AI can generate an API that receives orders from an ecommerce platform relatively quickly.&lt;/p&gt;

&lt;p&gt;But what should happen if the same order is submitted twice?&lt;/p&gt;

&lt;p&gt;What if payment succeeds but the inventory update fails?&lt;/p&gt;

&lt;p&gt;What if a request is retried after a timeout?&lt;/p&gt;

&lt;p&gt;These are problems involving data integrity and system design.&lt;/p&gt;

&lt;p&gt;Being able to handle them correctly creates substantial value when software is used in real operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Use AI Within a Verifiable Engineering Workflow
&lt;/h3&gt;

&lt;p&gt;I believe learning to work with AI coding agents should now be part of a developer's professional development.&lt;/p&gt;

&lt;p&gt;Beyond knowing how to assign tasks to AI, we need to provide useful context, define acceptance criteria, design tests, review changes, and evaluate results.&lt;/p&gt;

&lt;p&gt;One practical habit is to write down the conditions for successful completion before asking AI to implement anything.&lt;/p&gt;

&lt;p&gt;For example, when building a payment feature, the acceptance criteria might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each transaction must be recorded only once.&lt;/li&gt;
&lt;li&gt;Partial payments must not be marked as fully paid.&lt;/li&gt;
&lt;li&gt;Repeated webhooks must not update a balance twice.&lt;/li&gt;
&lt;li&gt;Every update must leave a trace that can be reconciled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI can then help write the implementation and tests, but the results still need to be verified against those conditions.&lt;/p&gt;

&lt;p&gt;This shifts our attention from the amount of code produced to whether the system behaves correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Understand the Business Lifecycle of Software
&lt;/h3&gt;

&lt;p&gt;If you work at a software company, try to understand what happens to the product after deployment.&lt;/p&gt;

&lt;p&gt;How do customers discover it? Why do they choose it? How much does it cost to serve one customer? Where do users tend to give up? What problems generate support requests?&lt;/p&gt;

&lt;p&gt;If you work on SaaS, learn about CAC, churn, retention, and LTV.&lt;/p&gt;

&lt;p&gt;If you work in outsourcing, understand how projects are estimated, priced, and managed for profitability.&lt;/p&gt;

&lt;p&gt;You don't need to own these responsibilities yourself.&lt;/p&gt;

&lt;p&gt;But understanding them can help you make engineering decisions that better support the business.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Measure Outcomes, Not Just Technical Output
&lt;/h3&gt;

&lt;p&gt;A developer might complete 20 tickets in a sprint.&lt;/p&gt;

&lt;p&gt;That's useful information for tracking work, but it doesn't tell us what those changes accomplished.&lt;/p&gt;

&lt;p&gt;We can start connecting engineering work to more concrete results: reducing order processing time, decreasing defects, improving workflow completion rates, lowering operating costs, or improving system response times.&lt;/p&gt;

&lt;p&gt;Of course, not every engineering task can be tied directly to revenue.&lt;/p&gt;

&lt;p&gt;Reliability, security, maintainability, and developer experience are important outcomes too.&lt;/p&gt;

&lt;p&gt;The goal is to understand how our work contributes to the results the product is supposed to achieve.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvu3h3qzoz9xj7apr5nno.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvu3h3qzoz9xj7apr5nno.png" alt="Figure 6: Five directions for developers to grow beyond coding execution: problem understanding, system architecture, AI engineering, product thinking, and outc" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 6. Five directions for developers to grow beyond coding execution: problem understanding, system architecture, AI engineering, product thinking, and outcome measurement.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. So, Does Coding Still Matter?
&lt;/h2&gt;

&lt;p&gt;I think it does, and I expect it will continue to matter for a long time.&lt;/p&gt;

&lt;p&gt;But the way we apply that skill may change considerably.&lt;/p&gt;

&lt;p&gt;Experienced developers have an advantage when working with AI because they understand systems, can evaluate proposed solutions, and can recognize mistakes that less experienced people might miss.&lt;/p&gt;

&lt;p&gt;At the same time, AI gives people with domain expertise new opportunities to participate in software development.&lt;/p&gt;

&lt;p&gt;Someone who understands accounting, education, business operations, or marketing may now be able to build prototypes, test ideas, and contribute more directly to developing software.&lt;/p&gt;

&lt;p&gt;As more people gain the ability to build, those of us with technical backgrounds need to think carefully about what makes our expertise distinctive.&lt;/p&gt;

&lt;p&gt;For some, that may mean deep specialization in distributed systems, security, data, or performance optimization.&lt;/p&gt;

&lt;p&gt;For others, it may mean combining engineering with industry knowledge, product design, or the ability to lead complex projects.&lt;/p&gt;

&lt;p&gt;There isn't one path that works for everyone.&lt;/p&gt;

&lt;p&gt;Personally, I still enjoy programming.&lt;/p&gt;

&lt;p&gt;Turning an idea into something that actually works has always been satisfying. AI makes that process even more interesting because I can experiment with things I previously didn't have enough time to build.&lt;/p&gt;

&lt;p&gt;But the more I work with AI, the more attention I find myself paying to what should be built, why it needs to exist, what constraints must be respected, and how we can tell whether a solution is actually good.&lt;/p&gt;

&lt;p&gt;Writing code faster doesn't answer those questions for us.&lt;/p&gt;

&lt;p&gt;Looking at the entire value chain, I think AI presents a meaningful opportunity for developers.&lt;/p&gt;

&lt;p&gt;We may be able to spend less time on certain implementation tasks and more time understanding problems, designing systems, verifying quality, and delivering results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customers ultimately pay for the problems software solves and the value it delivers. The number of lines we write is rarely what matters to them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Coding remains one of the capabilities that helps create that value.&lt;/p&gt;

&lt;p&gt;As AI changes how coding gets done, this seems like a good time to reconsider where our own work fits within the software value chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;The following sources informed the theoretical framework and helped me examine the evidence on AI's impact. The value curves in this article are my own conceptual illustrations, not empirical measurements from these studies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Michael E. Porter, &lt;a href="https://www.isc.hbs.edu/strategy/business-strategy/Pages/the-value-chain.aspx" rel="noopener noreferrer"&gt;The Value Chain&lt;/a&gt;, Harvard Business School, Institute for Strategy and Competitiveness.&lt;/li&gt;
&lt;li&gt;Sida Peng et al. (2023), &lt;a href="https://arxiv.org/abs/2302.06590" rel="noopener noreferrer"&gt;The Impact of AI on Developer Productivity: Evidence from GitHub Copilot&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;McKinsey (2023), &lt;a href="https://www.mckinsey.com/capabilities/tech-and-ai/our-insights/unleashing-developer-productivity-with-generative-ai" rel="noopener noreferrer"&gt;Unleashing Developer Productivity with Generative AI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;METR (2025), &lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;METR (2026), &lt;a href="https://metr.org/blog/2026-02-24-uplift-update/" rel="noopener noreferrer"&gt;We are Changing our Developer Productivity Experiment Design&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google DORA (2025), &lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;State of AI-assisted Software Development&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google DORA (2026), &lt;a href="https://dora.dev/insights/balancing-ai-tensions/" rel="noopener noreferrer"&gt;Balancing AI Tensions: Moving from AI Adoption to Effective SDLC Use&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What Actually Belongs in CLAUDE.md?</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Wed, 28 Oct 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/thetonynotes/what-actually-belongs-in-claudemd-3beo</link>
      <guid>https://dev.to/thetonynotes/what-actually-belongs-in-claudemd-3beo</guid>
      <description>&lt;p&gt;I’m Tony. I build and run web products, and I use Claude Code as my main development tool every day. A common problem with coding agents starts when an instruction file grows every time the agent makes a mistake. You add an architecture rule, then a testing reminder, then a preference about formatting, and eventually &lt;code&gt;CLAUDE.md&lt;/code&gt; contains permanent policies mixed with notes from tasks nobody remembers.&lt;/p&gt;

&lt;p&gt;The problem isn't simply that the file is long. It's that different instructions have different lifetimes, scopes, and purposes, yet we ask the agent to treat them as one document. In this article, I'll show you how I separate project rules, reusable procedures, and temporary task instructions. You'll leave with a minimal Claude Code configuration, a reusable Skill, a task brief template, and a way to test whether the arrangement actually works.&lt;/p&gt;

&lt;p&gt;This is the second article in &lt;strong&gt;Making Coding Agents Reliable&lt;/strong&gt;, a series about building, verifying, and maintaining software with coding agents. The article on trusting code you didn't write in this series focuses on verification. Here, we'll focus on the configuration that guides the agent before it starts making changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  More instructions do not automatically produce better behavior
&lt;/h2&gt;

&lt;p&gt;Consider a TypeScript monorepo with an administrative web application, a multi-tenant API, and two shared packages. The team uses pnpm, enforces tenant isolation in the API, and maintains reusable components separately from application code. These constraints matter, but they don't all need to appear in every instruction the agent reads.&lt;/p&gt;

&lt;p&gt;A developer might start with three useful lines in &lt;code&gt;CLAUDE.md&lt;/code&gt; and keep adding more whenever an output looks wrong. An unsuccessful component change produces a rule about UI reuse. An incomplete API test produces another testing reminder. Eventually, the file contains instructions that overlap or contradict each other.&lt;/p&gt;

&lt;p&gt;For example:&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="p"&gt;-&lt;/span&gt; Always create a separate component for new features.
&lt;span class="p"&gt;-&lt;/span&gt; Reuse existing components whenever possible.
&lt;span class="p"&gt;-&lt;/span&gt; Never modify shared components without approval.
&lt;span class="p"&gt;-&lt;/span&gt; Keep component implementations as small as possible.
&lt;span class="p"&gt;-&lt;/span&gt; Follow the approach used in the previous reporting task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These statements don't establish a consistent decision process. The first two can conflict, while the final instruction refers to a task that may no longer be relevant. Adding more language doesn't resolve which instruction should control the next change.&lt;/p&gt;

&lt;p&gt;Claude Code's official guidance recommends specific, verifiable instructions and removing outdated or conflicting rules. Conflicting instructions can produce unpredictable choices. I treat this as a maintenance problem rather than something to solve by writing increasingly forceful prompts.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1w7d6ej9pe0ykdll4r65.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1w7d6ej9pe0ykdll4r65.png" alt="Instruction ownership map" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The useful distinction is between information Claude needs for the project, procedures it needs for certain kinds of work, and requirements that apply only to the current task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give CLAUDE.md a clear responsibility
&lt;/h2&gt;

&lt;p&gt;I use &lt;code&gt;CLAUDE.md&lt;/code&gt; for durable information about the repository and its development expectations. It should help Claude understand where code belongs, which boundaries matter, and what evidence the team expects before calling a change complete. It doesn't need to reproduce the architecture documentation or describe every possible workflow.&lt;/p&gt;

&lt;p&gt;Here's the fictional repository we'll use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── CLAUDE.md
├── apps/
│   ├── admin/
│   └── api/
├── packages/
│   ├── ui/
│   └── shared/
├── .claude/
│   ├── rules/
│   └── skills/
└── docs/
    └── architecture.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal root &lt;code&gt;CLAUDE.md&lt;/code&gt; could look like this:&lt;br&gt;
&lt;/p&gt;

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

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

TypeScript monorepo managed with pnpm.
&lt;span class="p"&gt;
-&lt;/span&gt; apps/admin: administrative web application
&lt;span class="p"&gt;-&lt;/span&gt; apps/api: multi-tenant backend API
&lt;span class="p"&gt;-&lt;/span&gt; packages/ui: reusable UI components
&lt;span class="p"&gt;-&lt;/span&gt; packages/shared: shared types and utilities

&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Keep application logic inside its application.
&lt;span class="p"&gt;-&lt;/span&gt; Shared packages must not import application code.
&lt;span class="p"&gt;-&lt;/span&gt; Check affected consumers before changing public contracts.
&lt;span class="p"&gt;-&lt;/span&gt; Preserve existing behavior outside the requested scope.

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

Before editing:
&lt;span class="p"&gt;-&lt;/span&gt; Identify affected packages.
&lt;span class="p"&gt;-&lt;/span&gt; Read the relevant implementation and tests.
&lt;span class="p"&gt;-&lt;/span&gt; Identify assumptions that affect the change.

Before reporting completion:
&lt;span class="p"&gt;-&lt;/span&gt; Run relevant available checks.
&lt;span class="p"&gt;-&lt;/span&gt; Report executed commands and their results.
&lt;span class="p"&gt;-&lt;/span&gt; State which checks were not run.
&lt;span class="p"&gt;-&lt;/span&gt; Summarize changed behavior and remaining risks.

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

API tests: pnpm -F api test

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

Architecture: docs/architecture.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template establishes useful boundaries without prescribing every implementation step. It also gives the agent a concrete verification command and a reporting contract. The example assumes the API package is named &lt;code&gt;api&lt;/code&gt; in its &lt;code&gt;package.json&lt;/code&gt; and defines a &lt;code&gt;test&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;Claude Code supports several instruction locations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Personal instructions across projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;./CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shared project instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;./.claude/CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Alternative shared project location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;./CLAUDE.local.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Personal instructions for one project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed policy file&lt;/td&gt;
&lt;td&gt;Organization-managed instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Commit shared project instructions so changes can be reviewed. Keep &lt;code&gt;CLAUDE.local.md&lt;/code&gt; out of Git by adding it to &lt;code&gt;.gitignore&lt;/code&gt;. When Claude Code launches, it loads applicable instruction files in the working directory and its parents, while instructions in subdirectories load when Claude accesses files there.&lt;/p&gt;

&lt;p&gt;These files accumulate in context rather than overriding one another. That means a personal preference and a project rule can both appear, even when they disagree. Avoid using multiple files to express competing versions of the same requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep area-specific rules out of the root
&lt;/h3&gt;

&lt;p&gt;Tenant isolation is essential for our API, but it doesn't need to accompany every frontend task. Claude Code supports path-scoped instruction files in &lt;code&gt;.claude/rules/&lt;/code&gt;. A file with &lt;code&gt;paths&lt;/code&gt; frontmatter loads when Claude reads or edits a matching file.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;.claude/rules/api.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;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/api/**/*.ts"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# API Rules&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Resolve the authenticated tenant before
  accessing tenant-owned data.
&lt;span class="p"&gt;-&lt;/span&gt; Scope tenant-owned queries to that tenant.
&lt;span class="p"&gt;-&lt;/span&gt; Validate authorization before accepting
  a tenant identifier from request input.
&lt;span class="p"&gt;-&lt;/span&gt; Add tests for authorized and denied access.
&lt;span class="p"&gt;-&lt;/span&gt; Test cross-tenant access boundaries.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For UI conventions, create a separate file with paths such as &lt;code&gt;packages/ui/**/*.ts&lt;/code&gt; and &lt;code&gt;packages/ui/**/*.tsx&lt;/code&gt;. Rules without &lt;code&gt;paths&lt;/code&gt; frontmatter load at launch, so adding a file to &lt;code&gt;.claude/rules/&lt;/code&gt; doesn't automatically make it conditional. The distinction matters when you want a rule to apply only within a particular part of a monorepo.&lt;/p&gt;

&lt;p&gt;Another option is placing &lt;code&gt;CLAUDE.md&lt;/code&gt; directly under &lt;code&gt;apps/api/&lt;/code&gt;. That keeps instructions near the code they govern. I would choose either approach based on how the team maintains instructions, rather than duplicating the same policies in both.&lt;/p&gt;

&lt;h3&gt;
  
  
  References are not the same as imports
&lt;/h3&gt;

&lt;p&gt;Claude Code supports &lt;code&gt;@path/to/file&lt;/code&gt; imports inside instruction files. Relative paths resolve from the importing file, and imports support up to four nested levels. This helps split documents into manageable files, but importing content doesn't reduce how much context gets loaded.&lt;/p&gt;

&lt;p&gt;For a lengthy architecture document, I prefer a reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Architecture: docs/architecture.md

Read the relevant sections before changing
module boundaries or public API contracts.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives Claude a location to consult without importing the complete document into the initial instruction context. Official guidance also recommends keeping individual instruction files under roughly 200 lines. I treat that as a useful review threshold, not a reason to split one overloaded file into several files that all load together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move procedures into Skills
&lt;/h2&gt;

&lt;p&gt;Project rules tell the agent what must remain true. A Skill tells it how to perform a particular kind of work. I use Skills for repeatable activities with recognizable inputs, defined steps, and an output that someone else can inspect.&lt;/p&gt;

&lt;p&gt;Suppose the team regularly asks Claude to review API changes before merging. A useful review covers backward compatibility, authentication, tenant isolation, database changes, tests, and API documentation. Putting that entire procedure in the root &lt;code&gt;CLAUDE.md&lt;/code&gt; would make Claude carry review instructions even when implementing a button.&lt;/p&gt;

&lt;p&gt;A project Skill belongs at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/
└── skills/
    └── api-review/
        └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Skill is centered on &lt;code&gt;SKILL.md&lt;/code&gt;, with optional metadata in YAML frontmatter. Claude can use it when relevant or when you invoke it with &lt;code&gt;/api-review&lt;/code&gt;. Its description remains available for selection, while its full instructions load when invoked.&lt;/p&gt;

&lt;p&gt;Here's a focused example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-review&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Review API changes before merge, including compatibility, authorization, tenant isolation, migrations, tests, and documentation.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# API Review&lt;/span&gt;

Review the requested API changes.
Do not modify code, approve, merge, or deploy.

&lt;span class="gu"&gt;## Input&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Identify the Git base ref for comparison.
&lt;span class="p"&gt;-&lt;/span&gt; If the base ref is missing, request it.
&lt;span class="p"&gt;-&lt;/span&gt; Do not select a base ref without confirmation.

&lt;span class="gu"&gt;## Procedure&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Identify changed API files and related packages.
&lt;span class="p"&gt;2.&lt;/span&gt; Read relevant implementation and tests.
&lt;span class="p"&gt;3.&lt;/span&gt; Check request and response compatibility.
&lt;span class="p"&gt;4.&lt;/span&gt; Check authentication and authorization.
&lt;span class="p"&gt;5.&lt;/span&gt; Trace tenant context through data access.
&lt;span class="p"&gt;6.&lt;/span&gt; Review affected database schema changes.
&lt;span class="p"&gt;7.&lt;/span&gt; Check relevant tests and documentation.
&lt;span class="p"&gt;8.&lt;/span&gt; Report evidence and verification gaps.

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

For each finding, provide:
&lt;span class="p"&gt;-&lt;/span&gt; Location
&lt;span class="p"&gt;-&lt;/span&gt; Issue
&lt;span class="p"&gt;-&lt;/span&gt; Evidence
&lt;span class="p"&gt;-&lt;/span&gt; Potential impact
&lt;span class="p"&gt;-&lt;/span&gt; Recommended action

Also report:
&lt;span class="p"&gt;-&lt;/span&gt; Areas checked
&lt;span class="p"&gt;-&lt;/span&gt; Tests executed and their results
&lt;span class="p"&gt;-&lt;/span&gt; Checks not performed
&lt;span class="p"&gt;-&lt;/span&gt; Unresolved assumptions

&lt;span class="gu"&gt;## Boundaries&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Do not change source files.
&lt;span class="p"&gt;-&lt;/span&gt; Do not approve or merge changes.
&lt;span class="p"&gt;-&lt;/span&gt; Do not claim a finding without evidence.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Skill describes a review process rather than encoding the tenant isolation policy itself. The permanent requirement to isolate tenants belongs in the API rules. The Skill defines how to inspect a change against that requirement and report the evidence.&lt;/p&gt;

&lt;p&gt;The description deserves particular attention because Claude uses it to decide whether the Skill is relevant. A description such as "Helps with code quality" says very little about when to activate it. "Review API changes before merge" establishes a clearer task boundary.&lt;/p&gt;

&lt;p&gt;You can keep additional reference documents or scripts beside &lt;code&gt;SKILL.md&lt;/code&gt; when the workflow grows. &lt;code&gt;${CLAUDE_SKILL_DIR}&lt;/code&gt; identifies the Skill directory for referencing those resources. Claude Code recommends keeping the main &lt;code&gt;SKILL.md&lt;/code&gt; under 500 lines and moving larger reference material into separate files.&lt;/p&gt;

&lt;p&gt;Skills also support &lt;code&gt;disable-model-invocation: true&lt;/code&gt; when only the user should invoke them. That is useful for workflows with side effects, such as deployment. The API review example doesn't need that setting, but it still needs appropriate permissions if the workflow uses tools.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7x5km73cyxh1ixiiu9ch.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7x5km73cyxh1ixiiu9ch.png" alt="Before and after splitting CLAUDE.md" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is an important boundary here: neither &lt;code&gt;CLAUDE.md&lt;/code&gt; nor a Skill is an enforcement mechanism. They provide instructions, not guarantees. If a team must prevent an action, Claude Code provides hooks and &lt;code&gt;permissions.deny&lt;/code&gt; for enforcement. The article on permissions and MCP tool control in this series covers that distinction in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep temporary instructions close to the task
&lt;/h2&gt;

&lt;p&gt;A temporary requirement shouldn't become permanent project policy merely because the agent needs to follow it carefully. Consider a task to add transaction export for administrators. It may require a date filter, pagination, CSV output, and a specific response contract.&lt;/p&gt;

&lt;p&gt;Those requirements belong in the task brief, not in the root instructions. They describe one deliverable rather than how the repository should operate for every feature.&lt;/p&gt;

&lt;p&gt;I use a small &lt;code&gt;task-brief.md&lt;/code&gt; template:&lt;br&gt;
&lt;/p&gt;

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

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

Describe the behavior to implement.

&lt;span class="gu"&gt;## Scope&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Allowed applications and packages:
&lt;span class="p"&gt;-&lt;/span&gt; Files or interfaces to inspect:
&lt;span class="p"&gt;-&lt;/span&gt; Explicit exclusions:

&lt;span class="gu"&gt;## Requirements&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Required behavior:
&lt;span class="p"&gt;-&lt;/span&gt; Input and output contracts:
&lt;span class="p"&gt;-&lt;/span&gt; Authorization requirements:
&lt;span class="p"&gt;-&lt;/span&gt; Edge cases:

&lt;span class="gu"&gt;## Verification&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Tests to add or update:
&lt;span class="p"&gt;-&lt;/span&gt; Commands to run:
&lt;span class="p"&gt;-&lt;/span&gt; Expected observable results:

&lt;span class="gu"&gt;## Delivery&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Summarize implementation.
&lt;span class="p"&gt;-&lt;/span&gt; Report executed checks.
&lt;span class="p"&gt;-&lt;/span&gt; Identify unverified behavior.
&lt;span class="p"&gt;-&lt;/span&gt; Do not expand scope without approval.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can give Claude this brief directly as part of the task. If requirements change, update that task's instructions rather than continually editing &lt;code&gt;CLAUDE.md&lt;/code&gt;. This keeps the shared configuration independent of a particular feature's progress.&lt;/p&gt;

&lt;p&gt;The distinction becomes especially useful across multiple development sessions. Claude Code re-reads the project-root &lt;code&gt;CLAUDE.md&lt;/code&gt; from disk during compaction, while instructions provided only in conversation can be lost. Durable repository conventions therefore need an appropriate file, while temporary work needs a task artifact that can be supplied again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design instructions around observable behavior
&lt;/h2&gt;

&lt;p&gt;A useful instruction changes something you can inspect. "Be careful about security" doesn't establish what the agent should check. "Test cross-tenant requests using data owned by two organizations" describes a concrete verification action.&lt;/p&gt;

&lt;p&gt;Here are examples of replacing broad preferences with testable expectations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vague instruction&lt;/th&gt;
&lt;th&gt;Observable instruction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Write clean code&lt;/td&gt;
&lt;td&gt;Follow existing module boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Be careful with API security&lt;/td&gt;
&lt;td&gt;Check authentication, authorization, and tenant scoping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test thoroughly&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;pnpm -F api test&lt;/code&gt; and report the result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoid breaking changes&lt;/td&gt;
&lt;td&gt;Identify affected API consumers before modifying response contracts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Give a good summary&lt;/td&gt;
&lt;td&gt;List changed files, executed checks, and unverified behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I also avoid instructions that require the agent to claim certainty it cannot establish. Running an API test suite is useful evidence, but it doesn't prove every endpoint is secure. A review report should separate confirmed findings, unverified assumptions, and checks that weren't executed.&lt;/p&gt;

&lt;p&gt;For our fictional API, imagine a new endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /reports/export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful response isn't enough to demonstrate correct authorization. The implementation must resolve the authenticated organization and keep its data isolated from other organizations. Tests should include an authorized request, an unauthorized request, and an attempted cross-tenant access.&lt;/p&gt;

&lt;p&gt;This is where instruction placement and verification meet. The API rule names the invariant, the task brief defines the endpoint's behavior, and the review Skill guides the assessment. Production authorization must still be implemented and enforced by the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the setup using representative tasks
&lt;/h2&gt;

&lt;p&gt;I wouldn't judge an instruction setup by asking Claude to explain the contents of &lt;code&gt;CLAUDE.md&lt;/code&gt;. The useful evidence is what it does when working on a representative change. That includes the files it inspects, the decisions it makes, the code it changes, and the checks it runs.&lt;/p&gt;

&lt;p&gt;For a fair comparison, prepare two documented configurations and use the same repository state and task briefs. Configuration A can use an overloaded root instruction file. Configuration B can use the minimal root file, scoped API rules, and the review Skill.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh8yzkvzpqg3qgbpq5ac.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjh8yzkvzpqg3qgbpq5ac.png" alt="Behavior comparison of two configurations" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Define the evaluation criteria before running either setup:&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;Expected evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Update a UI component&lt;/td&gt;
&lt;td&gt;No API-specific review procedure for a UI-only change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add an API export endpoint&lt;/td&gt;
&lt;td&gt;Tenant-scoped data access and cross-tenant tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change an API response field&lt;/td&gt;
&lt;td&gt;Identification of affected consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review an API diff&lt;/td&gt;
&lt;td&gt;Findings supported by file and code evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complete an API change&lt;/td&gt;
&lt;td&gt;Actual test results and explicit verification gaps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Run the tasks in separate sessions with equivalent starting conditions. Record whether the expected behaviors occurred and whether unrelated changes appeared. Don't treat a polished final explanation as evidence of correct implementation.&lt;/p&gt;

&lt;p&gt;For the tenant isolation case, create test fixtures for organizations A and B. Authenticate as an account belonging to A and attempt to retrieve B's data through the relevant endpoint. The expected result is that the account cannot access B's records, regardless of how request parameters are constructed.&lt;/p&gt;

&lt;p&gt;Claude Code provides &lt;code&gt;/context&lt;/code&gt; to inspect loaded context and &lt;code&gt;/memory&lt;/code&gt; to open memory files. Use &lt;code&gt;/context&lt;/code&gt; while testing the scoped rules to check which instructions are available. You can use &lt;code&gt;/init&lt;/code&gt; to generate an initial &lt;code&gt;CLAUDE.md&lt;/code&gt;, but review its contents against your actual repository before adopting it.&lt;/p&gt;

&lt;p&gt;For the Skill, test both positive and negative activation cases. Ask Claude to review an API diff and check whether it uses the workflow. Then ask it to explain a TypeScript type or modify an unrelated UI component and check that it doesn't invoke API review unnecessarily.&lt;/p&gt;

&lt;p&gt;Separate activation from execution when investigating failures. If Claude doesn't select the review Skill automatically, invoke &lt;code&gt;/api-review&lt;/code&gt; directly and evaluate the resulting procedure. If the procedure still misses required checks, the problem is no longer just Skill selection.&lt;/p&gt;

&lt;p&gt;A comparison only becomes useful when you preserve the task, the expected results, and the actual artifacts. I wouldn't claim that a shorter configuration improves reliability by a particular percentage without controlled evidence. The immediate objective is to discover whether the instructions produce the behavior your project needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintain the configuration like code
&lt;/h2&gt;

&lt;p&gt;Agent instructions deserve the same review discipline as application configuration. When the team moves a package, changes a test command, or modifies an architecture boundary, the corresponding instructions may become incorrect. A perfectly followed outdated rule can still produce the wrong implementation.&lt;/p&gt;

&lt;p&gt;Consider moving tenant-owned data access into a different package. The original &lt;code&gt;apps/api/**/*.ts&lt;/code&gt; glob may no longer cover the code that needs isolation rules. Someone reviewing that architectural change should also review the scoped instruction files and their tests.&lt;/p&gt;

&lt;p&gt;I would assign clear ownership and include these checks in configuration reviews:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the instruction still describe the repository?&lt;/li&gt;
&lt;li&gt;Does it belong at this scope?&lt;/li&gt;
&lt;li&gt;Does another file express a conflicting requirement?&lt;/li&gt;
&lt;li&gt;Can the expected behavior be observed?&lt;/li&gt;
&lt;li&gt;Does a representative test cover the requirement?&lt;/li&gt;
&lt;li&gt;Can the instruction be removed without losing necessary guidance?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would also avoid adding sensitive credentials or tokens to committed instruction files. Shared configuration should describe where approved credentials come from, not contain their values. Review Skills and supporting scripts before sharing them with the team.&lt;/p&gt;

&lt;p&gt;When an instruction repeatedly fails, investigate whether Claude received it, whether it is specific enough, and whether competing instructions exist. Fix the relevant cause rather than adding a second version of the rule. If the requirement demands a hard restriction, move that control into the appropriate enforcement mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  A small starter you can adapt
&lt;/h3&gt;

&lt;p&gt;The complete starter for this example has four essential artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;claude-project-starter/
├── CLAUDE.md
├── skills/
│   └── api-review/
│       └── SKILL.md
├── task-brief.md
└── instruction-placement-checklist.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy &lt;code&gt;CLAUDE.md&lt;/code&gt; to your project root and &lt;code&gt;skills/api-review/&lt;/code&gt; into &lt;code&gt;.claude/skills/&lt;/code&gt;. Keep &lt;code&gt;task-brief.md&lt;/code&gt; as a template for individual tasks. Add &lt;code&gt;.claude/rules/&lt;/code&gt; with scoped files when your repository needs area-specific policies.&lt;/p&gt;

&lt;p&gt;The final checklist is the decision process I use when deciding where to place a new instruction:&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;# Instruction Placement Checklist&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Is this a durable repository-wide rule?
   -&amp;gt; Project CLAUDE.md
&lt;span class="p"&gt;
2.&lt;/span&gt; Does it apply only to specific code paths?
   -&amp;gt; .claude/rules/ with paths
&lt;span class="p"&gt;
3.&lt;/span&gt; Is it a repeatable, multi-step procedure?
   -&amp;gt; .claude/skills/&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;/SKILL.md
&lt;span class="p"&gt;
4.&lt;/span&gt; Is it specific to one deliverable?
   -&amp;gt; Task brief
&lt;span class="p"&gt;
5.&lt;/span&gt; Is it lengthy reference material?
   -&amp;gt; Documentation, read when needed
&lt;span class="p"&gt;
6.&lt;/span&gt; Is it a personal working preference?
   -&amp;gt; Personal CLAUDE.md or CLAUDE.local.md
&lt;span class="p"&gt;
7.&lt;/span&gt; Must the action be technically blocked?
   -&amp;gt; Hooks or permissions.deny

Before adding the instruction:
&lt;span class="p"&gt;-&lt;/span&gt; Check for an existing equivalent rule.
&lt;span class="p"&gt;-&lt;/span&gt; Remove conflicting or obsolete wording.
&lt;span class="p"&gt;-&lt;/span&gt; Define an observable verification criterion.
&lt;span class="p"&gt;-&lt;/span&gt; Identify who maintains it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to create the smallest possible collection of instruction files. It's to give every instruction a clear responsibility, scope, and way to verify its effect. A useful &lt;code&gt;CLAUDE.md&lt;/code&gt; remains understandable because it contains project knowledge, not every procedure and reminder the team has ever written.&lt;/p&gt;

&lt;p&gt;The next article, on context and memory in this series, examines another part of the same problem: what the agent needs to retain, what it can retrieve, and what should remain in the repository. For now, take one instruction from your existing &lt;code&gt;CLAUDE.md&lt;/code&gt; and apply the checklist. Decide whether it describes the project, a procedure, or a temporary task, then test the behavior it is supposed to produce.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's one instruction you added to CLAUDE.md that probably doesn't belong there anymore?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>ai</category>
      <category>claudecode</category>
      <category>programming</category>
    </item>
    <item>
      <title>Can You Trust Code You Didn't Write?</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Sat, 24 Oct 2026 23:34:34 +0000</pubDate>
      <link>https://dev.to/thetonynotes/can-you-trust-code-you-didnt-write-2e97</link>
      <guid>https://dev.to/thetonynotes/can-you-trust-code-you-didnt-write-2e97</guid>
      <description>&lt;p&gt;I'm Tony. I build and run web products, and Claude Code is my main development tool. A coding agent finishes implementing a feature, reports that everything is complete, and presents a summary of the changes. The code looks reasonable, the tests appear green, and you have another task waiting. But what exactly did the agent prove?&lt;/p&gt;

&lt;p&gt;Generating working code and verifying correct behavior are different engineering activities. I use a verification workflow that starts with observable acceptance criteria, checks the implementation at several levels, and records evidence before accepting a change. I'll walk through it using a TypeScript application with an admin interface and a multi-tenant API, including an authorization bug that ordinary tests can miss. You'll leave with a reusable verification checklist and a completed example showing what an acceptable evidence trail looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  A completed task is not a verified change
&lt;/h2&gt;

&lt;p&gt;A coding agent can produce a convincing implementation without establishing that it solves the original problem. It might modify the right files, follow the existing patterns, and run the available tests successfully. None of those results automatically establishes that the requested behavior works. They answer narrower questions.&lt;/p&gt;

&lt;p&gt;Consider four statements an agent might make:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Statement&lt;/th&gt;
&lt;th&gt;What it actually establishes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Implementation complete"&lt;/td&gt;
&lt;td&gt;The agent produced code it considers finished.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"TypeScript compilation passed"&lt;/td&gt;
&lt;td&gt;The compiler found no errors covered by that check.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"All tests passed"&lt;/td&gt;
&lt;td&gt;The executed tests passed under their configured conditions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"The requested behavior works"&lt;/td&gt;
&lt;td&gt;Requires evidence that the implementation satisfies the acceptance criteria.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The difference matters because tests only exercise the scenarios someone anticipated. A passing authorization test might establish that a resource owner can access a document, while saying nothing about another authorized member or an unrelated tenant. A successful browser interaction might show text appearing in an editor without proving that the correct value was saved. Even a valid download can contain files with incorrect permissions.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ku7d72mkd620a4h0okx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ku7d72mkd620a4h0okx.png" alt="The verification gap" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think of this as a verification gap. The agent's final message belongs on one side; evidence that supports the product requirements belongs on the other. My responsibility is to close that gap, not merely decide whether the generated code looks plausible.&lt;/p&gt;

&lt;p&gt;The same distinction applies to human-written code, but agents change the amount of implementation a developer can produce without personally tracing every decision. That makes a disciplined acceptance process more important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with an observable acceptance contract
&lt;/h2&gt;

&lt;p&gt;Before implementation, I want a short contract describing what the system must do and how we will know it works. This is not a complete specification or an elaborate test plan. It is a set of observable behaviors that can be checked independently of the agent's explanation.&lt;/p&gt;

&lt;p&gt;Imagine a pnpm TypeScript monorepo with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/
  admin/              # React admin application
  api/                # Multi-tenant API
packages/
  ui/                 # Shared UI components
  shared/             # Shared contracts and utilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose the API serves multiple customer organizations. A resource can be associated with several groups, and users receive access through group membership. The requested change is to correct a permission check that incorrectly rejects some authorized users.&lt;/p&gt;

&lt;p&gt;Here is the acceptance contract I would give the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Task:
Correct group-based access to shared resources.

Expected behavior:
&lt;span class="p"&gt;1.&lt;/span&gt; A member of any group attached to a resource
   can access that resource within the same tenant.
&lt;span class="p"&gt;2.&lt;/span&gt; A user outside all attached groups is denied.
&lt;span class="p"&gt;3.&lt;/span&gt; A user from another tenant is denied, even when
   group identifiers overlap.
&lt;span class="p"&gt;4.&lt;/span&gt; Existing resource-owner access remains unchanged.

Evidence required:
&lt;span class="p"&gt;-&lt;/span&gt; Focused authorization tests for all four cases.
&lt;span class="p"&gt;-&lt;/span&gt; A regression test where the authorized user
  belongs to the second attached group.
&lt;span class="p"&gt;-&lt;/span&gt; Confirmation that the regression test fails
  without the fix and passes with it.
&lt;span class="p"&gt;-&lt;/span&gt; A summary of changed files and remaining risks.

Constraints:
&lt;span class="p"&gt;-&lt;/span&gt; Preserve tenant isolation.
&lt;span class="p"&gt;-&lt;/span&gt; Do not change unrelated authorization behavior.
&lt;span class="p"&gt;-&lt;/span&gt; Do not modify tests merely to make them pass.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This contract specifies results rather than implementation details. I have not instructed the agent to use a particular SQL query, ORM method, or function structure. It can choose an approach that fits the existing code, but it cannot redefine successful completion as "the code compiles."&lt;/p&gt;

&lt;p&gt;The edge cases carry much of the value. Testing an owner and an unauthorized stranger is insufficient when access depends on several relationships. The important case is a user who belongs to a valid group that the previous implementation failed to consider.&lt;/p&gt;

&lt;p&gt;For a bug fix, I also provide the reproduction command, relevant stack trace when one exists, and steps needed to reproduce the behavior. I state whether the failure is intermittent. These details reduce guesswork and give the agent a concrete starting point.&lt;/p&gt;

&lt;p&gt;The principle is simple: define success before evaluating the implementation. Otherwise, the agent's solution can influence what everyone considers an acceptable test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask the agent to implement, not declare victory
&lt;/h2&gt;

&lt;p&gt;I separate implementation instructions from acceptance decisions. The agent can inspect the repository, propose a solution, edit code, and execute tests. It can also identify missing cases and explain technical tradeoffs. But I do not treat its final assessment as independent evidence.&lt;/p&gt;

&lt;p&gt;For changes with unclear scope, I start Claude Code in plan mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--permission-mode&lt;/span&gt; plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plan mode lets Claude read the project and propose an approach without editing files until approval. I use that boundary to examine assumptions, identify impacted modules, and check whether the proposed tests cover the acceptance contract. The plan is useful because it exposes decisions before implementation makes those decisions harder to notice.&lt;/p&gt;

&lt;p&gt;For the authorization example, I might use this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inspect the shared-resource authorization flow.

Identify:
- How resources are associated with groups.
- Where tenant isolation is enforced.
- Which tests cover users with multiple group paths.
- Why membership in the second attached group fails.

Propose the smallest safe change and the tests
needed to verify it. Do not edit files yet.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After reviewing the proposal, I authorize implementation and ask for a report containing the actual commands and outcomes. I also ask the agent to identify missed edge cases. This makes the agent useful as an implementation partner without making it the final authority on correctness.&lt;/p&gt;

&lt;p&gt;An instruction in CLAUDE.md can require the agent to include test evidence in its response. That is a useful working convention, not an enforcement mechanism. The presence of a well-formatted report does not prove that the underlying evidence is valid.&lt;/p&gt;

&lt;p&gt;If the change moves in the wrong direction, Claude Code's &lt;code&gt;/rewind&lt;/code&gt; can restore the conversation and code to a checkpoint. That helps manage the implementation process, but it does not replace version control or acceptance testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify at different levels
&lt;/h2&gt;

&lt;p&gt;Verification works better when each check has a specific responsibility. Compilation, automated tests, browser interactions, and human review observe different properties of the system. Running more checks is not automatically better; choosing checks that cover different failure modes is what matters.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcly680l6j9bmvdama7w3.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcly680l6j9bmvdama7w3.png" alt="Verification layers" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Static checks: Is the change structurally valid?
&lt;/h3&gt;

&lt;p&gt;I start with the checks already defined by the repository. For a TypeScript project, these typically include type checking, linting, and build validation. They reveal broken imports, incompatible types, invalid code patterns, and some integration mistakes.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nt"&gt;-F&lt;/span&gt; api &lt;span class="nb"&gt;exec &lt;/span&gt;tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command only makes sense when the workspace and TypeScript configuration support it. A successful result tells me that the relevant TypeScript checks passed. It does not establish that group membership is evaluated correctly or that the API returns the expected authorization decisions.&lt;/p&gt;

&lt;p&gt;I record which command ran, its exit status, and whether the check covers the changed code. "Static checks passed" is less informative than the exact command and result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Focused tests: Does the behavior match the contract?
&lt;/h3&gt;

&lt;p&gt;Consider this incorrect permission check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findFirst&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resourceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;isGroupMember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation checks membership against the first group returned by the database. If a resource belongs to groups A and B, a user belonging only to B can be denied access. The code compiles, and a test using a member of A might pass.&lt;/p&gt;

&lt;p&gt;The correction should ask whether there is at least one qualifying membership, not whether the user belongs to one arbitrarily selected group. One possible approach is a relational query that keeps the tenant condition within the authorization predicate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resourceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;memberships&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;some&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact query depends on the application's data model and ORM schema. Its essential property is that it evaluates all eligible relationships while preserving tenant boundaries. The surrounding authorization flow must still validate the user's tenant context and any additional access rules.&lt;/p&gt;

&lt;p&gt;The regression test is more valuable than a generic "authorized user succeeds" test:&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allows a member of the second attached group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tenantA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;groupIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;groupA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;groupB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tenantA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;groupIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;groupB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;requestResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;resourceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;asUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;Here, &lt;code&gt;createResource&lt;/code&gt;, &lt;code&gt;createUser&lt;/code&gt;, and &lt;code&gt;requestResource&lt;/code&gt; represent application-specific test helpers. A real implementation should use the repository's existing fixtures and request utilities, with deterministic setup that makes the relevant group ordering explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regression proof: Does the test detect the original bug?
&lt;/h3&gt;

&lt;p&gt;A passing test is useful. A test that fails against the broken implementation and passes against the correction provides stronger evidence that it detects the intended defect.&lt;/p&gt;

&lt;p&gt;One way to perform this check in a controlled working tree is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash push src/auth/permissions.ts
npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; permissions
git stash pop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sequence assumes the working-tree state, stash contents, and test command have been inspected first. The stash must actually restore the known broken implementation for the test to mean anything. It can also stash other uncommitted edits in the named file, so I would use a clean, isolated working tree rather than run it casually against active work.&lt;/p&gt;

&lt;p&gt;Notice another operational detail: combining the test and restore operations with &lt;code&gt;;&lt;/code&gt; allows the restore attempt to run even if the test fails. With three separate commands, I must explicitly execute the restoration after the expected failure and inspect the resulting working-tree state.&lt;/p&gt;

&lt;p&gt;The evidence I want is specific: the regression test fails for the expected authorization reason without the fix, then passes with the correction restored. A failure caused by missing fixtures, invalid imports, or environment setup is not proof that the regression test detects the original bug.&lt;/p&gt;

&lt;p&gt;The repository might use pnpm instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nt"&gt;-F&lt;/span&gt; api &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use the command that matches the actual project rather than changing package managers simply to match an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Browser checks: Does the user see the correct result?
&lt;/h3&gt;

&lt;p&gt;API tests do not establish that the browser handles state correctly. A common case is automation entering text into a rich-text editor built with DraftJS-style or React-managed state. The text becomes visible, but the application saves a default value because the submitted content lives in parent component state.&lt;/p&gt;

&lt;p&gt;A screenshot of the editor would look correct while the saved record would be wrong. The appropriate fix is to update the value through the component's supported &lt;code&gt;onChange&lt;/code&gt; mechanism, then save and read back the persisted content. The verification target is the reopened or fetched record, not merely the visible text before submission.&lt;/p&gt;

&lt;p&gt;For the authorization example, a browser check can establish that an authorized member can open the shared resource and an unauthorized member receives the intended denial. That user-facing result complements the API tests without replacing them.&lt;/p&gt;

&lt;p&gt;I cover browser automation patterns in more detail in the article on browser testing with Playwright in this series.&lt;/p&gt;

&lt;h3&gt;
  
  
  Human review: Does the behavior make sense?
&lt;/h3&gt;

&lt;p&gt;Automated checks can establish consistency with written expectations. They cannot decide whether those expectations fully reflect the product's intended policy. A developer still needs to evaluate whether the change introduces unintended access, violates an architectural boundary, or relies on an assumption the tests never challenge.&lt;/p&gt;

&lt;p&gt;For authorization code, I examine query scoping, user identity, tenant ownership, and any caching that might retain stale permissions. I also look for inconsistent behavior between endpoints using the same permission model. Those concerns are part of engineering review, not defects a green test suite automatically rules out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the diff against the original intent
&lt;/h2&gt;

&lt;p&gt;After executing the checks, I return to the original acceptance contract and inspect the actual diff. The question is not simply whether I understand the implementation. I want to know whether every change serves the requested behavior.&lt;/p&gt;

&lt;p&gt;For the authorization fix, the intended scope is narrow: correct membership evaluation and add meaningful coverage. A change that also modifies authentication middleware, restructures tenant resolution, or removes failing assertions deserves separate justification. Scope expansion increases the number of assumptions I need to verify.&lt;/p&gt;

&lt;p&gt;My diff review focuses on five questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Which behavior changed?&lt;/strong&gt; Identify the precise condition that produces a different result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which files changed, and why?&lt;/strong&gt; Look for unrelated formatting, generated files, or dependency updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which assumptions did the implementation introduce?&lt;/strong&gt; Check group ordering, nullable relationships, tenant context, and error handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which failure paths remain untested?&lt;/strong&gt; Consider cross-tenant requests, absent memberships, deleted groups, and resource ownership.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Did the tests become weaker?&lt;/strong&gt; Look for removed assertions, permissive mocks, skipped cases, or fixtures changed to avoid failures.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another useful example is generating a downloadable ZIP package. The download can succeed, contain the correct files, use the expected version, and pass a secrets check. Yet its setup script might lose the executable bit because the ZIP library does not preserve Unix file modes.&lt;/p&gt;

&lt;p&gt;After extraction, this result is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rw-r--r-- scripts/setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the script directly produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./scripts/setup.sh: Permission denied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a package where scripts are expected to run directly on Unix, a packaging rule can assign mode &lt;code&gt;0755&lt;/code&gt; to files beginning with &lt;code&gt;#!&lt;/code&gt; and &lt;code&gt;0644&lt;/code&gt; to ordinary files. Verification should then inspect the extracted archive, not just the source directory.&lt;/p&gt;

&lt;p&gt;The expected extracted permission is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rwxr-xr-x scripts/setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrates why a passing pipeline can still miss an important delivery requirement. The implementation artifact must be checked in the form and environment where someone actually uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give every result an evidence trail
&lt;/h2&gt;

&lt;p&gt;I prefer a compact verification report over a long transcript of everything the agent attempted. The report should let another developer understand the requested behavior, identify the executed checks, reproduce important results, and see what remains uncertain. It should also distinguish the agent's statements from recorded observations.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ku3rfh79zgqv5oqmf23.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ku3rfh79zgqv5oqmf23.png" alt="Claims backed by evidence" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following is a completed example for our fictional authorization fix. The paths and outcomes illustrate what a report should contain; they are not claims that these commands were executed against a real repository.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;agent-change-verification.md&lt;/code&gt;&lt;/strong&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="gh"&gt;# Agent Change Verification&lt;/span&gt;

&lt;span class="gu"&gt;## Task&lt;/span&gt;
Correct group-based access to shared resources.

&lt;span class="gu"&gt;## Acceptance criteria&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [x] Member of any attached group is allowed.
&lt;span class="p"&gt;-&lt;/span&gt; [x] Nonmember is denied.
&lt;span class="p"&gt;-&lt;/span&gt; [x] User from another tenant is denied.
&lt;span class="p"&gt;-&lt;/span&gt; [x] Existing owner access remains unchanged.

&lt;span class="gu"&gt;## Files changed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; src/auth/permissions.ts
  Replaced first-group lookup with membership query.
&lt;span class="p"&gt;-&lt;/span&gt; src/auth/permissions.test.ts
  Added second-group and tenant-isolation cases.

&lt;span class="gu"&gt;## Checks executed&lt;/span&gt;

| Check | Result | Evidence |
|---|---|---|
| TypeScript check | PASS | typecheck.log |
| API permission tests | PASS | permissions-test.log |
| Regression without fix | EXPECTED FAIL | regression-red.log |
| Regression with fix | PASS | regression-green.log |
| Focused diff review | PASS | review-notes.md |

&lt;span class="gu"&gt;## Expected vs observed&lt;/span&gt;
Expected:
A user in group B can access a resource shared
with groups A and B within the same tenant.

Observed:
The API returns 200 for the group B member.
The regression test fails with the original
first-group logic and passes with the fix.

&lt;span class="gu"&gt;## Unverified scenarios&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Concurrent group membership changes.
&lt;span class="p"&gt;-&lt;/span&gt; Cache invalidation after permission updates.
&lt;span class="p"&gt;-&lt;/span&gt; Browser-level permission error presentation.

&lt;span class="gu"&gt;## Known limitations&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Tests use a local test database.
&lt;span class="p"&gt;-&lt;/span&gt; Production data distribution was not reproduced.
&lt;span class="p"&gt;-&lt;/span&gt; No performance evaluation of the new query.

&lt;span class="gu"&gt;## Human review decision&lt;/span&gt;
APPROVED FOR REVIEW, NOT DEPLOYMENT.

Reason:
Acceptance tests pass and regression behavior
is demonstrated. Query execution characteristics
and cache behavior require separate review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The report does not need to claim absolute confidence. Its value comes from making the evidence inspectable and showing where the evidence stops. In a real repository, the referenced logs and review notes should exist, correspond to the tested revision, and be accessible to the reviewer.&lt;/p&gt;

&lt;p&gt;I find it useful to rank evidence by what it establishes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The agent says the task is complete.&lt;/li&gt;
&lt;li&gt;A command executes without error.&lt;/li&gt;
&lt;li&gt;Relevant tests pass.&lt;/li&gt;
&lt;li&gt;A regression test fails without the fix and passes with it.&lt;/li&gt;
&lt;li&gt;The resulting behavior is read back from the system where the user actually encounters it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is an ordering of evidence strength, not a replacement for evaluating test quality or requirement coverage. A read-back confirms a particular observed result; it does not establish that every untested condition is safe.&lt;/p&gt;

&lt;p&gt;For write operations, I like tools that return both &lt;code&gt;verified&lt;/code&gt; and &lt;code&gt;evidence&lt;/code&gt;. The first indicates whether post-action verification succeeded. The second explains what the system returned when the tool read the result back.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deleteResource"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/resources/example-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the write tool deleted a resource and then performed a separate read. A successful delete request alone would not provide equivalent evidence. The observed 404 supports the claim that the resource is no longer retrievable at that endpoint, assuming the read uses the appropriate identity and tenant context.&lt;/p&gt;

&lt;p&gt;For pull requests, I can use &lt;code&gt;gh pr create&lt;/code&gt; to connect a Claude Code session with a PR and reopen that session using &lt;code&gt;claude --from-pr &amp;lt;number&amp;gt;&lt;/code&gt;. The PR then becomes a practical place to review the diff, attach test evidence, and ask Claude to flag risks. The review decision still belongs to the people responsible for accepting the change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know when the workflow is insufficient
&lt;/h2&gt;

&lt;p&gt;A verification checklist helps make acceptance consistent, but it cannot compensate for missing requirements or an environment that fails to represent production behavior. Authorization, billing, data migration, destructive operations, and sensitive-data handling deserve closer attention because incorrect behavior can have consequences beyond a single feature.&lt;/p&gt;

&lt;p&gt;Weak test coverage also changes how much confidence I assign to a passing suite. If the application has no realistic integration environment, no tenant-isolation fixtures, or no way to inspect persisted changes, the verification report should say so. The correct response is to identify the missing evidence, not lower the acceptance criteria until everything appears green.&lt;/p&gt;

&lt;p&gt;I also separate new failures from existing failures. If an unrelated test was already failing, I do not edit it, skip it, or change its expectations just to produce a green result. I document the failure in the PR, explain why it appears unrelated, and leave the decision visible to reviewers.&lt;/p&gt;

&lt;p&gt;Some decisions remain fundamentally human. Whether two groups should share access to a sensitive resource is a product and security policy question before it is a query implementation question. An agent can implement the stated rule and test that implementation, but the team must decide whether the rule is correct.&lt;/p&gt;

&lt;p&gt;The workflow I use is therefore not "make the agent pass every check." It is to define observable expectations, collect independent evidence, review the change against its intent, and explicitly record what has not been established. That process makes code written by an agent easier to understand, verify, and maintain.&lt;/p&gt;

&lt;p&gt;This is the foundation of &lt;em&gt;Making Coding Agents Reliable&lt;/em&gt;, a six-article series about practical workflows for working with AI coding agents. The next article covers CLAUDE.md and Skills, including how to make project instructions useful without confusing instructions with enforcement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the one check you never skip before accepting an AI-generated change?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>claudecode</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
