<?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: Mykola Mizhigurskiy</title>
    <description>The latest articles on DEV Community by Mykola Mizhigurskiy (@kotyk).</description>
    <link>https://dev.to/kotyk</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%2F3186292%2Ff76ff383-d13c-42f5-9b1c-f438e95b8036.jpg</url>
      <title>DEV Community: Mykola Mizhigurskiy</title>
      <link>https://dev.to/kotyk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kotyk"/>
    <language>en</language>
    <item>
      <title>Codex at No Extra Cost: How I Turned ChatGPT into a Free AI Coding Agent</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Fri, 16 Oct 2026 12:59:35 +0000</pubDate>
      <link>https://dev.to/kotyk/codex-at-no-extra-cost-how-i-turned-chatgpt-into-a-free-ai-coding-agent-1fo0</link>
      <guid>https://dev.to/kotyk/codex-at-no-extra-cost-how-i-turned-chatgpt-into-a-free-ai-coding-agent-1fo0</guid>
      <description>&lt;p&gt;Recently, while working on a personal project, I stumbled upon an interesting feature in ChatGPT. Apparently, you can connect it to GitHub and give it access to your repositories. Nothing particularly groundbreaking at first glance, just another integration in a world already overflowing with AI tools. But it got me wondering how far I could push it. What if I used ChatGPT not just to analyze code, but as a proper coding agent capable of working directly with my repository?&lt;/p&gt;

&lt;p&gt;By that point, I'd already been using Codex quite extensively, so I was familiar with both its capabilities and its biggest annoyance: usage limits. There's nothing quite like getting into the flow, breaking a large task into manageable pieces, and then hitting your five-hour quota just as things start getting interesting. That got me thinking: why spend my Codex allowance generating code if I could delegate some of that work to regular ChatGPT? Especially since I wasn't paying for Plus specifically for coding. I subscribed for everyday conversations, research, and all sorts of other things.&lt;/p&gt;

&lt;p&gt;Of course, calling this approach completely free would be stretching the truth. ChatGPT Plus costs money, has its own limits, and computing power doesn't magically appear out of thin air. But if you're already paying for the subscription and your regular usage stays comfortably within its limits, having an additional way to generate code feels like a pretty nice bonus. At least in my case, I hadn't managed to hit ChatGPT's limits, even while using it for some fairly substantial development tasks.&lt;/p&gt;

&lt;p&gt;The remaining question was whether this approach could do more than just dump code into a repository. Could it actually produce something useful without leaving me with hours of debugging afterward? There was only one way to find out. But first, I needed to set everything up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up ChatGPT with GitHub
&lt;/h2&gt;

&lt;p&gt;To get started, you'll need a ChatGPT account with access to the GitHub integration and, naturally, a repository to work with. Open the Plugins section in ChatGPT's settings, find GitHub, and start the connection process. You'll be redirected to GitHub, where you authorize the application and choose which repositories it can access. The setup is straightforward and doesn't require manually creating or configuring API tokens.&lt;/p&gt;

&lt;p&gt;At this point, I'd strongly recommend taking a moment before clicking through the authorization screens. GitHub lets you choose between granting access to all repositories and the &lt;strong&gt;Only select repositories&lt;/strong&gt; option, where you explicitly specify which repositories the application can access. I went with the latter, granting access only to the project I intended to work on. It's a straightforward application of the Principle of Least Privilege, something that's surprisingly easy to overlook when you're eager to try out a new tool.&lt;/p&gt;

&lt;p&gt;It's equally important to review the permissions the application requests, especially if they include the ability to write to or modify repository contents. If an agent can change code, I wouldn't let it work directly on the main branch under any circumstances. It's much safer to create a separate branch for each independent task and review the results through a Pull Request. Besides making code reviews easier, this approach preserves the history of changes, lets you measure how much code the agent actually generated, and gives you a clean way to reject an implementation if things go sideways.&lt;/p&gt;

&lt;p&gt;Once authorization is complete, make sure ChatGPT can access your repository and read its structure. There's one important detail, though: being able to read code doesn't necessarily mean your particular integration supports modifying it. Before getting started, check whether the agent can create branches, commits, and Pull Requests. In my case, all of these capabilities were available, so it was time for the interesting part: giving the agent a real task and seeing what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It to the Test: 20,000 Lines of Code in Half a Day
&lt;/h2&gt;

&lt;p&gt;Back to my project. I'm working with a fairly large monorepo, where functionality is organized into separate packages with clearly defined responsibilities. While going about my usual development work, I picked out a few tasks I could delegate to ChatGPT without interfering with what I was doing locally. I wasn't particularly interested in starting with something trivial, like fixing lint errors or renaming variables. If I was going to test what this agent could do, I wanted to give it a proper architectural challenge: understand the existing codebase, work out an approach, and implement new functionality.&lt;/p&gt;

&lt;p&gt;ChatGPT lets you choose the model's reasoning effort, so I decided to go straight for the strongest option available to me: High. I deliberately chose a setting intended for complex tasks rather than trying to save resources by using a less demanding mode. I don't know exactly how many tokens the agent burned through while reasoning, since I wasn't tracking that separately. But the amount of work it produced was substantial: &lt;strong&gt;in half a day, ChatGPT generated roughly 20,000 lines of code through GitHub&lt;/strong&gt;, implementing new functionality in my monorepo.&lt;/p&gt;

&lt;p&gt;But that wasn't even the most interesting part. Throughout the process, I kept an eye on my five-hour Codex quota, curious to see how much of it this kind of code generation would consume. And the number didn't budge. At least in my setup, regular ChatGPT with the GitHub integration could handle fairly substantial tasks on High reasoning without touching my Codex allowance. Of course, generating 20,000 lines of code doesn't automatically mean you've produced 20,000 lines of verified, production-ready software, but as a first test of the approach, the results were promising.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slower, but You Can Go for a Walk
&lt;/h3&gt;

&lt;p&gt;One thing became clear pretty quickly: generating code through ChatGPT was noticeably slower than using my usual local coding agent. ChatGPT also didn't have direct access to my computer, local runtime, or development tools, so its ability to validate the generated code was different from what Codex could do inside my IDE. That's a disadvantage, of course, since the code would still need to pass static analysis, build checks, and actual tests. On the other hand, if the agent doesn't need my computer to do its job, I don't necessarily need to be sitting in front of it either.&lt;/p&gt;

&lt;p&gt;And that turned out to be one of my favorite parts of the whole experience. I actually launched some of those first tasks while taking my kid for a walk, with nothing but my phone and a mobile internet connection. Because I'd planned the tasks ahead of time and made them substantial enough, I didn't have to babysit the agent or intervene every few minutes. Checking my phone once every 10–15 minutes was usually enough to see how things were going and provide another instruction if needed. The rest of the time, I could focus on spending time with my kid while new commits quietly appeared in a GitHub repository somewhere in the cloud.&lt;/p&gt;

&lt;p&gt;In a way, I'd found a way to turn time I wouldn't normally spend programming into actual development output. And it wasn't really about squeezing more working hours into my day, but about organizing the work differently. When a task is well-defined, being a developer doesn't necessarily mean sitting in front of an IDE and watching every step of the implementation. You can get on with your life and check in with the agent only when it actually needs your attention.&lt;/p&gt;

&lt;p&gt;Another feature I particularly appreciated was ChatGPT's notifications when a conversation finished its work. As someone who constantly feels the urge to check whether a process is still running or if something has gone wrong, I found them surprisingly useful. They're especially handy when you have several conversations running at once, since you can rely on notifications instead of constantly switching between chats. That said, the notifications didn't always accurately reflect the actual state of the task, so I wouldn't recommend trusting them blindly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Agents, Multiple Branches, Almost No Conflicts
&lt;/h3&gt;

&lt;p&gt;Another interesting discovery was that independent tasks could run in parallel. If your repository is well-structured and packages have clearly defined responsibilities, there's little reason to make a single agent handle everything sequentially. I opened separate ChatGPT conversations, gave each agent its own task, and instructed it to work in a dedicated Git branch. As a result, several agents were modifying different parts of the same project simultaneously without getting in each other's way.&lt;/p&gt;

&lt;p&gt;Of course, this approach requires a bit of discipline. I never allowed agents to modify the main branch directly, keeping their changes separate for later review and integration. The monorepo architecture helped a lot here: when packages have clear boundaries, it's much easier to distribute work without having two agents editing the same files. That doesn't eliminate the possibility of conflicts, but it certainly reduces the chances.&lt;/p&gt;

&lt;p&gt;To give you an idea of how well this worked, merging the changes from those separate branches turned out to be surprisingly painless. I did run into a few conflicts, but resolving all of them took roughly two minutes. For me, that was a nice confirmation that parallel AI development is perfectly practical when tasks are properly decomposed. It also makes the slower generation speed of individual ChatGPT agents much less of a concern, since you can compensate for some of that delay by running multiple tasks at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations and Unexpected Surprises
&lt;/h3&gt;

&lt;p&gt;It would be suspicious if everything had worked perfectly, especially considering I was figuring things out through trial and error. ChatGPT has its own usage limits, and being able to launch several complex tasks simultaneously doesn't mean you have unlimited computing power. I didn't investigate the exact concurrency limits or track how many tokens each task consumed. What I can say is that &lt;strong&gt;three parallel conversations handling complex tasks on High reasoning worked reasonably well&lt;/strong&gt; in my experience, and I didn't hit any usage limits during this initial experiment.&lt;/p&gt;

&lt;p&gt;The actual problems came from somewhere else: occasionally, a task would stop unexpectedly. Some of these interruptions were probably related to unstable mobile internet, since I was using ChatGPT over 4G, including during air raid alerts here in Ukraine. Usually, once the connection recovered, I could continue without much trouble. But on several occasions, ChatGPT returned an error saying it couldn't verify the integrity of a response, and the agent effectively stopped working.&lt;/p&gt;

&lt;p&gt;I can't say for sure what caused those errors. Perhaps a data stream was interrupted somewhere, or the system couldn't properly process the result of a tool call. Whatever the reason, the outcome was the same: the agent stopped, leaving some of its work already committed to the repository. That's when I discovered another quirk worth knowing about.&lt;/p&gt;

&lt;p&gt;Simple commands like &lt;code&gt;continue&lt;/code&gt;, &lt;code&gt;go&lt;/code&gt;, or &lt;code&gt;next&lt;/code&gt; didn't always help in these situations. The agent sometimes seemed to lose track of the interrupted operation or couldn't figure out exactly where to pick things up. What worked much better was giving it explicit instructions: you've already been working on this task, there are commits in your branch, so inspect the current state of the repository, figure out what's been implemented, and resume from where you left off. That usually got things moving again without having to restart the entire task.&lt;/p&gt;

&lt;p&gt;After running into this a few times, I came away with a simple lesson: when working with a remote coding agent, Git history isn't just a way to store code. It's also a recovery mechanism. If a task is broken down into manageable stages and the agent regularly commits its progress, even a failed conversation doesn't necessarily mean losing the work that's already been done. This becomes especially important for long-running tasks, where starting over could be expensive in both time and resources.&lt;/p&gt;

&lt;p&gt;Overall, my first experience turned out to be far more interesting than I'd expected. I generated roughly 20,000 lines of code, delegated several architectural tasks simultaneously, and barely touched my Codex quota in the process. But one question remained: how good was the generated code, and how much additional work would it take to make sure everything actually worked? That question led me to the next stage: a much more controlled experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  From First Impressions to a Controlled Experiment
&lt;/h2&gt;

&lt;p&gt;The initial results were promising enough to make me want to take the idea further. Generating 20,000 lines of code without spending any Codex quota was certainly satisfying, but the number of lines alone says very little about the quality of the result. I was also curious how expensive it would be to bring that code to a working state if I delegated generation entirely to ChatGPT and used local Codex only for validation and bug fixing. So instead of running another AI coding demo, I decided to set up a controlled experiment on a real project.&lt;/p&gt;

&lt;p&gt;The idea was simple: take the exact same task, give two agents as close to identical starting conditions as possible, and compare the total cost of getting a finished, working result. One agent would run locally through Codex in my IDE, while the other would work through ChatGPT's GitHub integration, without access to my computer. Both would use High reasoning, identical instructions, and the same test specifications. Once generation was complete, I'd subject both implementations to independent code reviews and then use the same local development environment to fix the identified problems and validate the results. This would allow me to compare not just how much code each agent produced, but also the effort required to bring its implementation into a working state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Tests?
&lt;/h3&gt;

&lt;p&gt;For the experiment, I chose automated tests for my backend API. My server has quite a few route handlers covering different business rules, request validation, authorization, and database interactions. I wanted a comprehensive test suite that would verify actual API behavior, support parallel execution, and run against an isolated test database. Ideally, the tests would spin up temporary Docker containers, prepare their own test data, and clean up after themselves.&lt;/p&gt;

&lt;p&gt;Why tests instead of another product feature? Mainly because they give you a reasonably objective way to evaluate the result. For each test, you can check whether the required scenario was implemented, whether the assertions actually verify the intended behavior, and whether the test passes when executed. A green test suite doesn't automatically mean the tests are good, but combined with clearly defined behavioral requirements, it gives you a much more concrete definition of done than a subjective assessment of newly generated functionality.&lt;/p&gt;

&lt;p&gt;There was another reason, too. I wasn't interested in comparing how well the agents could invent test scenarios, analyze coverage, or decide which edge cases deserved attention. That would have been a different experiment, where differences in the results might come down to how each agent interpreted the requirements rather than how it generated the code. What I wanted to measure was much simpler: how many resources would two different workflows need to implement the same, predefined amount of work?&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements First, Generation Second
&lt;/h3&gt;

&lt;p&gt;I started by preparing the testing infrastructure so neither agent would waste time solving the same setup problems. Then I asked an independent agent to analyze all the route handlers in my server and produce a list of test scenarios. At this stage, it wasn't supposed to implement anything, just identify the behaviors that needed verification. The result was a set of Markdown documents containing references to specific route files and lists of required tests.&lt;/p&gt;

&lt;p&gt;I tried to write the test names in a BDD style, making each one describe a specific behavioral requirement rather than the details of its implementation. For example, instead of something vague like &lt;code&gt;should work correctly&lt;/code&gt;, a scenario such as &lt;code&gt;should reject a request with an invalid identifier without modifying the database&lt;/code&gt; tells you much more. The name itself communicates the expected behavior and what the test needs to verify. At the same time, it leaves the agent free to decide which tools, fixtures, and code structure to use.&lt;/p&gt;

&lt;p&gt;In total, I ended up with a specification covering 476 tests. I didn't want to throw all of them at the model at once, even with High reasoning enabled. A large context window doesn't necessarily mean the agent will give every requirement equal attention, and an excessively long task can make it harder to keep track of progress. So I split the specification into five parts, each containing roughly a hundred scenarios, and decided to feed them to the agents one at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Same Prompts, Same Context
&lt;/h3&gt;

&lt;p&gt;For each workflow, I created a separate Git branch from the same starting point in the repository. One branch was handled by local Codex in my IDE, while the other was handled by ChatGPT through GitHub. Both agents received the exact same initial prompt, which briefly described the task and the expected outcome. I deliberately kept it short instead of spelling out the project's architecture, since the repository already contained detailed instructions for AI agents, package conventions, and documentation of the existing infrastructure.&lt;/p&gt;

&lt;p&gt;Both agents started with the same Markdown document containing the first batch of test scenarios. Once they completed it, I provided the next document, repeating the process until all five batches were done. The remaining four tasks didn't even come with any extra explanation: I simply attached the next document to the relevant conversation and hit Enter. I wanted to minimize the influence of additional hints and let each agent work with the project context already available to it.&lt;/p&gt;

&lt;p&gt;Of course, I still managed to make a small mistake in the preparation. My initial prompt was missing one of the most important architectural requirements: the tests had to work against a real test database rather than verify the behavior of a mocked persistence layer. I realized this only after the first generation stage, so I had to introduce an additional task, which I called 1.1. Both agents received identical instructions to refactor the tests they'd already written to use isolated Docker containers with a test database.&lt;/p&gt;

&lt;p&gt;So instead of the original five stages, I ended up with six tasks for each agent: the initial generation, a correction to the architectural requirements, and four more batches of test specifications. It wasn't exactly a flawless experiment from a preparation standpoint, but the important thing was that both agents received the same correction. Besides, this little mistake introduced an interesting variable of its own: I could now see how much extra effort each agent needed to rework existing code after a change in requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different Execution Environments
&lt;/h3&gt;

&lt;p&gt;This brings us to one of the fundamental differences between the two approaches. Local Codex has access to my development environment, so it can execute commands, run TypeScript checks and tests, inspect failures, and fix problems immediately. ChatGPT with the GitHub integration, on the other hand, works primarily with the remote repository and doesn't have the same direct access to my IDE or local development tools. So even though both agents received the same task, they had very different options for validating their own work.&lt;/p&gt;

&lt;p&gt;However, during generation, I noticed something interesting. The cloud agent discovered the GitHub Actions workflows already configured in my repository and started using CI to run checks. In other words, it wasn't just mentally simulating what the code might do. It found a way to get feedback from actual executions, even if that meant going through a much slower cycle of commits and workflow runs. That was a pleasant surprise, since it partially made up for the lack of a local runtime.&lt;/p&gt;

&lt;p&gt;Of course, there's an economic side to this as well. GitHub Actions consumes computing resources, and the free CI allowance comes with limits depending on your plan, repository visibility, and runner configuration. I'm using a free GitHub account, and I didn't pay anything extra for those workflow runs. Still, it's worth accounting for this resource when comparing costs: not receiving a bill doesn't mean the computation itself is free.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Do You Compare Results Across Different Environments?
&lt;/h3&gt;

&lt;p&gt;The difference in available tools is exactly why I decided not to treat code generation as the finish line. Once both agents had completed the six generation tasks, I preserved their original revisions and conducted four independent, read-only audits of each implementation: ChatGPT Medium and High through GitHub, and local Codex Medium and High. All reviewers received the same five specification documents, identical evaluation requirements, and access to the exact same revision of the implementation they were reviewing. The local agents could run TypeScript checks, ESLint, Jest, and Docker, while the cloud agents relied on the GitHub integration and available CI results. Their task was to identify problems and provide evidence without modifying the code.&lt;/p&gt;

&lt;p&gt;After completing all eight audits, I consolidated the findings into a separate report for each implementation. I removed duplicates and separated findings that actually described multiple independent defects. This gave me a more complete picture of the problems identified across all four reviews, rather than relying on the observations of a single agent. I also removed information about which reviewer had reported each issue, so the agent responsible for evaluating and fixing the problems wouldn't be influenced by the reviewer's identity.&lt;/p&gt;

&lt;p&gt;For the remediation stage, I used local Codex with Medium reasoning for both implementations. At this point, the task was no longer about designing functionality from scratch, but about verifying the reported issues, implementing the necessary corrections, and running the tests. Both implementations were fixed in the same local development environment, under comparable conditions. For the final cost comparison, however, I counted only one High-reasoning audit per workflow: Local High for the Codex implementation and Cloud High for the ChatGPT implementation. The other independent reviews contributed to the consolidated remediation reports but were not included in that simplified cost calculation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Counting More Than Just Tokens
&lt;/h3&gt;

&lt;p&gt;Since the whole point of the experiment was to save Codex quota, I tracked its consumption after each generation and validation stage. This would show how much of the allowance a complete local Codex workflow consumed compared with an approach where ChatGPT handled code generation and Codex was brought in only for the final checks. But I also wanted to know how much code each agent had written before any fixes, and how extensive those fixes turned out to be.&lt;/p&gt;

&lt;p&gt;To measure that, I organized both implementations into separate Pull Requests and divided their Git histories into two distinct ranges. The first covered the initial generation and showed how many lines had been added or deleted before the independent audit began. The second covered the remediation commits made by the local agent after reviewing the implementation. This allowed me to measure the amount of generated code and the subsequent rework separately, without confusing either with the final size of the Pull Request.&lt;/p&gt;

&lt;p&gt;And I wasn't particularly interested in the raw line counts alone. If one agent wrote 5,000 lines of tests and the other wrote 7,000, that wouldn't necessarily tell me which approach was better. The number of missing scenarios, incorrect tests, architectural violations, and lines that needed to be added, removed, or rewritten after the audit would be far more informative. Especially when considered alongside the Codex quota consumed and the total time each workflow took.&lt;/p&gt;

&lt;p&gt;Ultimately, I wanted to answer a very practical question: could I delegate most of the code generation to ChatGPT, use local Codex only for validation and fixes, and save a significant portion of my Codex quota in the process? And could I do that without ending up with hundreds of manual corrections or a pile of unreliable tests, but with a fully working implementation that met the exact same requirements in both workflows? If the approach actually worked, how much could I save compared with my usual local Codex workflow?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: How Much Did Code Generation Actually Cost?
&lt;/h2&gt;

&lt;p&gt;With both implementations finished, I finally had enough data to move beyond impressions and start comparing numbers. The first thing I wanted to measure was the cost of code generation itself, before bringing independent reviews and subsequent fixes into the picture. Both agents had received the same specifications, worked through the same six tasks, and used High reasoning. The difference was where they worked: one was running locally through Codex, while the other operated through ChatGPT and GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generation Time and Codex Quota
&lt;/h3&gt;

&lt;p&gt;I tracked the execution time of every task and, for local Codex, the percentage of my five-hour usage quota it consumed. The quota figures represent the amount spent on each individual task, not the remaining allowance shown afterward. I deliberately kept those two measurements separate because the entire experiment eventually stretched across more than one quota window. For this first comparison, though, the six generation tasks give us a straightforward picture.&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;Local Codex High&lt;/th&gt;
&lt;th&gt;Codex Quota Used&lt;/th&gt;
&lt;th&gt;ChatGPT High + GitHub&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Task 1&lt;/td&gt;
&lt;td&gt;6m 17s&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;12m 44s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task 1.1&lt;/td&gt;
&lt;td&gt;10m 29s&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;td&gt;21m 02s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task 2&lt;/td&gt;
&lt;td&gt;11m 30s&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;16m 04s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task 3&lt;/td&gt;
&lt;td&gt;4m 49s&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;td&gt;11m 54s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task 4&lt;/td&gt;
&lt;td&gt;6m 36s&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;11m 15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task 5&lt;/td&gt;
&lt;td&gt;6m 35s&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;8m 59s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;46m 16s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;65%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1h 21m 58s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The local Codex agent completed all six tasks in just over 46 minutes, consuming 65% of a five-hour Codex quota in the process. ChatGPT took almost 82 minutes to complete the same sequence, making it approximately 77% slower. That's a fairly substantial difference, and it confirms what I'd already noticed during my earlier experiments: local Codex is considerably faster at this kind of work. But the cloud workflow consumed none of my separate Codex quota.&lt;/p&gt;

&lt;p&gt;That last distinction is the entire reason I started experimenting with this approach. I wasn't measuring whether ChatGPT somehow performed the computation for free, because it obviously didn't. I was measuring how much of my limited Codex allowance I could preserve by moving code generation into a service I was already using. And in this particular case, the difference was striking: 65% of my Codex quota versus no consumption of that quota at all, although ChatGPT remained subject to its own subscription limits.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Much Code Did They Produce?
&lt;/h3&gt;

&lt;p&gt;Execution time and quota consumption were only part of the picture. I also compared the Git changes produced by each agent before the independent audit and remediation stages began. Since the task involved both writing route tests and supporting them with real PostgreSQL infrastructure, I counted the complete implementation diff rather than test files alone. This gave me a consistent measure of how much code each workflow introduced.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Local Codex High&lt;/th&gt;
&lt;th&gt;ChatGPT High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lines added&lt;/td&gt;
&lt;td&gt;5,032&lt;/td&gt;
&lt;td&gt;6,214&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines deleted&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Net lines changed&lt;/td&gt;
&lt;td&gt;+5,006&lt;/td&gt;
&lt;td&gt;+6,172&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Interestingly, the cloud agent produced 1,182 more added lines, roughly 23% more than local Codex. Both implementations accounted for the same 476 distinct required scenarios, although their test organization and supporting infrastructure differed. More code isn't automatically better code, of course, and at this stage I had no reason to assume the larger implementation was more complete or more reliable. That's precisely what the independent reviews were supposed to establish.&lt;/p&gt;

&lt;p&gt;So the initial trade-off was clear. Local Codex delivered the implementation considerably faster, but at a substantial cost to its usage quota. ChatGPT took longer and generated a larger codebase, yet left that separate quota untouched. The remaining question was whether the savings would survive the next stages, when both implementations had to undergo code review, verification, and whatever fixes were necessary to make them genuinely reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Does a Better Job Reviewing Code?
&lt;/h2&gt;

&lt;p&gt;Writing several thousand lines of code in a relatively short time is certainly impressive. But the amount of code written tells us very little about how well it was implemented. So, after the generation phase, I decided to run another experiment: compare how AI agents with different reasoning levels and execution environments handle the analysis of a large, already implemented codebase.&lt;/p&gt;

&lt;p&gt;For each of the two implementations, I ran four independent audits: ChatGPT Medium and High through GitHub, and local Codex Medium and High. All agents received the same review requirements, the five original specification documents, and access to the same revision of the implementation they were reviewing. However, their capabilities differed: local agents could independently run TypeScript, ESLint, Jest, and Docker, while cloud agents worked through the GitHub integration and could examine available CI results. Each agent was tasked with identifying problems, providing evidence, and producing a report without making any fixes.&lt;/p&gt;

&lt;p&gt;Once the audits were complete, I consolidated all the reports into a separate findings registry for each implementation, removed duplicates, and split findings that actually described several independent defects. Another local agent running at Medium reasoning then examined each finding and attempted to fix the confirmed problems. It worked from the consolidated list without knowing which reviewer had originally reported each issue. This allowed me to evaluate not just the number of findings, but how well-founded they actually were.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing the Code Generated by ChatGPT
&lt;/h3&gt;

&lt;p&gt;Let's start with the cloud agent's implementation. The four independent reviews produced a total of 31 initial findings, which were consolidated into 23 distinct defect candidates after normalization. Subsequent verification confirmed 19 problems, of which 16 were fixed and three remained unresolved. Another four cases were classified as Unverifiable: the agents had observed intermittent test failures, but their root causes could not be established.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Cloud Medium&lt;/th&gt;
&lt;th&gt;Cloud High&lt;/th&gt;
&lt;th&gt;Local Medium&lt;/th&gt;
&lt;th&gt;Local High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review time&lt;/td&gt;
&lt;td&gt;4:13&lt;/td&gt;
&lt;td&gt;15:12&lt;/td&gt;
&lt;td&gt;5:56&lt;/td&gt;
&lt;td&gt;10:41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex quota consumed&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;7%&lt;/td&gt;
&lt;td&gt;27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defect candidates identified&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirmed findings&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False Positives&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unverifiable&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique confirmed findings&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Known defects detected&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;26.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;57.9%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;26.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The results were quite revealing. Local Codex High found the most confirmed problems: 15 out of 19, although the review consumed 27% of its five-hour quota. ChatGPT High found 11 problems, taking more time but consuming none of the separate Codex quota. Interestingly, three confirmed problems were identified exclusively by Cloud High, while another four were found only by Local High.&lt;/p&gt;

&lt;p&gt;None of the findings was ultimately classified as a False Positive, but that doesn't mean every finding was confirmed. Four cases remained unresolved due to insufficient evidence, so I excluded them from the confirmed defect count. It's also important to remember that passing tests don't guarantee those tests are correct: a significant proportion of the findings concerned insufficiently precise assertions rather than failing tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing the Code Generated by Local Codex
&lt;/h3&gt;

&lt;p&gt;Now let's look at the review results for the local implementation. Here, the four reviewers produced 27 initial findings, which were consolidated into 17 distinct candidates after removing duplicates. Subsequent verification confirmed 13 problems, 12 of which were fixed. One finding turned out to be a false positive, while another three were classified as outside the agreed scope of work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Cloud Medium&lt;/th&gt;
&lt;th&gt;Cloud High&lt;/th&gt;
&lt;th&gt;Local Medium&lt;/th&gt;
&lt;th&gt;Local High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review time&lt;/td&gt;
&lt;td&gt;5:02&lt;/td&gt;
&lt;td&gt;16:04&lt;/td&gt;
&lt;td&gt;5:04&lt;/td&gt;
&lt;td&gt;5:04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex quota consumed&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;td&gt;7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defect candidates identified&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirmed findings&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False Positives&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Out of Scope&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique confirmed findings&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Known defects detected&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;23.1%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;46.2%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38.5%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;61.5%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once again, Local Codex High found the most confirmed problems: eight out of thirteen. But this time, the difference in resource consumption was much smaller. Both local agents completed their reviews in approximately five minutes, consuming 6% and 7% of their quotas, respectively. Cloud High spent over 16 minutes and identified six confirmed problems, four of which no other agent detected. Meanwhile, Cloud Medium found only three genuine problems out of the four it reported, although one of those was its unique finding.&lt;/p&gt;

&lt;p&gt;This time, false positives also appeared. Cloud Medium and Cloud High reported the same issue, which verification later revealed to be the result of an incorrect comparison of Git revisions. Another three findings were excluded from the confirmed defect statistics as Out of Scope. This clearly demonstrates why simply comparing the number of findings in each report would have been misleading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results Across Both Experiments
&lt;/h3&gt;

&lt;p&gt;Combining the results of both implementations gives us 40 distinct defect candidates, 32 of which were confirmed during subsequent verification. Of those, 28 were fixed and four remained unresolved. Another four cases could not be sufficiently verified, one turned out to be a False Positive, and three were excluded as Out of Scope. Importantly, these findings concern two different implementations, so even similar defects are counted separately for each one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Cloud Medium&lt;/th&gt;
&lt;th&gt;Cloud High&lt;/th&gt;
&lt;th&gt;Local Medium&lt;/th&gt;
&lt;th&gt;Local High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Defect candidates identified&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;True Positives&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False Positives&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Out of Scope&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unverifiable&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique confirmed findings&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Precision&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;88.9%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;94.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observed Recall&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;25.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;53.1%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;31.3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;71.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here, Precision measures the proportion of an agent's adjudicated findings that turned out to be genuine problems, excluding Out of Scope and Unverifiable cases. Observed Recall measures how many of the 32 known confirmed problems each agent managed to identify. This is not an absolute measure of review completeness, since some defects may have gone unnoticed by all four agents. Likewise, a Precision score of 100% doesn't mean the model is infallible: the sample is relatively small, and the final decisions were made by another AI agent, albeit one that also inspected the code and executed tests.&lt;/p&gt;

&lt;p&gt;Across both implementations, Local Codex High ranked first in defect detection, identifying 23 of the 32 confirmed problems. ChatGPT High found 17, outperforming Local Codex Medium, which identified ten. At the same time, seven confirmed findings were unique to Cloud High, while six were unique to Local High. This means that even the most resource-intensive configuration could not replace all the others.&lt;/p&gt;

&lt;p&gt;On the other hand, these results don't justify claiming that Local High will always review code better or that Cloud Medium will always perform worst. We compared only two specific implementations of the same requirements, and the execution environments had different capabilities for running checks. Still, an interesting trend emerges: increasing the reasoning level in both environments was accompanied by a substantial increase in the number of confirmed problems detected. ChatGPT High through GitHub also demonstrated that a high-quality audit doesn't necessarily require direct access to a local development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Much Did It Cost to Fix the Bugs?
&lt;/h2&gt;

&lt;p&gt;After four independent audits of each implementation, it was time to fix the identified problems. And this is where I decided to simplify the experiment a little.&lt;/p&gt;

&lt;p&gt;Instead of using a single agent's report, I combined the results of all four reviews, removed duplicates, and created one consolidated list of problems for each implementation. This way, the agent responsible for the fixes received the most complete picture possible, regardless of which reviewer had originally identified a particular defect.&lt;/p&gt;

&lt;p&gt;For both implementations, I used &lt;strong&gt;local Codex with Medium reasoning&lt;/strong&gt;. In my view, High was no longer quite as necessary at this stage: most of the investigative work had already been done during the audits. What remained was to verify the validity of the findings, implement the fixes, and ensure the tests passed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time, Quota, and Scope of Changes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Local Codex Code&lt;/th&gt;
&lt;th&gt;ChatGPT + GitHub Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time spent fixing bugs&lt;/td&gt;
&lt;td&gt;23m 01s&lt;/td&gt;
&lt;td&gt;12m 30s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex quota consumed&lt;/td&gt;
&lt;td&gt;44%&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initial lines of code added&lt;/td&gt;
&lt;td&gt;5,032 lines&lt;/td&gt;
&lt;td&gt;6,214 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines added during fixes&lt;/td&gt;
&lt;td&gt;297 lines&lt;/td&gt;
&lt;td&gt;346 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines deleted during fixes&lt;/td&gt;
&lt;td&gt;125 lines&lt;/td&gt;
&lt;td&gt;5 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total volume of changes&lt;/td&gt;
&lt;td&gt;422 lines&lt;/td&gt;
&lt;td&gt;351 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Changes relative to initial code volume&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The percentage of changes is calculated by dividing the sum of added and deleted lines during remediation by the number of lines added during the initial implementation. This measures Git code churn, not the literal percentage of code that was rewritten.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And this is where I encountered a rather unexpected difference.&lt;/p&gt;

&lt;p&gt;Fixing the code generated by local Codex took 23 minutes and consumed 44% of the quota. Meanwhile, the code created through ChatGPT was refined in just 12.5 minutes, consuming only 24%.&lt;/p&gt;

&lt;p&gt;In other words, the local implementation required approximately &lt;strong&gt;1.84 times as much time and 1.83 times as much quota&lt;/strong&gt;, even though its initial codebase was smaller.&lt;/p&gt;

&lt;p&gt;Interestingly, the ratios for time and quota consumption are almost identical. This suggests that the unusually high 44% figure is unlikely to be explained by some special cost associated with Medium reasoning on that particular task. A much simpler explanation is that the agent simply worked longer.&lt;/p&gt;

&lt;p&gt;But why? One possible factor was flaky tests that occasionally failed and then passed when rerun. This may have forced the agent to spend additional time repeating checks and investigating failures. However, I can't determine exactly how much time was spent on those cases. Therefore, the 44% should be treated as the actual measured result of this particular run, not as a guaranteed cost for anyone attempting to reproduce the experiment.&lt;/p&gt;

&lt;p&gt;The difference in the volume of changes was interesting too. In the local implementation, the agent added 297 lines and deleted 125, while in the cloud implementation it added 346 and deleted only five. Comparing the total volume of these changes against the original implementation size gives us 8.4% versus 5.6%.&lt;/p&gt;

&lt;p&gt;However, it would be wrong to conclude that one implementation was better simply because it required a smaller percentage of changes. Fixes can involve either rewriting existing code or adding new checks. So these numbers are better understood as a measure of the amount of rework required, rather than a direct measure of the initial implementation's quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Results: Which Approach Was More Cost-Effective?
&lt;/h2&gt;

&lt;p&gt;Now it's time to put all the numbers together and answer the main question behind this experiment: can you really save Codex quota by moving code generation into ChatGPT and using the local agent primarily for reviews and fixes?&lt;/p&gt;

&lt;p&gt;For this comparison, I decided to include three main stages of work: code generation, independent Code Review, and fixing the identified problems.&lt;/p&gt;

&lt;p&gt;For each approach, I'm counting the High-level review performed in its corresponding environment. That means Local High for the code generated by local Codex, and Cloud High for the code generated through ChatGPT. In both cases, the fixes were performed by local Codex Medium.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Much Did the Full Cycle Cost?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Local Codex: Time&lt;/th&gt;
&lt;th&gt;Codex Quota&lt;/th&gt;
&lt;th&gt;ChatGPT + GitHub: Time&lt;/th&gt;
&lt;th&gt;Codex Quota&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generation — High&lt;/td&gt;
&lt;td&gt;46:16&lt;/td&gt;
&lt;td&gt;65%&lt;/td&gt;
&lt;td&gt;1:21:58&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Review — High&lt;/td&gt;
&lt;td&gt;5:04&lt;/td&gt;
&lt;td&gt;7%&lt;/td&gt;
&lt;td&gt;15:12&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixes — Local Medium&lt;/td&gt;
&lt;td&gt;23:01&lt;/td&gt;
&lt;td&gt;44%&lt;/td&gt;
&lt;td&gt;12:30&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1:14:21&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;116%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1:49:40&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;24%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The quota percentages are summed across separate stages, which may have taken place in different five-hour usage windows. This does not mean that 116% was consumed within a single window. The zero values for ChatGPT mean zero consumption of the separate Codex quota, not an absence of all costs or usage limits.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And this is where things get really interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local Codex was approximately 35 minutes faster.&lt;/strong&gt; The complete measured cycle took 1 hour and 14 minutes, compared with almost 1 hour and 50 minutes for ChatGPT. In other words, the cloud-based approach required approximately 47.5% more time.&lt;/p&gt;

&lt;p&gt;But when we look at Codex quota consumption, the picture changes dramatically.&lt;/p&gt;

&lt;p&gt;The local approach consumed a total of 116% of a five-hour quota, while the cloud-based approach consumed just 24%. This means that &lt;strong&gt;ChatGPT reduced Codex quota consumption by approximately 4.8 times&lt;/strong&gt;, or 79%.&lt;/p&gt;

&lt;p&gt;For me, this is the main result of the experiment. I obtained two functionally comparable results while spending almost five times less of the local agent's limited resources on one of them. The price of those savings was approximately 35 additional minutes of waiting.&lt;/p&gt;

&lt;p&gt;Of course, this isn't a monetary saving in the literal sense. ChatGPT has its own pricing model and limits, and my calculations specifically concern Codex quota consumption. But if you already use both services and regularly run into Codex's five-hour usage limit, the difference can be quite significant.&lt;/p&gt;

&lt;h3&gt;
  
  
  But What About the Quality of the Generated Code?
&lt;/h3&gt;

&lt;p&gt;Here, the results were less straightforward.&lt;/p&gt;

&lt;p&gt;Both agents implemented the same 476 unique test scenarios. However, independent audits found different numbers of problems in their respective implementations.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Local Codex&lt;/th&gt;
&lt;th&gt;ChatGPT + GitHub&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Confirmed problems&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time spent on fixes&lt;/td&gt;
&lt;td&gt;23:01&lt;/td&gt;
&lt;td&gt;12:30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quota consumed by fixes&lt;/td&gt;
&lt;td&gt;44%&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changes relative to initial code volume&lt;/td&gt;
&lt;td&gt;8.4%&lt;/td&gt;
&lt;td&gt;5.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Judging by the number of confirmed defects, &lt;strong&gt;the initial local Codex implementation appears to be better&lt;/strong&gt;: reviewers found 13 problems in it, compared with 19 in ChatGPT's implementation. In other words, the cloud implementation had approximately 46% more confirmed findings.&lt;/p&gt;

&lt;p&gt;But here's the paradox: fixing ChatGPT's code required almost half as much time and quota, and the relative volume of changes was smaller — 5.6% versus 8.4%.&lt;/p&gt;

&lt;p&gt;This is a good example of why the number of defects and the difficulty of fixing them aren't always directly correlated. Some problems can be resolved by adding a few assertions, while others require substantial changes to the testing infrastructure or a different testing strategy altogether.&lt;/p&gt;

&lt;p&gt;I wouldn't try to convert these numbers into something like "95% correct code." A Git diff measures the volume of changes, not the percentage of correct implementation. And the number of identified problems doesn't guarantee that reviewers found absolutely every defect.&lt;/p&gt;

&lt;p&gt;So, in terms of initial code generation quality, I would favor local Codex because it received fewer confirmed findings. But when it comes to the cost of subsequent remediation, ChatGPT's implementation won this particular experiment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which Agent Is Better at Code Review?
&lt;/h3&gt;

&lt;p&gt;Here, the winner was much clearer.&lt;/p&gt;

&lt;p&gt;Combining the review results for both implementations gives us 32 confirmed problems. Here's how many of them the two High-reasoning agents managed to identify:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Local High&lt;/th&gt;
&lt;th&gt;Cloud High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Confirmed problems identified&lt;/td&gt;
&lt;td&gt;23 out of 32&lt;/td&gt;
&lt;td&gt;17 out of 32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known problems detected&lt;/td&gt;
&lt;td&gt;71.9%&lt;/td&gt;
&lt;td&gt;53.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unique confirmed findings&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex quota consumed across two reviews&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Local Codex High proved to be the more effective reviewer&lt;/strong&gt;, finding almost 72% of known problems compared with ChatGPT High's 53%. A difference of nearly 19 percentage points is quite substantial.&lt;/p&gt;

&lt;p&gt;But the cloud agent's performance shouldn't be underestimated either. It found 17 confirmed defects — approximately 74% of the number identified by Local High. What's more, seven of those defects went unnoticed by every other reviewer.&lt;/p&gt;

&lt;p&gt;And it achieved all of this without consuming any of the separate Codex quota.&lt;/p&gt;

&lt;p&gt;So here's my conclusion: if I needed the most thorough Code Review possible and quota wasn't a concern, I would choose Local High. But if I needed to regularly review large amounts of code without burning through Codex limits, ChatGPT High with GitHub would be a very attractive alternative.&lt;/p&gt;

&lt;p&gt;Better yet, I'd use them as independent reviewers. After all, the experiment showed that they don't simply find different numbers of problems — they also catch defects that the other agent misses.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Final Verdict
&lt;/h3&gt;

&lt;p&gt;After all these experiments, I've come to the conclusion that there's little reason to force a single tool to do absolutely everything.&lt;/p&gt;

&lt;p&gt;Local Codex is faster, and its initial implementation received fewer confirmed findings in this experiment. At the High reasoning level, it also demonstrated the strongest Code Review performance.&lt;/p&gt;

&lt;p&gt;But ChatGPT with GitHub delivered a functionally comparable result while consuming almost five times less Codex quota. Yes, it took approximately 47.5% more time, but for large tasks that don't require a developer's constant attention, that seems like a perfectly reasonable trade-off.&lt;/p&gt;

&lt;p&gt;I'll probably adopt a hybrid approach going forward: ChatGPT for large-scale code generation and independent audits, and local Codex for tasks where speed is critical, direct code execution is necessary, or maximum review thoroughness matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The main idea is simple: you don't have to use the most quota-expensive tool at every stage to get a good result. Sometimes, all you need is to distribute the work intelligently between several agents.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Limitations of the experiment.&lt;/em&gt; The cost comparison presented here sums the recorded generation stage, one selected High-level review, and the measured remediation run. In reality, I used the combined results of four independent audits to prepare the remediation tasks, not just the single audit included in the cost table. There were also additional verification and remediation iterations after the initial fixes, for which time and quota consumption were not fully recorded. Therefore, the 116% and 24% figures should be interpreted as a comparison of selected, measured stages rather than the complete actual cost of every action performed during the experiment. Furthermore, several problems remained unresolved, and some intermittent test failures never received a definitive explanation.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Small Clarification About "Free Codex"
&lt;/h3&gt;

&lt;p&gt;I can already anticipate a perfectly fair question: if I promised Codex without consuming its quota, why did I end up using local Codex Medium to fix the bugs?&lt;/p&gt;

&lt;p&gt;The thing is, I believe &lt;strong&gt;it's entirely possible to bring the code into a working state using ChatGPT with GitHub as well&lt;/strong&gt;. But since the result still needs to be validated in a real execution environment, I decided to simplify the experiment and have a local agent fix both implementations under identical conditions.&lt;/p&gt;

&lt;p&gt;Even with this approach, &lt;strong&gt;Codex quota consumption was reduced by approximately 4.8 times&lt;/strong&gt; across the stages included in the comparison. And I suspect it's also realistic to avoid consuming the local Codex quota entirely: use ChatGPT for generation, analysis, and fixes, while running checks locally and feeding the results back into the chat. Of course, such a workflow would most likely require considerably more time and manual effort.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;"free" here means no consumption of the separate Codex quota&lt;/strong&gt;, not the absence of a subscription, usage limits, or any other costs whatsoever. I didn't test a fully cloud-based development cycle in this experiment, but the results give me reason to believe that it's a promising approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Does More Code Mean Better Code?
&lt;/h2&gt;

&lt;p&gt;Toward the end of the experiment, I noticed something interesting: &lt;strong&gt;ChatGPT had generated 23.5% more code than local Codex&lt;/strong&gt; — 6,214 added lines versus 5,032.&lt;/p&gt;

&lt;p&gt;That raised another question: was the additional code actually justified, or had the cloud agent simply produced more boilerplate and duplication?&lt;/p&gt;

&lt;p&gt;To find out, I asked an independent cloud-based AI reviewer to compare both original implementations, before any remediation. The reviewer examined functional correctness, requirements compliance, test reliability, architecture, decomposition, DRY, maintainability, and implementation complexity.&lt;/p&gt;

&lt;p&gt;This time, I wasn't interested in how many individual bugs each implementation contained. I wanted an overall engineering assessment: &lt;strong&gt;which codebase would be better to maintain and extend?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the verdict:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evaluation criterion&lt;/th&gt;
&lt;th&gt;ChatGPT + GitHub&lt;/th&gt;
&lt;th&gt;Local Codex&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Functional correctness&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requirements compliance&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test reliability&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture &amp;amp; Separation of Concerns&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decomposition&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DRY &amp;amp; Reusability&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintainability&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation complexity&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code efficiency&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Score&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.0 / 9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.0 / 9&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Scoring: Each implementation receives 1 point for a category win and 1 point for a tie. Scores are not zero-sum: a tie indicates comparable performance, so neither implementation is penalized. The maximum individual score is 9 points. This is a simplified summary of the reviewer's qualitative judgments, not a standardized software quality benchmark.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Interestingly, the reviewer gave &lt;strong&gt;ChatGPT the overall win&lt;/strong&gt;, although with only moderate confidence.&lt;/p&gt;

&lt;p&gt;Its implementation received stronger assessments for correctness, requirements compliance, and reliability. It featured more extensive database assertions, stricter test isolation, and a successful CI run on the exact revision being evaluated.&lt;/p&gt;

&lt;p&gt;Local Codex, meanwhile, demonstrated better code efficiency and lower implementation complexity. Its centralized test infrastructure and greater use of parameterized tests allowed it to cover essentially the same requirements with substantially less code.&lt;/p&gt;

&lt;p&gt;The reviewer found that approximately &lt;strong&gt;86% of the difference in added lines came from the route tests themselves&lt;/strong&gt;, rather than infrastructure. Some of ChatGPT's additional code provided meaningful assertions, while some came from repeated setup and less aggressive reuse.&lt;/p&gt;

&lt;p&gt;There is one important qualification: the reviewer could verify a successful CI run for ChatGPT's original revision, but not for the exact local Codex revision. That gave ChatGPT stronger evidence of working behavior, without proving that the local implementation was broken. The final verdict was therefore conditional, not an absolute measurement of intrinsic code quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My takeaway?&lt;/strong&gt; The additional 23.5% of code wasn't entirely wasted, but it wasn't entirely justified either. ChatGPT produced the implementation the independent reviewer preferred overall, while local Codex delivered a leaner solution with a similarly strong architectural foundation.&lt;/p&gt;

&lt;p&gt;A rather fitting conclusion to this experiment: &lt;strong&gt;more code doesn't necessarily mean better code — but less code doesn't automatically mean better engineering either.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  P.S. Thanks for Reading All the Way to the End!
&lt;/h2&gt;

&lt;p&gt;If you found this article interesting or useful, I'd really appreciate a ❤️ and a follow!&lt;/p&gt;

&lt;p&gt;I regularly run technical experiments, explore new approaches to software development, and share what I learn along the way. There's plenty more to come!&lt;/p&gt;

&lt;p&gt;In the meantime, you might also enjoy my other articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0"&gt;💥 Easy way to save your AI coding agent a surprising amount of context&lt;/a&gt;&lt;/strong&gt; — Learn how to optimize your AI-assisted development workflow and dramatically reduce token consumption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co"&gt;100+ API Endpoints and Almost Zero Integration Bugs. Sharing the Framework&lt;/a&gt;&lt;/strong&gt; — Discover my approach to managing complex API contracts and preventing integration issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading, and see you in the next experiment! 🚀&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0" class="crayons-story__hidden-navigation-link"&gt;💥 Easy way to save your AI coding agent a surprising amount of context.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kotyk" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3186292%2Ff76ff383-d13c-42f5-9b1c-f438e95b8036.jpg" alt="kotyk profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kotyk" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mykola Mizhigurskiy
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mykola Mizhigurskiy
                
                
              
              &lt;div id="story-author-preview-content-4361926" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kotyk" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3186292%2Ff76ff383-d13c-42f5-9b1c-f438e95b8036.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mykola Mizhigurskiy&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0" id="article-link-4361926"&gt;
          💥 Easy way to save your AI coding agent a surprising amount of context.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/softwareengineering"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;softwareengineering&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co" class="crayons-story__hidden-navigation-link"&gt;100+ API Endpoints and Almost Zero Integration Bugs. Sharing the Framework.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kotyk" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3186292%2Ff76ff383-d13c-42f5-9b1c-f438e95b8036.jpg" alt="kotyk profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kotyk" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mykola Mizhigurskiy
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mykola Mizhigurskiy
                
                
              
              &lt;div id="story-author-preview-content-4427022" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kotyk" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3186292%2Ff76ff383-d13c-42f5-9b1c-f438e95b8036.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mykola Mizhigurskiy&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 18&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co" id="article-link-4427022"&gt;
          100+ API Endpoints and Almost Zero Integration Bugs. Sharing the Framework.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/api"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;api&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/testing"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;testing&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/software"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;software&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            13 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>programming</category>
      <category>chatgpt</category>
      <category>productivity</category>
    </item>
    <item>
      <title>100+ API Endpoints and Almost Zero Integration Bugs. Sharing the Framework.</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Tue, 18 Aug 2026 14:19:48 +0000</pubDate>
      <link>https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co</link>
      <guid>https://dev.to/kotyk/100-api-endpoints-and-almost-zero-integration-bugs-sharing-the-framework-49co</guid>
      <description>&lt;p&gt;Like most developers, I spent quite a long time suffering from integration issues that inevitably appear in any reasonably serious project: the backend changes a field, adds a new one, changes its format — and the frontend finds out only after something breaks.&lt;/p&gt;

&lt;p&gt;So, some time ago, I decided I had had enough and built my own API contract testing framework for the project I was working on. In practice, the result turned out even better than I expected: after fully implementing it, the number of integration issues between the frontend and backend dropped to almost zero.&lt;/p&gt;

&lt;p&gt;In this article, I want to share this framework with you: how I designed it, what problems I wanted to solve, how I organized schemas and contracts, and why it eventually became much more than just a collection of API tests.&lt;/p&gt;

&lt;p&gt;The stack in my case is fairly standard for a modern frontend project: &lt;strong&gt;JavaScript, TypeScript, React, and Zod&lt;/strong&gt;. But the idea itself is not tied to any particular library — Zod is simply a very convenient tool for implementing it.&lt;/p&gt;

&lt;p&gt;Before building anything, I defined the primary goal of the framework: &lt;strong&gt;automatically validate real API responses and guarantee that the backend returns exactly what the frontend expects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That means catching changes in field types and formats, missing required fields, newly introduced unexpected fields, validation rule violations, and changes to stable response structures.&lt;/p&gt;

&lt;p&gt;And that is where the entire framework architecture begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  QA Engineer vs. Software Developer
&lt;/h2&gt;

&lt;p&gt;Before we begin, I want to address what I believe is a fairly common misconception about API contract testing: &lt;strong&gt;that it should be done by developers rather than QA engineers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This framework can be implemented and successfully used by both a QA engineer and a software developer. Its basic implementation does not require deep knowledge of the application architecture: a QA engineer can describe API contracts, build validation schemas, and use them to automatically validate API responses. In this form, the framework already fully performs its primary task — detecting contract violations between the backend and its consumer.&lt;/p&gt;

&lt;p&gt;However, when a software developer integrates this framework directly into the application architecture, the same resources can provide significantly more value. Properly designed schemas effectively become a &lt;strong&gt;single source of truth&lt;/strong&gt; for several parts of the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript types;&lt;/li&gt;
&lt;li&gt;contract tests;&lt;/li&gt;
&lt;li&gt;runtime validation;&lt;/li&gt;
&lt;li&gt;form validation;&lt;/li&gt;
&lt;li&gt;rules and constraints for individual fields;&lt;/li&gt;
&lt;li&gt;frontend elements that depend on those constraints, such as validation errors or character counters;&lt;/li&gt;
&lt;li&gt;API documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of independently describing the same structure in types, tests, forms, UI, and documentation, we define it once and reuse it everywhere it is needed.&lt;/p&gt;

&lt;p&gt;That is why, for QA, this framework can be a powerful API contract testing tool, while for a developer it can also become part of the application architecture itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework Organization
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/api/
  ├── endpoints  # Resources required for API interaction
  |   └── users  # Business-entity folder grouping related endpoints
  |       └── getProductById/  # Named endpoint folder
  |           ├── getProductById.api.ts  # Bare reusable API function
  |           ├── getProductById.hook.ts  # UI-ready hook
  |           └── getProductById.schemas.ts  # Validation schemas and types
  └── schemas  # Business-entity definitions
      ├── common.schemas.ts  # Schemas and types reused across business entities
      └── product.schemas.ts  # Schemas and types for a specific business entity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention to how the files inside each endpoint are organized. There are two reasons for this.&lt;/p&gt;

&lt;p&gt;The first is that I build this framework as an &lt;strong&gt;AI-native architecture&lt;/strong&gt; and try to make it as predictable and convenient for AI agents as possible. The more clearly responsibilities are separated and the more stable the naming patterns are, the easier it is for an agent to understand the structure, locate the correct file, and extend the existing implementation consistently.&lt;/p&gt;

&lt;p&gt;The second reason is separation of concerns. I intentionally split the implementation into several &lt;strong&gt;suffix files&lt;/strong&gt;, each with one clearly defined responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;*.api.ts&lt;/code&gt;&lt;/strong&gt; — a minimal function responsible for interacting with the API. It does not depend on React and contains only the logic required to make a request and receive a response. Because of this, it can be used independently in React hooks, contract tests, server-side code, or any other consumer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;*.hook.ts&lt;/code&gt;&lt;/strong&gt; — the React layer on top of the API function. This is where loading and error states, caching, state management, transformations, and other UI-specific logic can live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;*.schemas.ts&lt;/code&gt;&lt;/strong&gt; — the contract of a specific endpoint: Zod schemas for runtime validation and the TypeScript types associated with them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation is particularly important for contract tests. A test does not need to initialize React or pull UI-specific logic along with it just to validate an API. It can call a function from &lt;code&gt;*.api.ts&lt;/code&gt; directly and validate the response using a schema from &lt;code&gt;*.schemas.ts&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Naming Conventions
&lt;/h2&gt;

&lt;p&gt;I personally consider semantics one of the most underrated parts of software development, and I take it very seriously. A good name should immediately tell you &lt;strong&gt;what entity you are looking at, what role it performs, and where it is used&lt;/strong&gt;, even before you open the file.&lt;/p&gt;

&lt;p&gt;This becomes especially important in AI-native repositories: consistent naming allows AI to infer relationships between entities more accurately, anticipate their purpose, and find the right context. That is why naming conventions in this framework are not cosmetic — they are part of the architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Endpoints
&lt;/h3&gt;

&lt;p&gt;For endpoints, I use a simple rule:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;operation&amp;gt;&amp;lt;entity&amp;gt;&amp;lt;qualifier?&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;operation&lt;/strong&gt; comes first, followed by the &lt;strong&gt;business entity&lt;/strong&gt;, and then, when necessary, an additional qualifier describing the request.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getProductById&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createProduct&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modifyProduct&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteProduct&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getUserProduct&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same naming is used for the endpoint folder and its related files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getProductById/
  ├── getProductById.api.ts
  ├── getProductById.hook.ts
  └── getProductById.schemas.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, all parts of a particular API request can easily be found using the same name.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schemas &amp;amp; Types
&lt;/h3&gt;

&lt;p&gt;For schemas and types, I use a separate set of standard suffixes describing the role of the data in a particular request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QueryParams&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RequestPayload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResponsePayload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the entity is a Zod schema, I simply add &lt;code&gt;Schema&lt;/code&gt; to the name.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GetProductById_QueryParams&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CreateProduct_RequestPayload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetProductById_ResponsePayload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetProductById_ResponsePayloadSchema&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, the name itself describes the structure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;endpoint&amp;gt;_&amp;lt;data role&amp;gt;&amp;lt;Schema?&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So when you see &lt;code&gt;GetProductById_ResponsePayloadSchema&lt;/code&gt;, you immediately know three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;which endpoint it belongs to;&lt;/li&gt;
&lt;li&gt;which part of the API contract it describes;&lt;/li&gt;
&lt;li&gt;that you are looking at a runtime schema rather than a TypeScript type.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Common Schemas
&lt;/h3&gt;

&lt;p&gt;Let us start with the simplest file — &lt;code&gt;common.schemas.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its purpose is to store small but reusable schemas that appear across many business entities. These are not standalone application models, but rather building blocks: IDs, timestamps, tracker fields, UUIDs, emails, and other standardized primitives.&lt;/p&gt;

&lt;p&gt;For example, a minimal &lt;code&gt;common.schemas.ts&lt;/code&gt; might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Unified ID type used across the application&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Id_Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Unified set of fields used to track entity creation and modification&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Tracker_Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;createdOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;modifiedOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;datetime&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;These schemas are not duplicated in every business entity. Instead, they are reused through &lt;code&gt;extend()&lt;/code&gt; or directly as individual fields.&lt;/p&gt;

&lt;p&gt;This allows us to change a rule in one place and automatically propagate it throughout the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business Entity
&lt;/h3&gt;

&lt;p&gt;Now let us move to &lt;code&gt;product.schemas.ts&lt;/code&gt; — the file describing the &lt;code&gt;Product&lt;/code&gt; business entity. For schemas like this, I use a simple naming rule: the entity name plus the &lt;code&gt;Schema&lt;/code&gt; suffix — in our case, &lt;code&gt;Product_Schema&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is one fundamentally important point here: &lt;strong&gt;we describe the entity as the frontend sees it, not as it exists internally on the backend&lt;/strong&gt;. The same entity can have different representations on the two sides of an API.&lt;/p&gt;

&lt;p&gt;For example, the backend model of a product might contain a &lt;code&gt;stock&lt;/code&gt; property with the exact number of units remaining in the warehouse. The store owners probably do not want to expose that information publicly, so instead of &lt;code&gt;stock: 12345&lt;/code&gt;, the frontend might receive only &lt;code&gt;inStock: true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That frontend representation is what our contract should describe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Id_Schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tracker_Schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./common.schemas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Product business-entity schema for runtime validation.&lt;/span&gt;
&lt;span class="c1"&gt;// Extends the shared tracker fields.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Product_Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Tracker_Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Id_Schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;inStock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Product type automatically inferred from the runtime validation schema.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Product_Schema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Generic Response Schema for endpoints that return the same object shape.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Product_GenericResponseSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Product_Schema&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An important detail here is that &lt;strong&gt;we do not define the &lt;code&gt;Product&lt;/code&gt; type separately&lt;/strong&gt;. It is automatically inferred from the same Zod schema through &lt;code&gt;z.infer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a result, &lt;code&gt;Product_Schema&lt;/code&gt; becomes both a runtime representation of the contract and the source of compile-time typing. If we change the structure or validation rules of &lt;code&gt;Product_Schema&lt;/code&gt;, the TypeScript &lt;code&gt;Product&lt;/code&gt; type changes with it.&lt;/p&gt;

&lt;p&gt;Runtime validation and typing remain synchronized by design.&lt;/p&gt;

&lt;p&gt;Also note &lt;code&gt;Product_GenericResponseSchema&lt;/code&gt;. In real-world APIs, several endpoints often return the same representation of an entity.&lt;/p&gt;

&lt;p&gt;Instead of describing that shape again in every endpoint-specific file, I suggest defining it at the higher business-entity level and reusing it from there.&lt;/p&gt;

&lt;p&gt;One more important clarification about &lt;code&gt;Product_Schema&lt;/code&gt;: &lt;strong&gt;a business-level schema should contain every field that may appear for this entity across any endpoint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is not an endpoint-specific contract. It is an entity-specific contract — effectively a &lt;strong&gt;single source of truth for all fields of the entity and their validation rules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Individual endpoints then build their own contracts on top of this base schema using &lt;code&gt;pick&lt;/code&gt;, &lt;code&gt;omit&lt;/code&gt;, &lt;code&gt;extend&lt;/code&gt;, or reusable subschemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Contract
&lt;/h3&gt;

&lt;p&gt;Once we have a canonical business entity, it is time to describe the contract of a specific endpoint. For this example, let us use &lt;code&gt;createProduct.schemas.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Suppose the &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, and &lt;code&gt;update&lt;/code&gt; endpoints all return &lt;code&gt;Product&lt;/code&gt; in the same representation. In that case, there is no reason to redefine the schema every time.&lt;/p&gt;

&lt;p&gt;We simply import the prepared &lt;code&gt;Product_GenericResponseSchema&lt;/code&gt; from &lt;code&gt;product.schemas.ts&lt;/code&gt; and use it as the basis for &lt;code&gt;CreateProduct_ResponsePayloadSchema&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Product_GenericResponseSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/api/schemas/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Runtime validation schema for the Create Product response payload.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CreateProduct_ResponsePayloadSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;Product_GenericResponseSchema&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CreateProduct_ResponsePayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;CreateProduct_ResponsePayloadSchema&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Request payload type for Create Product.&lt;/span&gt;
&lt;span class="c1"&gt;// A Zod schema is intentionally not created because it is not used.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CreateProduct_RequestPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is another important principle here: &lt;strong&gt;do not create a Zod schema just because you can&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If some data never goes through runtime validation and the schema is not used anywhere, it only creates additional code and another entity that must be maintained.&lt;/p&gt;

&lt;p&gt;That is why a Zod schema makes sense for &lt;code&gt;ResponsePayload&lt;/code&gt;, which we are going to validate in contract tests. But if compile-time typing is enough for &lt;code&gt;RequestPayload&lt;/code&gt;, we can simply derive the required type from the existing &lt;code&gt;Product&lt;/code&gt; type using &lt;code&gt;Pick&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This way, even endpoint-specific contracts continue to derive from the same source of truth instead of creating parallel descriptions of the same structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contract Tests
&lt;/h3&gt;

&lt;p&gt;Once the business entities and endpoint contracts have been described, the tests themselves become almost boring.&lt;/p&gt;

&lt;p&gt;All you need to do is call the API, receive the response, and validate it against the appropriate Zod schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getProductById_API&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/api/endpoints&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GetProductById_ResponsePayloadSchema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/api/schemas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API contracts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&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="s1"&gt;GET product by ID&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;data&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;getProductById_API&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12345&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;GetProductById_ResponsePayloadSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the complexity is already contained in properly designed schemas, so adding another check usually takes only a few lines of code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important Clarification: These Are Not API Unit Tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is important to understand the purpose of contract testing correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are not trying to test the API itself or verify all of its business logic.&lt;/strong&gt; This is not the place for edge cases, attempts to “break” an endpoint, or checks of how the backend behaves when given invalid data.&lt;/p&gt;

&lt;p&gt;Our task is much simpler: make a valid request, receive a successful response, and verify that it matches the contract our application relies on.&lt;/p&gt;

&lt;p&gt;So keep contract tests as simple as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call the API;&lt;/li&gt;
&lt;li&gt;make sure the request succeeds;&lt;/li&gt;
&lt;li&gt;validate the response against the appropriate schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not turn contract tests into a duplicate of the backend unit test suite — you do have one, right?&lt;/p&gt;

&lt;p&gt;There is only one thing we care about here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the API return what its consumer expects?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #1. Array Validation
&lt;/h3&gt;

&lt;p&gt;Keep in mind that Zod successfully validates an empty array even when a specific schema is defined for its elements:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;z.array(Product_Schema)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;[]&lt;/code&gt;, validation passes successfully because there is simply no element to which &lt;code&gt;Product_Schema&lt;/code&gt; can be applied.&lt;/p&gt;

&lt;p&gt;So if your test is supposed to validate not only the presence of an array but also &lt;strong&gt;the shape of its elements&lt;/strong&gt;, make sure your test data contains at least one item.&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 typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeGreaterThanOrEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, you risk getting a false positive: the test is green, but the structure of the objects inside the array has never actually been validated.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2. Catching New Fields
&lt;/h3&gt;

&lt;p&gt;In contract tests, it is important to detect not only missing or invalid fields, but also &lt;strong&gt;new unexpected fields&lt;/strong&gt; appearing in the response.&lt;/p&gt;

&lt;p&gt;That is why schemas should be validated in strict mode. Otherwise, the backend may add a new field and your test will never notice it.&lt;/p&gt;

&lt;p&gt;There are two ways to solve this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first&lt;/strong&gt; is to explicitly enable strict validation in every Zod object schema:&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;Product_Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Id_Schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The second option&lt;/strong&gt;, which I personally prefer, is to create a dedicated utility for contract tests.&lt;/p&gt;

&lt;p&gt;It recursively traverses the entire provided Zod schema and applies strict behavior to all object schemas, including objects nested inside arrays, other objects, unions, and so on.&lt;/p&gt;

&lt;p&gt;This keeps the schemas themselves universal while centralizing strict behavior exactly where it is needed — in contract tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  #3. Show the Received Value
&lt;/h3&gt;

&lt;p&gt;Another small detail that has a surprisingly large impact on debugging: &lt;strong&gt;the validation error should show the actual value that failed validation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A message such as “the field does not match the expected format” is often not enough, especially when tests operate on large responses or deeply nested structures.&lt;/p&gt;

&lt;p&gt;I recommend configuring error reporting so that, along with the field path and the reason for the failure, it also prints the value that triggered the error.&lt;/p&gt;

&lt;p&gt;Instead of something abstract like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invalid format at products[3].id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it is much more useful to get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invalid format at products[3].id
Received: "abc-123"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may seem like a small detail, but in practice it significantly reduces the time required to investigate failing tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  #4. Stable Data
&lt;/h3&gt;

&lt;p&gt;Sometimes an API contains endpoints that return &lt;strong&gt;stable data&lt;/strong&gt; — values that are not expected to change regularly.&lt;/p&gt;

&lt;p&gt;A typical example is a list of statuses for a business entity.&lt;/p&gt;

&lt;p&gt;In this case, it can be useful not only to validate the general response shape but also to &lt;strong&gt;explicitly lock down the expected set of values using literals&lt;/strong&gt;.&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 typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProductStatus_Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;In Progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this may look like unnecessary overhead. In practice, however, it can be extremely useful — especially when frontend behavior depends directly on specific statuses.&lt;/p&gt;

&lt;p&gt;For example, different statuses may display different UI, enable different actions, or trigger different business logic.&lt;/p&gt;

&lt;p&gt;In such a case, introducing a new status or renaming an existing one is no longer just a data change. It is &lt;strong&gt;a contract change that can potentially affect the frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you cannot be completely sure that the backend team will always notify you about such changes in time, contract tests can serve as an additional safety net.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonuses
&lt;/h2&gt;

&lt;p&gt;At the beginning of the article, I mentioned that a software developer can get much more from this framework than contract tests alone.&lt;/p&gt;

&lt;p&gt;Since the Zod schemas have already become our &lt;strong&gt;single source of truth&lt;/strong&gt;, we can reuse them directly in application code.&lt;/p&gt;

&lt;p&gt;Here are a few practical examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1. API Typing
&lt;/h3&gt;

&lt;p&gt;Since TypeScript types are automatically inferred from our Zod schemas, the same types can be used directly in the API layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductByIdApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GetProductById_ResponsePayload&lt;/span&gt;&lt;span class="o"&gt;&amp;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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/products/&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means API typing and API validation are based on the same source of truth.&lt;/p&gt;

&lt;p&gt;Change the schema, and the type used by the application code changes with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2. Runtime Validation of Local Storage Data
&lt;/h3&gt;

&lt;p&gt;Suppose a user is creating a product and we store a draft of the form in &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After the page reloads, we want to restore it — but before putting the data back into the form, we want to make sure it still conforms to our contract.&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;rawDraft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;productDraft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawDraft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;parsedDraft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawDraft&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ProductDraft_Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedDraft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Invalid JSON — ignore the stored draft&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;This gives the data from &lt;code&gt;localStorage&lt;/code&gt; two validation layers: first, we ensure it is valid JSON; then Zod checks its structure and values before it is allowed back into the form.&lt;/p&gt;

&lt;h3&gt;
  
  
  #3. Form Validation
&lt;/h3&gt;

&lt;p&gt;The same Zod schemas can be integrated directly with popular form libraries.&lt;/p&gt;

&lt;p&gt;For example, React Hook Form provides a Zod resolver:&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;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;zodResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Product_Schema&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;As a result, rules such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do not need to be described again in the form.&lt;/p&gt;

&lt;p&gt;The schema that defines the API contract and TypeScript type also defines the form validation rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  #4. Using Schema Constraints in the UI
&lt;/h3&gt;

&lt;p&gt;A Zod schema contains not only information about the field type, but also its rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the UI displays a character counter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127 / 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;there is no reason to hardcode &lt;code&gt;500&lt;/code&gt; separately inside the React component.&lt;/p&gt;

&lt;p&gt;We can get it directly from the schema:&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;maxLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Product_Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxLength&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use that value directly in the UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CharacterCounter&lt;/span&gt;
  &lt;span class="na"&gt;current&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;maxLength&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means &lt;code&gt;500&lt;/code&gt; exists in exactly one place — &lt;code&gt;Product_Schema&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Form validation, runtime validation, and the UI all use the same rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  #5. Third-Party Service Integration
&lt;/h3&gt;

&lt;p&gt;But why are we talking only about the classic frontend ↔ backend integration?&lt;/p&gt;

&lt;p&gt;Let us look at this framework from another angle.&lt;/p&gt;

&lt;p&gt;Suppose your application integrates with a &lt;strong&gt;third-party API&lt;/strong&gt;. Your code directly depends on the responses returned by an external service, but you have neither a direct communication channel with its team nor any guarantee that you will receive timely notifications about API changes.&lt;/p&gt;

&lt;p&gt;In this scenario, contract testing can become even more valuable.&lt;/p&gt;

&lt;p&gt;Your tests effectively turn into an early-warning system: if the external service changes the response structure, removes a field, adds a new one, or changes its format, you can find out automatically — before that change turns into a problem for your users.&lt;/p&gt;

&lt;p&gt;In other words, the same framework that helps reduce communication and integration issues in an internal frontend ↔ backend setup can, in the case of a third-party API, partially &lt;strong&gt;compensate for the complete absence of that communication&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  #6. AI Compatibility
&lt;/h3&gt;

&lt;p&gt;I put a lot of effort into &lt;strong&gt;standardization, structural consistency, and semantics&lt;/strong&gt; while designing this framework.&lt;/p&gt;

&lt;p&gt;And this is where we get to reap the benefits.&lt;/p&gt;

&lt;p&gt;The more predictable the repository architecture is, the easier it is for AI to understand its patterns and extend them correctly.&lt;/p&gt;

&lt;p&gt;If the framework is implemented consistently, AI no longer has to decide every time where to create files, how to name schemas, how to group endpoints, or how to structure contract tests.&lt;/p&gt;

&lt;p&gt;The repository already contains a pattern that the agent only needs to recognize and reproduce.&lt;/p&gt;

&lt;p&gt;In practice, this means that when a new API module appears, I can simply give the AI a link to the Swagger specification.&lt;/p&gt;

&lt;p&gt;From there, it can parse the API specification, identify business entities and endpoints, and generate the module according to the existing structure: schemas, types, abstractions, and contract tests.&lt;/p&gt;

&lt;p&gt;And yes, this has been tested in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementing a new API module with around 10 endpoints, including testing, takes about 16 minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So standardization here improves more than developer experience.&lt;/p&gt;

&lt;p&gt;It makes the repository genuinely &lt;strong&gt;AI-native&lt;/strong&gt;: instead of repeatedly explaining to an agent &lt;em&gt;how&lt;/em&gt; another module should be implemented, we give it an architecture where the correct implementation pattern is already encoded in the structure and semantics of the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A few numbers.&lt;/p&gt;

&lt;p&gt;While working with a large API containing more than 100 endpoints, this framework allowed me to reduce structural integration bugs to almost zero, cut the reaction time to API changes to within a single day, and catch around 100 integration issues in just three months — without requiring additional communication with the backend team.&lt;/p&gt;

&lt;p&gt;I consider that a fairly strong result.&lt;/p&gt;

&lt;p&gt;At this point, the framework solves one of the classic problems of software development quite well: the constant need to stay synchronized with API changes and detect situations where the actual contract starts diverging from what the application expects.&lt;/p&gt;

&lt;p&gt;Overall, I am happy with the result.&lt;/p&gt;

&lt;p&gt;The framework solves all the core problems I originally designed it for, requires relatively little additional code, and provides significantly more value than API validation alone.&lt;/p&gt;

&lt;p&gt;I would be very interested to hear your thoughts.&lt;/p&gt;

&lt;p&gt;Do you use anything similar in your projects?&lt;/p&gt;

&lt;p&gt;Where do you think this approach works well — and where do you think it starts to break down?&lt;/p&gt;

</description>
      <category>api</category>
      <category>testing</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Tested Two AI Context Architectures: Context Discovery vs Prompt Engine. Here’s What I Learned.</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:51:23 +0000</pubDate>
      <link>https://dev.to/kotyk/i-tested-two-ai-context-architectures-context-discovery-vs-prompt-engine-heres-what-i-learned-2286</link>
      <guid>https://dev.to/kotyk/i-tested-two-ai-context-architectures-context-discovery-vs-prompt-engine-heres-what-i-learned-2286</guid>
      <description>&lt;p&gt;For the last few months, I have been building my own AI framework for software development. It contains instructions for different engineering activities: implementing features, refactoring, writing tests, debugging, working with APIs, reviewing code, and many smaller tasks. As the framework grew beyond 100,000 characters of instructions, one problem became increasingly important: how do I give an AI agent exactly the instructions it needs without loading the entire framework into its context?&lt;/p&gt;

&lt;p&gt;While working on this problem, I ended up testing two different architectures: &lt;em&gt;Agent-Driven Context Discovery&lt;/em&gt; and a &lt;em&gt;Prompt Engine with Context Compilation&lt;/em&gt;. Both allow you to keep instructions modular and load only what is relevant to the current task. The major difference is who is responsible for assembling that context.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Agent-Driven Context Discovery&lt;/em&gt; leaves this responsibility to the agent. You give it an entry point, usually a base instruction file, and that file references other instructions. The agent reads those files, follows their references, and gradually discovers the context required for the task.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt Engine with Context Compilation&lt;/em&gt; moves most of this work into deterministic code. The agent still selects the type of activity it is about to perform, but once that decision is made, the Prompt Engine deterministically resolves the required instructions and compiles them into a ready-to-use context. The agent no longer has to manually discover and retrieve every instruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared Foundation: Intent Router / Playbook
&lt;/h2&gt;

&lt;p&gt;Both architectures still need a mechanism that connects a task with the appropriate instructions. I call mine &lt;strong&gt;a playbook&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The playbook is essentially an intent router. It describes the types of activities the framework supports and maps those activities to the instruction sets they require. Implementing functionality, refactoring code, writing tests, debugging, and reviewing code are examples of activities that can have different instruction dependencies.&lt;/p&gt;

&lt;p&gt;With &lt;em&gt;Context Discovery&lt;/em&gt;, this routing can live inside the instruction graph itself. The base instruction tells the agent where to go, and the agent follows the appropriate path.&lt;/p&gt;

&lt;p&gt;With my &lt;em&gt;Prompt Engine&lt;/em&gt;, I use an MCP tool called &lt;code&gt;getInstructions&lt;/code&gt;. It accepts typed activities and uses them to programmatically determine which instructions should be compiled. The agent therefore makes one high-level decision — &lt;em&gt;what am I about to do?&lt;/em&gt; — while deterministic code handles the low-level question — &lt;em&gt;which exact instructions does that activity require?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 1: Agent-Driven Context Discovery
&lt;/h2&gt;

&lt;p&gt;This was the first architecture I implemented. I split my framework into many small instruction files and created references between them. The agent received a base instruction as its entry point and was expected to follow those references whenever additional instructions were required.&lt;/p&gt;

&lt;p&gt;Conceptually, it looked something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Task → Base Instructions → Agent → Referenced Instructions → More Instructions → Work&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I liked this approach initially because it was extremely easy to build. The instruction system remained modular, individual files could be reused, and adding a new rule usually meant adding or updating a reference. There was no separate infrastructure responsible for assembling prompts because the agent itself effectively acted as the resolver.&lt;/p&gt;

&lt;p&gt;After using this architecture for some time, however, I started noticing several problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1: Reasoning Overhead
&lt;/h3&gt;

&lt;p&gt;Every time the agent encounters a reference, it has to understand why that instruction exists, decide whether it should follow it, retrieve the file, process it, and potentially repeat the process. These are small decisions, but they are still decisions made by the model instead of deterministic operations performed by software.&lt;/p&gt;

&lt;p&gt;I increasingly disliked spending the agent's reasoning capacity on this kind of plumbing. I want the model thinking about architecture, requirements, edge cases, and implementation decisions. Resolving an instruction dependency does not require intelligence if I can already express that dependency in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2: Reliability
&lt;/h3&gt;

&lt;p&gt;I repeatedly saw agents skip files even when another instruction explicitly told them to read those files. It did not happen every time, but it happened often enough that I could not consider instruction delivery deterministic.&lt;/p&gt;

&lt;p&gt;This creates an unpleasant failure mode. Your agent may produce perfectly reasonable code while silently missing one of the rules it was supposed to follow. The problem is not that the model misunderstood an instruction — it never loaded that instruction in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 3: Tool Usage
&lt;/h3&gt;

&lt;p&gt;Reading each instruction file requires a tool call. With more than 100,000 characters distributed across many files, the agent could make a surprising number of calls just to prepare itself for the actual task.&lt;/p&gt;

&lt;p&gt;I repeatedly hit Copilot’s maximum tool-call limit while the agent was navigating instruction files. When that happened, Copilot stopped before the actual task was completed. That was a strong signal that I needed a different architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 4: Inefficient Context Usage
&lt;/h3&gt;

&lt;p&gt;Another problem is that routing instructions remain in the agent's context long after they have served their purpose. Instructions such as "read this file," "for this activity, also read that file," or "if this condition applies, load these additional instructions" are useful during context discovery, but provide little value once the agent starts working on the actual task. From that point on, they simply consume space in the context window.&lt;/p&gt;

&lt;p&gt;This problem also has the potential to grow over time. If the agent occasionally fails to load the right files for certain activities, the natural response is to make the routing instructions more explicit: add explanations, introduce more specific terminology, describe additional conditions, or repeat important references. That may improve routing reliability, but it also increases the amount of temporary information that remains in the context throughout the task.&lt;/p&gt;

&lt;p&gt;In other words, the more effort you put into making agent-driven context discovery reliable, the more context you may end up spending on instructions that become useless immediately after discovery is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 2: Prompt Engine with Context Compilation
&lt;/h2&gt;

&lt;p&gt;My second implementation moved instruction resolution out of the agent and into code.&lt;/p&gt;

&lt;p&gt;The framework still contains dozens of small, reusable instruction files. The difference is that the agent no longer needs to navigate them one by one. A script resolves the dependencies, collects the required files, and returns the complete instruction set in a single operation.&lt;/p&gt;

&lt;p&gt;The architecture now looks closer to this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Task → Activity → Prompt Engine → Compiled Context → Agent → Work&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The change may sound small, but the practical improvement was substantial. Once the agent selects an activity, the rest of the process is deterministic. If activity X requires instructions A, B, C, and D, the Prompt Engine delivers all four. There is no intermediate step where the agent can forget to open C or decide that D is unnecessary.&lt;/p&gt;

&lt;p&gt;Context delivery also became much faster. Instead of making a sequence of tool calls, reading files one by one, and reasoning about what to retrieve next, the agent makes a single request. The Prompt Engine resolves the instruction graph programmatically and returns the compiled context in a single operation. This removes both the latency of repeated tool calls and the reasoning overhead involved in navigating the instruction structure.&lt;/p&gt;

&lt;p&gt;Another important improvement was eliminating a practical limitation I repeatedly hit with Copilot: the maximum number of tool calls available to the agent. With Context Discovery, the agent regularly exhausted this limit while navigating and reading instruction files, which caused Copilot to stop before the task was completed. After moving instruction resolution into the Prompt Engine, instruction delivery requires only one tool call, so this failure mode effectively disappeared from my workflow.&lt;/p&gt;

&lt;p&gt;In practice, I got three immediate benefits: the required instructions started reaching the context reliably, context assembly became much faster, and instruction discovery stopped consuming the agent's limited tool calls. Combined, these changes produced a very noticeable improvement in the overall speed and reliability of my workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1: Your Prompt Engine Becomes a Mini-Product
&lt;/h3&gt;

&lt;p&gt;The first downside is additional infrastructure. In my case, the Prompt Engine requires a custom MCP server that exposes the tools the agent uses to request its instructions. Once you introduce this layer, you effectively have another small software product living inside your repository.&lt;/p&gt;

&lt;p&gt;Like any other software, it needs maintenance. You need to keep the implementation clean, handle edge cases, and ideally cover its critical behavior with automated tests. As the instruction system evolves, the Prompt Engine has to evolve with it.&lt;/p&gt;

&lt;p&gt;This is simply the price of moving from a lightweight instruction structure to a more sophisticated architecture. You gain more deterministic and reliable context delivery, but you also introduce another component that you are responsible for maintaining.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2: You Can Accidentally Create Two Sources of Truth
&lt;/h3&gt;

&lt;p&gt;Another challenge is instruction representation. The format that is convenient for programmatic processing is not necessarily the format that is convenient for a human. For example, the Prompt Engine may work better with structured JSON, while I would much rather read, write, review, and maintain the same instructions as Markdown.&lt;/p&gt;

&lt;p&gt;The obvious solution is to keep both representations, but that immediately creates another problem: they can drift apart. If JSON says one thing and Markdown says another, you effectively have two sources of truth and can no longer be certain which representation describes the actual behavior of the system.&lt;/p&gt;

&lt;p&gt;A better architecture needs one canonical source and a deterministic way to generate the other representation from it. Ideally, the two formats should also remain structurally similar enough that you can debug the agent-facing JSON while reading the human-friendly Markdown. Otherwise, the convenience of having two representations can quickly turn into another maintenance problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 3: Compiled Instructions Can Pollute the Context
&lt;/h3&gt;

&lt;p&gt;A Prompt Engine can also make context usage worse if the routing rules are not strict enough. Imagine that the current session already contains the instructions for API engineering, but the agent does not clearly understand that those instructions should not be requested again. It may call the instruction tool a second time and inject another full copy of the same compiled context into the conversation.&lt;/p&gt;

&lt;p&gt;If your instruction sets are large, this can become surprisingly expensive. Instead of optimizing context usage, you may end up filling the context window with repeated copies of the same material. The more often the agent re-requests instructions, the faster this duplication compounds.&lt;/p&gt;

&lt;p&gt;My recommendation is to add a hard guardrail at the infrastructure level. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Track which instruction sets have already been delivered during the current session, and if the agent requests the same one again, do not return the full instruction set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Return a short message saying that the instruction is already present in the current context and should be reused.&lt;/p&gt;

&lt;p&gt;I also &lt;strong&gt;make this failure mode explicit&lt;/strong&gt;. If the agent believes the required instruction is actually missing despite the guardrail, it should treat that as a critical inconsistency, stop, and report the problem to the user rather than silently requesting or reconstructing the same context again.&lt;/p&gt;

&lt;p&gt;This is one of those cases where a small deterministic safeguard can prevent a large amount of unnecessary context duplication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Note: There Is Still One Non-Deterministic Step
&lt;/h3&gt;

&lt;p&gt;This architecture does not make everything deterministic. The agent still needs to select the correct activity when it calls &lt;code&gt;getInstructions&lt;/code&gt;, and that selection is an LLM decision.&lt;/p&gt;

&lt;p&gt;For this reason, I think the tool interface should be strongly typed and the playbook should be designed carefully. Activity names and descriptions need to be clear enough that the model can reliably map real tasks to them. Otherwise, you simply move the failure point from instruction discovery to activity classification.&lt;/p&gt;

&lt;p&gt;I would also recommend watching this routing closely when introducing such a system. Check which activities the agent selects for real tasks and adjust the playbook when you find ambiguous cases. In my framework, my subjective estimate is that incorrect activity selection happens in less than 1% of cases, possibly even below 0.5%, so this has not been a significant practical problem for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;After working with both architectures, &lt;strong&gt;Prompt Engine with Context Compilation wins&lt;/strong&gt; for me by a large margin.&lt;/p&gt;

&lt;p&gt;The difference is not really about prompts or files. It is about deciding which responsibilities belong to an LLM and which belong to traditional software.&lt;/p&gt;

&lt;p&gt;An LLM is excellent at understanding intent, interpreting ambiguous requirements, reasoning about code, and making decisions where the answer cannot be reduced to a simple algorithm. A script is excellent at following predefined dependencies, assembling files, validating inputs, and producing the same result every time.&lt;/p&gt;

&lt;p&gt;Context Discovery asks the LLM to do some of both. A Prompt Engine lets me draw the boundary more deliberately.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;The Core Takeaway:&lt;/strong&gt; Whenever something can be reliably handled by deterministic software, move it out of the agent's reasoning loop.&lt;br&gt;

&lt;/div&gt;


&lt;p&gt;That experiment eventually contributed to a broader principle I now use in my &lt;a href="https://dev.to/kotyk/stop-asking-ai-to-do-a-linters-job-1cp0"&gt;Semi-Automatic AI-Native Flow with a Human in the Loop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For me, this is becoming one of the more interesting questions in AI-native development. We spend a lot of time asking how much more responsibility we can give to AI agents. &lt;/p&gt;

&lt;p&gt;Maybe we should spend just as much time asking how much responsibility we can take away from them.&lt;/p&gt;




&lt;p&gt;What edge cases did I miss here? How are you managing large instruction sets or context windows in your own AI frameworks? Let me know in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Microsoft GH-300: GitHub Copilot | Tips &amp; Tricks</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Mon, 10 Aug 2026 19:10:40 +0000</pubDate>
      <link>https://dev.to/kotyk/microsoft-gh-300-github-copilot-tips-tricks-430o</link>
      <guid>https://dev.to/kotyk/microsoft-gh-300-github-copilot-tips-tricks-430o</guid>
      <description>&lt;p&gt;Today I passed the GitHub Copilot GH-300 exam and decided to write down my impressions right away while they are still fresh. First of all, this article is not so much a “how to pass” guide as a place where people who are currently preparing for the exam can ask questions to someone who literally took it today. If anything from my experience helps you prepare better, or at least understand what to expect, then this article has already served its purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap between preparation materials and the actual exam questions
&lt;/h2&gt;

&lt;p&gt;The first thing that genuinely surprised me was how different the information in the recommended preparation materials can be from what you actually see on the exam. A few times, my completely honest reaction was: “Where did this even come from?” Subjectively, I managed to answer some of those questions not because I had memorized the materials well, but because by the time I took the exam I had already been using Copilot quite intensively in real-world development. Sometimes practical experience helped, sometimes it was a general understanding of engineering processes, and sometimes it was simply common sense.&lt;/p&gt;

&lt;p&gt;So I would not recommend treating the official materials as a complete map of the exam. They are useful and they provide the basic structure of the topics, but they are not enough to make you confident about every question. If you already use Copilot at work, that is a serious advantage, because part of the exam tests not only whether you know the wording from the documentation, but also whether you understand how the product behaves in common scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot = Microsoft
&lt;/h2&gt;

&lt;p&gt;Another thing worth keeping in mind: Copilot is GitHub, GitHub is Microsoft, and Microsoft also means Windows and PowerShell. If, like many developers, you have spent years working on macOS and barely touching the Windows ecosystem, some questions may come as an unpleasant surprise. For example, you may need at least a basic understanding of how something is &lt;strong&gt;installed&lt;/strong&gt; or configured through PowerShell. I barely looked at things like that during my preparation because I relied too heavily on the recommended resources and hardly read any additional documentation. If I were preparing again, I would definitely close that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do questions from the preparation materials appear on the exam?
&lt;/h2&gt;

&lt;p&gt;A separate story is my attempt to “outsmart the system.” During preparation, I collected all the questions I came across in the learning modules and the practice exam, put them into Anki, and simply memorized them. I thought it would be a decent safety net: even if the questions were not repeated word for word, at least I would have the relevant facts firmly memorized. In practice, my subjective impression is that I did not see a single question repeated exactly on the real exam, and only one or two vaguely resembled something I had learned this way. So I would not recommend memorizing the correct answers; it is much more useful to use those questions as a way to check whether you actually understand the topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question formats
&lt;/h2&gt;

&lt;p&gt;Another mistake in my expectations about the GH-300 was assuming that the exam would mostly follow the classic format: one question, four answers, one correct choice. In reality, there are more formats. Some questions require you to choose two correct answers out of four or three out of five, some ask you to match items between two columns, and some require you to arrange several steps in the correct order. Personally, I found the last type to be one of the trickiest because it is no longer enough to “roughly remember the correct answer” — you need to understand the process itself.&lt;/p&gt;

&lt;p&gt;Statistically, you can feel the difference too. In a standard multiple-choice question with four options, you at least have a 25% chance of guessing correctly if you know absolutely nothing. But when you need to choose several items from a set and then put them in the correct order, the number of possible combinations grows very quickly. That is why I would pay particular attention to how GitHub Copilot handles basic workflows: authentication, starting a new session, resuming a previous one, working with context, and common interaction scenarios. It is important not only to know that a feature exists, but to understand what happens step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  A final gift :)
&lt;/h2&gt;

&lt;p&gt;And finally, here is a small semi-joking life hack that I came up with for myself while preparing. Use this entirely at your own risk.&lt;/p&gt;

&lt;p&gt;If you are looking at a question where you have absolutely no idea which answer is correct and you are going to guess anyway, take a closer look at the longest option. In the practice materials, I repeatedly noticed a pattern: the correct answer is often written in a complete, careful way with all the necessary qualifications, while the incorrect options sometimes look as if, after writing the correct one, the author got a little tired of coming up with alternatives.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don’t know which answer to choose, choose the longest one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do not know how consistently this works on the real exam, and I definitely would not recommend using it as a substitute for knowledge. But if you are already in a situation where you have to guess anyway, at least you will have some kind of heuristic. I saw this pattern often enough in the practice questions to notice it.&lt;/p&gt;

&lt;p&gt;If I had to start preparing again today, I would spend less time memorizing ready-made answers and more time on three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;actually working with Copilot&lt;/li&gt;
&lt;li&gt;reading additional documentation&lt;/li&gt;
&lt;li&gt;understanding the product workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The learning path and the demo exam are useful, but I would treat them as a map of the topics rather than a simulation of the actual exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  So,
&lt;/h2&gt;

&lt;p&gt;if you are preparing for the GH-300 right now, leave your questions in the comments.&lt;/p&gt;

&lt;p&gt;While my impressions are still as fresh as possible, I will try to answer everything I can.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>microsoft</category>
      <category>certification</category>
    </item>
    <item>
      <title>Chasing Tokens: I Renamed My Entire Repository — Here’s What Happened</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Mon, 10 Aug 2026 15:11:14 +0000</pubDate>
      <link>https://dev.to/kotyk/chasing-tokens-i-renamed-my-entire-repository-heres-what-happened-5gg6</link>
      <guid>https://dev.to/kotyk/chasing-tokens-i-renamed-my-entire-repository-heres-what-happened-5gg6</guid>
      <description>&lt;p&gt;After optimizing my &lt;a href="https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0"&gt;CI logs for AI agents&lt;/a&gt;, I found myself looking for tokens everywhere.&lt;/p&gt;

&lt;p&gt;Then I had another idea.&lt;/p&gt;

&lt;p&gt;Many of my files and directories used &lt;code&gt;kebab-case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My assumption was simple: if &lt;code&gt;-&lt;/code&gt; increases token count, then switching everything to &lt;code&gt;camelCase&lt;/code&gt; might reduce the amount of context an AI agent has to process.&lt;/p&gt;

&lt;p&gt;So instead of guessing, I measured it.&lt;/p&gt;

&lt;p&gt;I wrote a script to tokenize my entire repository before and after renaming every &lt;code&gt;kebab-case&lt;/code&gt; path to &lt;code&gt;camelCase&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository before:&lt;/strong&gt; 376,553 tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository after:&lt;/strong&gt; 376,204 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total reduction:&lt;/strong&gt; &lt;strong&gt;349 tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Honestly? That was much smaller than I expected.&lt;/p&gt;

&lt;p&gt;At first glance, this looks like a classic micro-optimization. But I don't think the story ends there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why File Paths Matter More Than You Think
&lt;/h2&gt;

&lt;p&gt;Unlike source code, file and directory names have a very different lifecycle during an AI coding session. &lt;/p&gt;

&lt;p&gt;An agent doesn't read them just once. They appear repeatedly in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;imports and exports&lt;/li&gt;
&lt;li&gt;directory listings&lt;/li&gt;
&lt;li&gt;search results&lt;/li&gt;
&lt;li&gt;git diffs&lt;/li&gt;
&lt;li&gt;stack traces&lt;/li&gt;
&lt;li&gt;test output&lt;/li&gt;
&lt;li&gt;formatter and linter logs&lt;/li&gt;
&lt;li&gt;tool responses from the IDE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, file paths are part of the agent's working context over and over again.&lt;/p&gt;

&lt;p&gt;So while the repository itself became only &lt;strong&gt;349 tokens&lt;/strong&gt; smaller, the cumulative savings across a long coding session could be noticeably larger because those same paths are processed repeatedly.&lt;/p&gt;

&lt;p&gt;I haven't measured that part yet, so I won't claim any specific numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This experiment reminded me of something more important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Measure first. Optimize second.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some optimizations that sound brilliant turn out to be negligible. Others—like reducing unnecessary tool output—have a much larger impact than you'd expect.&lt;/p&gt;

&lt;p&gt;AI-assisted development is creating a whole new class of performance optimizations. The only way to know which ones matter is to measure them.&lt;/p&gt;




&lt;p&gt;What micro-optimizations have you tested for your AI coding agents? Did they actually move the needle, or did the data surprise you? Let me know in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>💥 Easy way to save your AI coding agent a surprising amount of context.</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Mon, 10 Aug 2026 15:07:28 +0000</pubDate>
      <link>https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0</link>
      <guid>https://dev.to/kotyk/easy-way-to-save-your-ai-coding-agent-a-surprising-amount-of-context-2h0</guid>
      <description>&lt;p&gt;One thing clicked for me only after working with AI agents for a while.&lt;/p&gt;

&lt;p&gt;Like many teams, I have a set of mandatory checks that must pass before code is committed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;ESLint&lt;/li&gt;
&lt;li&gt;Type checking&lt;/li&gt;
&lt;li&gt;Unit tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also have a rule for my coding agent: whenever it makes executable code changes, it automatically runs all of these checks before moving on.&lt;/p&gt;

&lt;p&gt;Sounds obvious, right?&lt;/p&gt;

&lt;p&gt;The problem was that all of these tools were configured for humans, not for AI.&lt;br&gt;
For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prettier printed every file it checked - even when nothing changed.&lt;/li&gt;
&lt;li&gt;The type checker produced verbose success output.&lt;/li&gt;
&lt;li&gt;The test runner listed every executed test file.&lt;/li&gt;
&lt;li&gt;ESLint printed a lot of informational output even when everything passed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it hit me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every line of that output becomes part of the agent's working context.&lt;br&gt;
Those hundreds of log lines aren't free. They consume context, increase token usage, and make it harder for the model to focus on information that actually matters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Fixing the Noise
&lt;/h2&gt;

&lt;p&gt;So I changed the defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prettier&lt;/strong&gt; runs silently unless there's a formatting issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt; only reports warnings and errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests&lt;/strong&gt; use a dot reporter and print detailed output only for failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Successful checks&lt;/strong&gt; produce only a short summary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result?&lt;/p&gt;

&lt;p&gt;Exactly the same safety guarantees, but with dramatically less noise.&lt;/p&gt;

&lt;p&gt;For humans, verbose logs are mostly harmless. For AI agents, they're context pollution.&lt;/p&gt;

&lt;p&gt;And context isn't free. Every unnecessary token is one that could have been spent reasoning about your code instead.&lt;/p&gt;

&lt;p&gt;Sometimes the best optimization isn't a faster model—it's simply giving the model less irrelevant information to read.&lt;/p&gt;


&lt;h2&gt;
  
  
  Appendix: For those who prefer numbers over opinions
&lt;/h2&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
I rolled the repository back and measured the raw output with a tokenizer:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prettier output:&lt;/strong&gt; ~15,000 tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test runner output:&lt;/strong&gt; ~35,000 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After enabling silent output and compact reporting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prettier:&lt;/strong&gt; ~500 tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test runner:&lt;/strong&gt; ~1,500 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;That is roughly 48,000 tokens removed from a single validation cycle&lt;/strong&gt;—without removing a single check or weakening the pipeline.&lt;br&gt;

&lt;/p&gt;
&lt;/div&gt;


&lt;p&gt;Same guarantees. Far less context pollution.&lt;/p&gt;




&lt;p&gt;What configuration tweaks have you made to keep your AI coding agents focused? Let me know in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>softwareengineering</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AI Melting Your Brain? Here’s the Fix.</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Mon, 10 Aug 2026 15:03:18 +0000</pubDate>
      <link>https://dev.to/kotyk/ai-melting-your-brain-heres-the-fix-5cdd</link>
      <guid>https://dev.to/kotyk/ai-melting-your-brain-heres-the-fix-5cdd</guid>
      <description>&lt;p&gt;A few weeks ago, I came across a post from a developer who had spent six months working with five or six Claude Code terminals open at once. His description of the experience was funny, but also uncomfortably familiar: most of the time, he was simply waiting for agents to finish and pressing Enter.&lt;/p&gt;

&lt;p&gt;His conclusion was blunt: “Claude Code is melting my brain.”&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%2Ffyvq0tvblvum64b3l4ue.jpeg" 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%2Ffyvq0tvblvum64b3l4ue.jpeg" alt="A screenshot of a terminal interface or discussion regarding AI coding agents" width="800" height="925"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been seeing variations of this concern more and more often. Developers who use AI heavily start wondering whether they are becoming less sharp because the machine is doing too much of the actual coding. At the same time, another term has started appearing in discussions around AI-assisted development: comprehension debt.&lt;/p&gt;

&lt;p&gt;I think that term captures the problem remarkably well.&lt;/p&gt;

&lt;p&gt;Technical debt appears when a codebase accumulates decisions that will have to be dealt with later. Comprehension debt appears when the codebase evolves faster than the people responsible for it can maintain a mental model of what is happening inside it. The software keeps moving forward, but your understanding of it falls further and further behind.&lt;/p&gt;

&lt;p&gt;Eventually, you can end up in a strange position: you are responsible for a system that you technically own, but no longer fully understand.&lt;/p&gt;

&lt;p&gt;These look like two different problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI making developers “dumber”&lt;/li&gt;
&lt;li&gt;AI creating comprehension debt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... but I suspect they are mostly the same problem viewed from two angles. And, more importantly, I think they have the same solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem is not AI. The problem is you going full auto.
&lt;/h2&gt;

&lt;p&gt;There is a peculiar productivity competition happening in software engineering right now. Every week I see another impressive number: hundreds of thousands of lines generated, thousands of commits, dozens of agents running in parallel, or thousands of pull requests produced by AI-assisted development pipelines.&lt;/p&gt;

&lt;p&gt;Uber, for example, has publicly discussed an internal AI coding system producing roughly 1,800 pull requests per week (1 PR each 80 seconds).&lt;/p&gt;

&lt;p&gt;That is certainly an impressive throughput number. But whenever I see metrics like this, I find myself asking a slightly uncomfortable question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What exactly are we optimizing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A pull request is a unit of software delivery. It is not a unit of product value.&lt;/p&gt;

&lt;p&gt;A software product is, at some level, encoded business logic. Its purpose is to solve problems: make something easier for a user, automate a process, reduce costs, create revenue, satisfy a regulatory requirement, improve reliability, or enable some new capability.&lt;/p&gt;

&lt;p&gt;So the interesting question is not how quickly an organization can manufacture changes to a repository. The interesting question is how quickly it can discover, validate and deliver meaningful changes to the product.&lt;/p&gt;

&lt;p&gt;Imagine someone tells you that their AI workflow can generate a thousand PRs in a relatively short period of time. Fine. Now ask them a different question: can you name the next important feature your product needs—right now?&lt;/p&gt;

&lt;p&gt;And I don’t mean something sitting in the backlog already. I mean a genuinely new requirement. Something that has been validated rather than hallucinated by AI. Something supported by customer feedback, user behavior, business analysis, stakeholder needs, market research or other evidence that suggests building it will actually create value.&lt;/p&gt;

&lt;p&gt;That is much harder. And definitely not possible at the rate of 1 feature per 80 seconds.&lt;/p&gt;

&lt;p&gt;The reason is simple: once implementation becomes extremely fast, implementation stops being the primary bottleneck. Product discovery does not suddenly become a hundred times faster because your coding agent did. Neither do requirements analysis, UX research, architectural reasoning, stakeholder alignment or understanding what customers actually need.&lt;/p&gt;

&lt;p&gt;At some point, enough is enough.&lt;/p&gt;

&lt;p&gt;There is a finite amount of meaningful change that a product can discover, validate, absorb and maintain. Once AI gives us effectively abundant implementation capacity, maximizing the amount of code produced becomes a strange goal in itself.&lt;/p&gt;

&lt;p&gt;And this is where I think full-auto development becomes dangerous. Not necessarily because AI writes bad code, but because execution can begin moving faster than understanding.&lt;/p&gt;

&lt;p&gt;That is where comprehension debt starts accumulating.&lt;/p&gt;

&lt;h2&gt;
  
  
  My approach: Semi-Automatic AI-Native Development
&lt;/h2&gt;

&lt;p&gt;The workflow I use has a deliberately cumbersome name: Semi-Automatic AI-Native Development with Human in the Loop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/kotyk/stop-asking-ai-to-do-a-linters-job-1cp0"&gt;I described the broader workflow in another article&lt;/a&gt;, so I won’t repeat the whole thing here. The important part for this discussion is the human in the loop.&lt;/p&gt;

&lt;p&gt;I almost never use AI in full-auto mode for meaningful development work. I use it aggressively, but I try to be very deliberate about which part of engineering I delegate.&lt;/p&gt;

&lt;p&gt;For me, AI is an extremely fast electronic typewriter, an implementation engine, a research assistant, a second opinion and a tool for validating assumptions. What I do not want it to become is a replacement for engineering judgment.&lt;/p&gt;

&lt;p&gt;Before I ask an agent to implement something, I try to define the system it is going to operate inside as precisely as the task justifies. Depending on the feature, that means thinking through types, validation rules, business requirements, functional behavior, file structure, data flow, relationships between modules, API contracts, architectural boundaries and test expectations.&lt;/p&gt;

&lt;p&gt;And one thing I care about particularly strongly is semantics.&lt;/p&gt;

&lt;p&gt;What does this entity actually represent? Who owns this state? Where does this transformation belong? What responsibility does this module have? What does this abstraction mean in terms of the domain? Which concepts are genuinely different, and which are merely different names for the same thing?&lt;/p&gt;

&lt;p&gt;Those questions are not formatting preferences. They are architecture.&lt;/p&gt;

&lt;p&gt;Once those constraints are clear, AI can do what it is extraordinarily good at: execute quickly inside them.&lt;/p&gt;

&lt;p&gt;Recently I came across a post from Robert "Uncle Bob" Martin that described a surprisingly similar philosophy.&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%2F70kj4ztyx9il0vkchvqd.jpeg" 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%2F70kj4ztyx9il0vkchvqd.jpeg" alt="A reference graphic illustrating architectural constraints in AI workflows" width="800" height="974"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;His approach is more extreme than mine. He says he does not read the code generated by his agents; instead, he surrounds those agents with extensive constraints: unit tests, Gherkin tests, QA procedures, quality metrics, mutation testing, coverage and many other forms of automated verification.&lt;/p&gt;

&lt;p&gt;I do still read AI-generated code. But the underlying idea resonates with me: the engineer’s job increasingly becomes designing the environment in which automated implementation is allowed to happen.&lt;/p&gt;

&lt;p&gt;You create the constraints. You define the architecture. You specify the semantics. Then you let the machine move quickly inside that system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I still review the code
&lt;/h2&gt;

&lt;p&gt;When people argue that developers should review AI-generated code, the usual explanation is safety: AI can hallucinate, misunderstand a requirement, introduce a security problem or simply produce incorrect code.&lt;/p&gt;

&lt;p&gt;All of that is true. But for me, there is another reason that is at least as important.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The generated code is feedback on the architecture I designed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before implementation begins, an architecture is partly a hypothesis. I believe these responsibilities belong in these modules. I believe this abstraction is sufficiently general. I believe this data flow is clean. I believe this type model represents the domain correctly. I believe these boundaries will continue to make sense when the next requirement arrives.&lt;/p&gt;

&lt;p&gt;Then the AI implements the feature at high speed, and that hypothesis collides with reality.&lt;/p&gt;

&lt;p&gt;Perhaps the abstraction turns out to be awkward. Perhaps data starts leaking across boundaries that were supposed to be clean. Perhaps a type requires exceptions everywhere. Perhaps two concepts that looked independent are much more tightly coupled than expected. Perhaps the agent repeatedly struggles with one particular part of the design.&lt;/p&gt;

&lt;p&gt;Those are not merely implementation problems. They are signals.&lt;/p&gt;

&lt;p&gt;When I review the result, I am not only checking whether the agent wrote acceptable code. I am checking whether my model of the system survived implementation.&lt;/p&gt;

&lt;p&gt;That creates an extraordinarily powerful learning loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI can make you learn faster, not slower
&lt;/h2&gt;

&lt;p&gt;This is the part of AI-assisted development that I think gets far less attention than it deserves.&lt;/p&gt;

&lt;p&gt;Without AI, much of a developer’s working day is consumed by execution. You design something, then spend hours or days typing it into existence. You write boilerplate. You perform repetitive refactorings. You search through documentation. You implement the twentieth variation of a pattern you already understand.&lt;/p&gt;

&lt;p&gt;AI can compress a huge percentage of that execution time.&lt;/p&gt;

&lt;p&gt;If you keep yourself inside the reasoning loop, the time you save does not have to disappear. It can be reinvested into the parts of software engineering where the real intellectual work happens: architecture, modeling, semantics, constraints, trade-offs and validation.&lt;/p&gt;

&lt;p&gt;My workflow increasingly looks like this:&lt;/p&gt;

&lt;p&gt;Design → constrain → let AI execute → inspect the result → learn → adjust the design.&lt;/p&gt;

&lt;p&gt;Then another requirement arrives and the loop starts again.&lt;/p&gt;

&lt;p&gt;The interesting part is the speed. Suppose I design an architectural approach and implementing enough of it to discover its weaknesses would traditionally take several weeks. With an agent, I may get that feedback in hours. Sometimes much faster.&lt;/p&gt;

&lt;p&gt;That means AI does not merely accelerate implementation. Used this way, it accelerates the architecture-feedback loop.&lt;/p&gt;

&lt;p&gt;You make a design decision. Reality tests it almost immediately. You learn. Then you make another design decision.&lt;/p&gt;

&lt;p&gt;Do that repeatedly and something interesting happens: instead of spending most of your time exercising your ability to type code, you spend much more of it exercising your ability to design systems.&lt;/p&gt;

&lt;p&gt;That is almost the opposite of “AI melting your brain.”&lt;/p&gt;

&lt;p&gt;It is closer to deliberate practice for software architecture, with an implementation engine attached.&lt;/p&gt;

&lt;p&gt;Of course, this only works if you actually stay in the loop. If you delegate the decisions, delegate the implementation, accept the output and move directly to the next prompt, the mechanism reverses. AI keeps learning about your codebase while you gradually stop doing so.&lt;/p&gt;

&lt;p&gt;That is comprehension debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  I probably won’t generate 1,800 PRs a week. That’s fine.
&lt;/h2&gt;

&lt;p&gt;A semi-automatic workflow with deliberate human involvement is obviously slower than telling a swarm of agents to modify a repository as quickly as possible.&lt;/p&gt;

&lt;p&gt;That does not bother me.&lt;/p&gt;

&lt;p&gt;I want to produce exactly as much code as meaningful product development requires. If AI makes me capable of implementing useful changes faster than a product organization can discover and validate those changes, I have already won. More implementation throughput beyond that point has rapidly diminishing value.&lt;/p&gt;

&lt;p&gt;The objective of software engineering is not to maximize the amount of software produced. It is to solve useful problems with software.&lt;/p&gt;

&lt;p&gt;AI gives us an extraordinary opportunity to remove a large amount of mechanical work from that process. I think the mistake would be to remove ourselves from the intellectual work at the same time.&lt;/p&gt;

&lt;p&gt;So yes, review the code. It may contain bugs. It may contain security issues. It may misunderstand your requirements. Those are all perfectly good reasons.&lt;/p&gt;

&lt;p&gt;But review it for another reason too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review it because it tells you whether your architecture was right.&lt;/li&gt;
&lt;li&gt;Review it because it forces you to maintain a mental model of the system you are responsible for.&lt;/li&gt;
&lt;li&gt;Review it because every implementation is an experiment, and every experiment gives you feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if AI can run those experiments dramatically faster than before, perhaps the technology that supposedly makes developers stop thinking can—used correctly—make us learn faster than we ever could before.&lt;/p&gt;

&lt;p&gt;There is one line from Uncle Bob’s recent posts that summarizes the responsibility better than anything I could add:&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%2Ffqw5kgm5786hbdnzydse.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%2Ffqw5kgm5786hbdnzydse.png" alt="An inspirational quote graphic about engineering accountability" width="799" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is the point.&lt;/p&gt;

&lt;p&gt;You are not the engineer because you typed every line of code. You are not the engineer because you can explain every keystroke that created the repository. And you are certainly not the engineer because your AI generated more pull requests than somebody else’s.&lt;/p&gt;

&lt;p&gt;You are the engineer because you are accountable for the system that comes out the other side.&lt;/p&gt;




&lt;h3&gt;
  
  
  What do you think?
&lt;/h3&gt;

&lt;p&gt;How are you managing the balance between AI speed and system comprehension in your codebase? Do you use a human-in-the-loop workflow, or have you experimented with full-auto agents? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>learning</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop asking AI to do a linter’s job.</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Mon, 10 Aug 2026 14:56:28 +0000</pubDate>
      <link>https://dev.to/kotyk/stop-asking-ai-to-do-a-linters-job-1cp0</link>
      <guid>https://dev.to/kotyk/stop-asking-ai-to-do-a-linters-job-1cp0</guid>
      <description>&lt;p&gt;I have developed a workflow that I call:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A semi-automated, AI-native development flow with a human in the loop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may sound like a collection of AI buzzwords, but each part represents a very practical principle.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Semi-automated
&lt;/h2&gt;

&lt;p&gt;If a task can be performed reliably by a simple script, it should not be delegated to AI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want consistently formatted code? Configure Prettier.&lt;/li&gt;
&lt;li&gt;Want custom naming conventions, import restrictions, or architectural constraints? Configure ESLint or write a custom rule.&lt;/li&gt;
&lt;li&gt;Want consistent formatting across different editors? Add an EditorConfig file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not make AI spend context and reasoning capacity checking indentation, semicolons, or naming conventions. Deterministic problems should have deterministic solutions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Here is a less obvious example.
&lt;/h4&gt;

&lt;p&gt;I have written several thousand unit tests for my current project. As a perfectionist and former QA engineer, I care about how elements are selected in tests.&lt;/p&gt;

&lt;p&gt;Whenever possible, tests should use accessible selectors first, such as roles and accessible names. A test ID should only be used as a fallback.&lt;/p&gt;

&lt;p&gt;Initially, I treated this as something AI should remember, while I would catch mistakes during code review.&lt;/p&gt;

&lt;p&gt;But I noticed that I was correcting the same issue far too often.&lt;/p&gt;

&lt;p&gt;So I asked myself:&lt;/p&gt;

&lt;p&gt;Why am I repeatedly reviewing something that can be checked automatically?&lt;br&gt;
I wrote a custom lint rule.&lt;/p&gt;

&lt;p&gt;A few lines of code solved the problem permanently.&lt;/p&gt;

&lt;p&gt;Now the linter knows the required selector priority and reports violations automatically.&lt;/p&gt;

&lt;p&gt;The best part is that AI fixes these issues in virtually every case.&lt;/p&gt;

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

&lt;p&gt;Because running the project’s validation procedures is mandatory in my workflow. Even when AI makes a mistake, it runs the linter, receives a precise error message, and corrects the code.&lt;/p&gt;

&lt;p&gt;That is what “semi-automated” means to me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI handles tasks that require reasoning.&lt;br&gt;
Scripts handle tasks that require consistency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. AI-native
&lt;/h2&gt;

&lt;p&gt;A repository can be structured primarily for human convenience, or it can be structured so that both humans and AI can navigate it efficiently.&lt;/p&gt;

&lt;p&gt;An AI-native repository treats context as a limited engineering resource.&lt;/p&gt;

&lt;p&gt;Some developers are familiar with &lt;strong&gt;code golf&lt;/strong&gt;: solving a problem using the fewest possible characters.&lt;/p&gt;

&lt;p&gt;AI-native development is not exactly code golf, but the underlying constraint is similar:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every token has a cost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This does not mean compressing the code until it becomes unreadable. It means finding a balance between readability, consistency, and context efficiency.&lt;/p&gt;

&lt;p&gt;Project standardization plays a major role here.&lt;/p&gt;

&lt;p&gt;One component should not use a completely different structure, style, or paradigm from another component without a good reason.&lt;/p&gt;

&lt;p&gt;Reusable abstractions should be clearly defined and used consistently.&lt;/p&gt;

&lt;p&gt;This allows AI to find an existing implementation, understand it as the project standard, and use it as a reliable reference.&lt;/p&gt;

&lt;p&gt;Another important principle is what I call &lt;strong&gt;context segregation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A feature should be divided into meaningful files so that AI can load only the context required for the current task.&lt;/p&gt;

&lt;p&gt;For example, a test implementation may have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the test file itself&lt;/li&gt;
&lt;li&gt;fixtures&lt;/li&gt;
&lt;li&gt;mocks&lt;/li&gt;
&lt;li&gt;setup utilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes the setup is larger than the actual test suite.&lt;/p&gt;

&lt;p&gt;When I only need AI to inspect test names or understand what behavior is covered, there is no reason to feed the entire setup into its context.&lt;/p&gt;

&lt;p&gt;I use colocated suffix files for this purpose. A larger feature can have several supporting files placed next to it, with clear suffixes describing their roles.&lt;/p&gt;

&lt;p&gt;Depending on the task, I can provide AI with exactly the files it needs—and nothing else.&lt;/p&gt;

&lt;p&gt;And please, use barrel exports where they make architectural sense.&lt;/p&gt;

&lt;p&gt;There is no reason to repeatedly feed AI long absolute import paths when a stable public module API can expose the same components with fewer tokens and less coupling.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Human in the loop
&lt;/h2&gt;

&lt;p&gt;The internet currently seems obsessed with fully autonomous pipelines where an agent writes code around the clock without human participation.&lt;/p&gt;

&lt;p&gt;Maybe I am old-fashioned, but I am highly skeptical of that approach.&lt;/p&gt;

&lt;p&gt;I could list many examples of what AI misunderstands, what must be reviewed, and where autonomous implementations fail.&lt;/p&gt;

&lt;p&gt;But there is one issue that matters more than all the others:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you remove yourself from the process, you stop &lt;strong&gt;LEARNING&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;You are no longer collecting feedback.&lt;/li&gt;
&lt;li&gt;You are no longer examining what AI understands and what it misunderstands.&lt;/li&gt;
&lt;li&gt;You do not see which instructions work, which create confusion, where AI is fast, where it struggles, or where an additional tool could eliminate an entire category of mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, you lose the data required to improve your own development framework.&lt;/p&gt;

&lt;p&gt;Here is my favorite example.&lt;/p&gt;

&lt;p&gt;At one point, I created what I believed was the perfect AI development process.&lt;/p&gt;

&lt;p&gt;I reviewed every instruction repeatedly. I refined every detail. I was convinced that the framework was exceptionally well designed.&lt;/p&gt;

&lt;p&gt;Then I used it in production.&lt;/p&gt;

&lt;p&gt;Within two months, the process went through five generations of fundamental changes—not counting dozens of smaller improvements.&lt;/p&gt;

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

&lt;p&gt;Because real-world usage generated feedback.&lt;/p&gt;

&lt;p&gt;I observed what failed, what created unnecessary work, what AI interpreted incorrectly, and what could be automated more effectively.&lt;/p&gt;

&lt;p&gt;No matter how good your prompt, instruction set, agent configuration, or MCP setup appears, you do not have objective evidence that it works until you observe it under real production conditions.&lt;/p&gt;

&lt;p&gt;That is why my workflow keeps a human in the loop.&lt;/p&gt;

&lt;p&gt;Not merely to approve AI-generated code.&lt;/p&gt;

&lt;p&gt;But to learn from every iteration and continuously improve the system producing that code.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A New AI Paradigm: The Billion-Dollar Blind Spot</title>
      <dc:creator>Mykola Mizhigurskiy</dc:creator>
      <pubDate>Wed, 21 May 2025 11:55:36 +0000</pubDate>
      <link>https://dev.to/kotyk/a-new-ai-paradigm-the-billion-dollar-blind-spot-2h5d</link>
      <guid>https://dev.to/kotyk/a-new-ai-paradigm-the-billion-dollar-blind-spot-2h5d</guid>
      <description>&lt;h1&gt;
  
  
  A New AI Paradigm: The Billion-Dollar Blind Spot
&lt;/h1&gt;

&lt;p&gt;Modern AI systems are excellent at detecting toxicity, abuse, radicalization.&lt;br&gt;&lt;br&gt;
But there's a blind spot — and it's costing us billions:&lt;/p&gt;

&lt;p&gt;They can't detect brilliance.&lt;/p&gt;

&lt;p&gt;Every day, millions of users interact with AI. Among them,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 in 10,000 may hold a breakthrough idea.
&lt;/li&gt;
&lt;li&gt;1 in 100,000 may be modeling the future of society, science, or intelligence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But all of that signal vanishes.&lt;br&gt;&lt;br&gt;
No system is designed to surface it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter SVITLO
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SVITLO&lt;/strong&gt; (Signal of Visionary Ideas Through Latent Observation) is a protocol that proposes a new direction:&lt;/p&gt;

&lt;p&gt;➡️ Not just detecting threats&lt;br&gt;&lt;br&gt;
➡️ But detecting &lt;strong&gt;insight&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
➡️ Surface-level agnostic, cognition-focused&lt;/p&gt;

&lt;p&gt;It doesn't require new infrastructure.&lt;br&gt;&lt;br&gt;
It builds on existing analytics pipelines and reorients them from defense to discovery.&lt;/p&gt;

&lt;p&gt;What if your model could say:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This interaction shows signs of exceptional thought. Would you like to be seen?”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Identifying overlooked talent
&lt;/li&gt;
&lt;li&gt;Spotting founder-level thinkers
&lt;/li&gt;
&lt;li&gt;Building archives of visionary insight
&lt;/li&gt;
&lt;li&gt;Enhancing alignment, recruitment, and impact&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;📖 Full manifesto on GitHub:&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://github.com/KiT-Maverik/svitlo" rel="noopener noreferrer"&gt;SVITLO manifest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback, forks, and discussion welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>futurechallenge</category>
      <category>chatgpt</category>
    </item>
  </channel>
</rss>
