<?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: Oleh Veheria</title>
    <description>The latest articles on DEV Community by Oleh Veheria (@5uper0).</description>
    <link>https://dev.to/5uper0</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%2F4027271%2Fb47d7f3a-d282-461e-98ec-c9801a73c150.png</url>
      <title>DEV Community: Oleh Veheria</title>
      <link>https://dev.to/5uper0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/5uper0"/>
    <language>en</language>
    <item>
      <title>Modularizing a Legacy iOS App Without Stopping Delivery</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Sat, 05 Sep 2026 09:34:17 +0000</pubDate>
      <link>https://dev.to/5uper0/modularizing-a-legacy-ios-app-without-stopping-delivery-2k2l</link>
      <guid>https://dev.to/5uper0/modularizing-a-legacy-ios-app-without-stopping-delivery-2k2l</guid>
      <description>&lt;p&gt;I spent a year migrating a smart-pet-device company's app off a single-target Objective-C codebase, module by module, while the team kept shipping releases the entire time. No feature freeze, no six-month rewrite branch nobody could merge back. +30% on performance and UX metrics by the end, and every release in between still went out on schedule.&lt;/p&gt;

&lt;p&gt;Modularization gets sold as a build-time problem: split the app so Xcode compiles faster. That part's real, but it's not what makes it hard. The hard part is deciding where the boundaries actually go, because a wrong one costs you for years, and the stop-the-world rewrite to fix it later is exactly the thing you were trying to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boundaries follow ownership, not folders
&lt;/h2&gt;

&lt;p&gt;The obvious move is modularizing along the existing folder structure: pull &lt;code&gt;Networking/&lt;/code&gt; into a module, then &lt;code&gt;UI/&lt;/code&gt;, then &lt;code&gt;Models/&lt;/code&gt;. That produces modules that compile a bit faster and change nothing else, because the coupling that used to be implicit inside one target is now explicit across module boundaries, and just as tight.&lt;/p&gt;

&lt;p&gt;The boundary that actually held on this migration was the one that followed who owned the code and how often it changed independently: a screen's data layer, its business logic, and its UI moved together as one unit, because that's the unit a single engineer or pair actually shipped changes to. A "shared utilities" module everyone imports and nobody owns is where modularization efforts go to die. It becomes a second monolith with extra ceremony bolted on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extract the smallest thing first, not the biggest
&lt;/h2&gt;

&lt;p&gt;The natural first move is pulling out the biggest, most obviously reusable piece: the design system, the networking layer. Those are the wrong first extractions, because they're also the pieces with the most existing call sites, so proving the approach means touching the most files before you've proven anything.&lt;/p&gt;

&lt;p&gt;The extraction that actually de-risks the migration is the smallest, most isolated feature module with the fewest dependents. Get its public interface defined, its internals hidden, and ship it in a real release. That's the proof the rest of the migration reuses. Start with the design system instead, and when something breaks in week three you can't tell whether it's the modularization approach or the size of the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interim is the project, not a phase you pass through
&lt;/h2&gt;

&lt;p&gt;A half-modularized app has a monolith target and a growing set of extracted modules depending on each other in ways nobody fully mapped. Every new feature during that stretch has to decide whether it belongs in the module structure or the legacy target, and whether that decision gets revisited when the module graph shifts next month. Budget the interim with an explicit exit criterion. "60% modularized" isn't a real number when nobody's diagrammed the dependency graph it's measured against.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually breaks delivery mid-migration
&lt;/h2&gt;

&lt;p&gt;Build times regress briefly while modules settle into their real dependency graph. Merge conflicts cluster in whatever file every module still touches, usually the app's root composition point, until that gets its own clear owner too. And team confidence dips: engineers who've shipped fast in the old monolith for years feel slower for a few sprints inside the new boundaries, before the structure starts paying that speed back. Name that dip to the team before it happens, not after someone asks why velocity looks worse this sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The discipline that holds
&lt;/h2&gt;

&lt;p&gt;Define a module's public interface before extracting its implementation. Ship one small module fully, in a real release, before touching a second. Track the interim as its own workstream with an exit criterion. And accept that the ownership map, not the folder structure, is what decides where a boundary actually goes.&lt;/p&gt;

&lt;p&gt;If you're staring at a monolithic codebase and a roadmap that can't pause for a rewrite, that's exactly the kind of call I help teams make in a &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;strategy session&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the module in your own codebase that everyone agrees should be split out, and what's actually stopping the team from starting?&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/modularizing-legacy-ios-app/" rel="noopener noreferrer"&gt;veheria.tech/blog/modularizing-legacy-ios-app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>architecture</category>
      <category>engineering</category>
      <category>legacy</category>
    </item>
    <item>
      <title>n8n vs Custom Code for Engineering Automation: The Decision, and the Bug That Proved It Right</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Fri, 04 Sep 2026 09:16:25 +0000</pubDate>
      <link>https://dev.to/5uper0/n8n-vs-custom-code-for-engineering-automation-the-decision-and-the-bug-that-proved-it-right-3a8l</link>
      <guid>https://dev.to/5uper0/n8n-vs-custom-code-for-engineering-automation-the-decision-and-the-bug-that-proved-it-right-3a8l</guid>
      <description>&lt;p&gt;I built the pipeline that publishes this site's content in versioned code instead of n8n. Not a philosophical stance against no-code tools, a practical call, and one specific bug is why I still think it was the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why code, not a canvas
&lt;/h2&gt;

&lt;p&gt;Four reasons drove it, in order of how much they actually mattered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Review parity.&lt;/strong&gt; Every change to how a post gets approved or published goes through the same PR review as the rest of the site. A workflow-canvas change doesn't get that by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headless operation.&lt;/strong&gt; Claude Code drives the queue directly, no GUI dashboard sitting between the agent and the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Existing infrastructure.&lt;/strong&gt; A Telegram bot already handled approvals; there was no gap a workflow tool needed to fill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One fewer service.&lt;/strong&gt; Every extra tool in the stack is something else to patch and keep secure. Skipping it was the cheap option, not just the principled one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The bug that proved it
&lt;/h2&gt;

&lt;p&gt;On July 20, 2026, a scheduled post silently failed. The Buffer API adapter treated an error response as a normal one, never checked the status, so the X post never actually went out while the pipeline marked it published. Nothing threw, nothing alerted, the queue just quietly lied about what had shipped.&lt;/p&gt;

&lt;p&gt;I found it the way you'd expect: read &lt;code&gt;buffer.py&lt;/code&gt;, saw exactly where the status check was missing, fixed one line. Cheap once you can see it.&lt;/p&gt;

&lt;p&gt;That's the part I can't picture happening the same way in a workflow canvas. I genuinely don't have a mental model for debugging that failure mode there, a canvas doesn't hand you the same thing a stack trace and &lt;code&gt;git blame&lt;/code&gt; hand you in code. You'd be reading node configuration and hoping the tool's own logging caught the edge case, instead of reading the exact line that skipped a check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is actually about
&lt;/h2&gt;

&lt;p&gt;It isn't code versus no-code as a philosophy. It's about legibility when automation is wrong in a way that doesn't throw an error. A silent-fail bug is the worst kind, because nothing tells you to go look. The only thing that saved this one was that the fix path was a normal code review, on a normal file, in a language with a debugger and a blame command. That's a property of the tool, not of how careful I was that week.&lt;/p&gt;

&lt;p&gt;If your automation stack can fail without telling you, the question worth asking isn't whether the tool is fast to build in. It's whether you'd actually be able to find the bug when it goes quiet.&lt;/p&gt;

&lt;p&gt;If you're weighing a workflow tool against custom code for something that publishes or ships on your behalf, that's exactly the kind of tradeoff I help teams think through in a &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;strategy session&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the automation in your own stack you'd have the hardest time debugging if it started failing silently?&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/n8n-vs-custom-agents-engineering-ops/" rel="noopener noreferrer"&gt;veheria.tech/blog/n8n-vs-custom-agents-engineering-ops&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>productivity</category>
    </item>
    <item>
      <title>CLAUDE.md for an iOS Team: What to Put In It (and What to Leave Out)</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Fri, 04 Sep 2026 09:16:07 +0000</pubDate>
      <link>https://dev.to/5uper0/claudemd-for-an-ios-team-what-to-put-in-it-and-what-to-leave-out-23pp</link>
      <guid>https://dev.to/5uper0/claudemd-for-an-ios-team-what-to-put-in-it-and-what-to-leave-out-23pp</guid>
      <description>&lt;p&gt;My first CLAUDE.md for a client project ran 400 lines: architecture diagrams, the full MVVM-vs-TCA debate, a style section that just repeated SwiftLint's config in prose. Claude Code reads that file in full on every single turn, and it still missed rules buried near the bottom, because by line 340 they're competing with everything else for the model's attention. I cut it to 60 lines over two weeks. Same team, same codebase, fewer violations of the rules that actually mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not documentation
&lt;/h2&gt;

&lt;p&gt;The instinct is to treat CLAUDE.md like a README: a place to record everything true about the project. A README gets read once by a human who skims for the one section they need. CLAUDE.md gets read in full, by a model, every turn, and every line you add dilutes every other line's share of attention. That's the whole design constraint, and most CLAUDE.md files ignore it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What earns a line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Non-obvious conventions.&lt;/strong&gt; Not "we use MVVM," that's visible in five minutes of reading the code. "ViewModels never import UIKit" earns its place only if it's a rule someone actually broke once and it cost a day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constraints invisible in the diff.&lt;/strong&gt; App Store review requirements, a minimum OS version the code doesn't yet reflect, a performance budget on one screen because a past ship got rejected for jank. An agent has no way to infer any of that from the code alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo-specific workflow gotchas.&lt;/strong&gt; Which branch triggers a real deploy, which test suite is a known-flaky non-gate versus a hard one, where the actual source of truth lives when two files disagree. I run a merge gate across a few of my own repos, code only merges once CI is green and review found nothing blocking, and the single highest-value line in each CLAUDE.md is the sentence explaining that the gate exists and why a raw &lt;code&gt;git merge&lt;/code&gt; is bypassing something on purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the agent never touches unsupervised.&lt;/strong&gt; For me that's deploy config and anything security-sensitive. Naming the boundary explicitly is cheaper than discovering it was needed after something already broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  What doesn't
&lt;/h2&gt;

&lt;p&gt;Anything git blame or the README already answers. Aspirational rules no linter enforces, an unenforced rule just teaches the model that the file's rules are optional. Architecture history and rationale, useful for onboarding a human, irrelevant to the task in front of the agent right now. Anything a linter or type system already blocks mechanically; if SwiftLint already kills force-unwraps, writing "avoid force-unwraps" adds length, not signal.&lt;/p&gt;

&lt;p&gt;The before/after: the 400-line version spelled out the Git branching strategy, every third-party dependency and why it was picked, and a style section duplicating the linter. The 60-line version points at the linter instead of repeating it, names the merge gate and why, and states the one ViewModel/UIKit rule an agent (and a couple of humans) had actually gotten wrong before. The short file is the harder one to write, it forces you to decide what actually matters instead of writing down everything you know.&lt;/p&gt;

&lt;p&gt;This is the same standardize-the-few-things-that-compound instinct behind &lt;a href="https://veheria.tech/blog/modularizing-legacy-ios-app/" rel="noopener noreferrer"&gt;modularizing a legacy iOS app without stopping delivery&lt;/a&gt;: legislate the few rules that matter across the whole team, leave the rest to local judgment. And it only holds if the codebase backs it up. A CLAUDE.md pointing at "the linter enforces this" is only as good as that linter config being current and actually run in CI.&lt;/p&gt;

&lt;p&gt;What's the longest-standing rule in your own CLAUDE.md that you're not sure is still true?&lt;/p&gt;

&lt;p&gt;If you're standing up this workflow on an iOS team and want a second pair of eyes on what belongs in the file versus what's just noise, &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;that's the kind of thing I help with&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/claude-md-for-ios-teams/" rel="noopener noreferrer"&gt;veheria.tech/blog/claude-md-for-ios-teams&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>swift</category>
    </item>
    <item>
      <title>SwiftUI vs UIKit in 2026: A Staff Engineer's Decision Framework</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Fri, 04 Sep 2026 09:03:41 +0000</pubDate>
      <link>https://dev.to/5uper0/swiftui-vs-uikit-in-2026-a-staff-engineers-decision-framework-h4p</link>
      <guid>https://dev.to/5uper0/swiftui-vs-uikit-in-2026-a-staff-engineers-decision-framework-h4p</guid>
      <description>&lt;p&gt;Every SwiftUI-vs-UIKit take argues which framework is better. That's the wrong question. The one that actually matters: which one can this specific team ship and maintain, on this specific timeline, without the codebase becoming the bottleneck. Framework superiority is a debate for a blog post. Team fluency and timeline are what actually decide a ship date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team fluency beats framework features
&lt;/h2&gt;

&lt;p&gt;An experienced UIKit team moving to SwiftUI pays a real productivity cost during ramp-up, even on the exact greenfield work SwiftUI is theoretically best at. The framework being technically superior for a use case doesn't matter if the team writing it is slower in it for the next two quarters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide per screen, not per app
&lt;/h2&gt;

&lt;p&gt;The better unit of decision isn't the app, it's the screen. Complex animation work and legacy SDK integrations still favor UIKit. Forms and straightforward navigation favor SwiftUI. Forcing one framework across an entire app because it won the debate once is how you end up fighting the wrong tool on the one screen that needed the other one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks in year two, not year one
&lt;/h2&gt;

&lt;p&gt;A screen that started as a simple form can grow custom interaction requirements a year later that the original framework choice never anticipated. The failure mode isn't picking wrong on day one, it's not revisiting the choice as a screen's requirements change underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hiring cost nobody prices in
&lt;/h2&gt;

&lt;p&gt;Junior engineers ramp on SwiftUI faster. Senior UIKit engineers take longer to become productive in SwiftUI than the migration timeline usually assumes. If your hiring plan and your framework plan aren't the same conversation, one of them is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing isn't a rounding error
&lt;/h2&gt;

&lt;p&gt;SwiftUI testing looks different enough from UIKit testing that a team can't assume the skill transfers by osmosis. That's ramp-up time you have to plan for explicitly, the same way you'd plan for a new build tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The framework, applied
&lt;/h2&gt;

&lt;p&gt;Four situations, four different calls: a greenfield project with an experienced team defaults to SwiftUI. A stable, working UIKit codebase doesn't get rewritten for novelty. An active migration needs its dual-stack interim budgeted as its own tracked phase with a real exit criterion, not folded into "get to the target architecture" and hoped to resolve itself, the same underestimation shows up in &lt;a href="https://veheria.tech/blog/modularizing-legacy-ios-app/" rel="noopener noreferrer"&gt;modularizing a legacy iOS app without stopping delivery&lt;/a&gt;, where the interim ran months longer than planned for exactly this reason. And any individual screen gets evaluated on its own requirements, not on which framework the rest of the app happens to use.&lt;/p&gt;

&lt;p&gt;If you're walking into this decision cold: don't start with the framework. Start with your team's fluency, your timeline, and which screens actually need what. The framework comparison is the easy 20% of the decision. The other 80% is admitting your team and your timeline are what's actually being decided, not React-Native-style feature checklists.&lt;/p&gt;

&lt;p&gt;If you're staring at this decision on a real team with a real deadline and want a second opinion before committing, that's what I help with in a &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;strategy session&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the one screen in your app where you'd pick the other framework if you were starting it today?&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/swiftui-vs-uikit-2026/" rel="noopener noreferrer"&gt;veheria.tech/blog/swiftui-vs-uikit-2026&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>swiftui</category>
      <category>engineering</category>
    </item>
    <item>
      <title>llms.txt Implementation: The Part Nobody Measures</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Mon, 24 Aug 2026 07:00:05 +0000</pubDate>
      <link>https://dev.to/5uper0/llmstxt-implementation-the-part-nobody-measures-2144</link>
      <guid>https://dev.to/5uper0/llmstxt-implementation-the-part-nobody-measures-2144</guid>
      <description>&lt;p&gt;My robots.txt has a line that says AI search and citation crawlers are "explicitly welcomed." I wrote that in July, four months after I'd already shipped an &lt;code&gt;llms.txt&lt;/code&gt; file to this exact site. In that time I have not been able to confirm that a single one of those crawlers has ever opened it.&lt;/p&gt;

&lt;p&gt;That is not the story you get from most llms.txt guides. Search "llms.txt implementation" and you get a dozen "Complete 2026 Guide" posts explaining the syntax, telling you to keep it to 20-50 curated links instead of dumping your sitemap, and listing which companies now publish one. All correct. All missing the part that actually matters once you have shipped it: how do you know it did anything?&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually shipped, and when
&lt;/h2&gt;

&lt;p&gt;I added &lt;code&gt;llms.txt&lt;/code&gt; to veheria.tech back in March, before I had more than two blog posts to point at (PR #63). It sat there as a curated summary: who I am, what I do, how to reach me. In July, once the AI-native engineering wedge posts started shipping, I updated it to list them explicitly (PR #84), each with a one-line description of what the post actually covers, not just a URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Writing&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Claude Code for iOS Development: The Workflow, Not the Setup&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://veheria.tech/blog/claude-code-ios-development/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: where an AI agent is trusted in a real iOS team's loop, and where a human keeps the call.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;A Claude Code Review Workflow That Saved 30 Minutes Per Engineer a Day&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://veheria.tech/blog/claude-code-code-review-workflow/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: what to automate, what to keep human, and the one number measured after months of daily use.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three posts, not twenty sitemap URLs. That was a deliberate call, not laziness. It is the same rule I run my code-review agents on: &lt;a href="https://veheria.tech/blog/claude-code-code-review-workflow/" rel="noopener noreferrer"&gt;every finding has to cite a file, a line, and a concrete failure scenario, or it gets dropped&lt;/a&gt;. A link with no reason for a model to follow it is noise, whether it comes from an agent's review comment or from a sitemap dump into a file that is supposed to be curated. The entire pitch of llms.txt over a sitemap is that a human decided what matters. Paste the sitemap in and you have thrown that advantage away to save five minutes.&lt;/p&gt;

&lt;p&gt;I left more out than I put in. The full site has language variants in English, Spanish, and Ukrainian; only the English canonical URLs made the file, because an assistant summarizing my work does not need three copies of the same claim. It has a contact page, a work page, and an about page; only &lt;code&gt;/work&lt;/code&gt; earned a line, because that is the one page where the outcome of reading this file (someone reaching out) actually happens, and a model deciding whether to surface me is more useful with one clear next step than three competing ones. Every entry I kept had to answer "what does a model do with this that it could not do with the URL alone," the same test I apply to a code comment before I let it survive review. Most links fail that test. That is exactly why most llms.txt files, mine included at first draft, start too long and get cut, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement problem nobody in the guides admits
&lt;/h2&gt;

&lt;p&gt;Here is where it gets uncomfortable. I already run SEO on this site the way I run everything else here: headless, through scripts that pull Google Search Console and GA4 on a schedule. That pipeline can tell me, to the click, when a page gets indexed and what query it shows up for. It cannot tell me whether GPTBot, ClaudeBot, or PerplexityBot ever fetched &lt;code&gt;/llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reasons are structural, not a gap in my scripts. GA4 fires on JavaScript execution in a browser; a crawler doing a raw HTTP fetch of a static Markdown file never runs a line of JS, so it never reports. Cloudflare Pages, on the free tier this site runs on, does not expose raw request logs, only aggregate analytics that do not break out user agents at the path level. The companies the guides cite as proof llms.txt "works" (Anthropic, Stripe, Vercel, Cloudflare) all run their own infrastructure with real access logs. A solo site on a hosting tier built for cheap static delivery does not get that visibility for free.&lt;/p&gt;

&lt;p&gt;So the honest state of my &lt;code&gt;llms.txt&lt;/code&gt;, four months in, is: it costs nothing, it might be read, and I have no instrument that would tell me either way. Before writing this I checked the other properties I run content or SEO for, not just this one. Most of them already ship an &lt;code&gt;llms.txt&lt;/code&gt;. None of them, this site included, has any way to confirm a crawler opened one. Every guide I found treats adoption as the finish line. Adoption is the easy 90% of the work. The other 10%, knowing if it did anything, is the part that would actually justify spending more time on it, and nowhere in what I run had anyone, including me until an hour ago, gotten past the first 90%.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake, and what I'd do differently
&lt;/h2&gt;

&lt;p&gt;I have made this exact mistake before, on a bigger stack. When I put Claude Code agents into a multinational iOS team's review loop, I deployed first and picked the metric of record after, which meant the first stretch of tuning was against a feeling instead of a number. &lt;code&gt;llms.txt&lt;/code&gt; is the same failure in miniature: I shipped the artifact and treated "it's live" as the win condition, without deciding up front how I would ever know if it earned its keep.&lt;/p&gt;

&lt;p&gt;What I'd do differently is treat instrumentation as part of the ship, not a follow-up. Search Console will not help here; it reports on Googlebot's own crawl, not on GPTBot, ClaudeBot, or PerplexityBot fetching a static file. The version I actually plan to try next: a Cloudflare Pages Function in front of the &lt;code&gt;/llms.txt&lt;/code&gt; route that logs the User-Agent header on every request before serving the file. Cheap to build, and it is the difference between "I hope a crawler reads this" and a line in a log that says one did. I did not build that when I shipped the file in March, or when I updated it in July. That is the mistake, not the file itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you still ship it
&lt;/h2&gt;

&lt;p&gt;Yes, and the guides are right about that much. Adoption cost is minutes, the downside is zero, and being the entry that shows up when an assistant is asked to summarize your site is worth having even if you cannot yet prove the mechanism. What I'd change about how everyone, myself included, talks about it: stop writing as if shipping the file were the result. It is the setup. The result is whatever you can actually verify happened after, and right now, for anyone without an enterprise logging stack, that verification does not exist by default. Say that part out loud instead of implying the file is doing invisible work you cannot see.&lt;/p&gt;

&lt;p&gt;This is the same judgment call that runs through most of what I write about &lt;a href="https://veheria.tech/blog/ai-agents-engineering-team-workflow/" rel="noopener noreferrer"&gt;putting AI agents into a real engineering workflow&lt;/a&gt;: the interesting question is never whether the tool is worth adopting, it almost always is. The interesting question is whether you built a way to tell if it is working, before you started telling other people to adopt it too.&lt;/p&gt;

&lt;p&gt;If you are deciding where to spend engineering time on AI-visibility work versus everything else competing for the sprint, that kind of "does this actually move something, or is it cargo cult" call is exactly what &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;I help teams work through in a strategy session&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have shipped &lt;code&gt;llms.txt&lt;/code&gt; on your own site, have you found any way to confirm a crawler actually read it? I would like to know I am not the only one flying blind on this.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/llms-txt-implementation/" rel="noopener noreferrer"&gt;veheria.tech/blog/llms-txt-implementation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>ai</category>
      <category>webdev</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Claude Code for iOS App Development: The Workflow, Not the Setup</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:55:51 +0000</pubDate>
      <link>https://dev.to/5uper0/claude-code-for-ios-app-development-the-workflow-not-the-setup-5bfo</link>
      <guid>https://dev.to/5uper0/claude-code-for-ios-app-development-the-workflow-not-the-setup-5bfo</guid>
      <description>&lt;p&gt;Every "Claude Code for iOS" guide stops at the same place: pin your Swift toolchain in CLAUDE.md, install XcodeBuildMCP, run generate → build → test from the terminal. That is the easy 20%. It gets you a demo. It does not get you a workflow you would trust on a team shipping to the App Store every week.&lt;/p&gt;

&lt;p&gt;I have run Claude Code inside a real multinational iOS team's loop, not as a toy. The setup took an afternoon. Deciding where the agent is allowed to make decisions and where a human stays took months. That second part is the whole job, and it is the part nobody writes down. So here it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup is real, and it is not the point
&lt;/h2&gt;

&lt;p&gt;To be fair, the setup does matter and the guides get it mostly right. XcodeBuildMCP gives Claude Code a real build-and-test surface instead of blind file edits. A Swift Package Manager layout matters more than people admit: Claude Code can fully own a &lt;code&gt;Package.swift&lt;/code&gt; module, but it should not be hand-editing &lt;code&gt;.pbxproj&lt;/code&gt; files, because the moment it corrupts the project graph you lose an hour untangling a merge conflict no human wrote.&lt;/p&gt;

&lt;p&gt;The CLAUDE.md I pin is deliberately boring, and after ten years of iOS I think boring is the point. It nails down three things. First, the exact Swift and Xcode versions CI builds against, so the agent can never "fix" a red build by quietly drifting the toolchain under you. Second, SwiftUI is the default for anything new; UIKit stays only where legacy screens already live, so the agent does not invent a second way of doing things. Third, one hard rule on dependencies: a new package is added through Swift Package Manager at a module boundary, never by hand-editing the project file. The breakage on iOS is almost always in the parts you left implicit, so the fix is to leave nothing implicit.&lt;/p&gt;

&lt;p&gt;The community numbers around this are loud. Guides published through mid-2026 claim 40% faster feature delivery and 60% less boilerplate (for example the June 2026 write-ups on Medium and Claude Lab). I would treat those like any vendor-adjacent number: directionally true for greenfield SwiftUI, much softer for a mixed UIKit and SwiftUI codebase where the agent spends half its time reading storyboards it cannot reliably edit. The honest version is that the gain is real and uneven, and it shows up in a specific place: the boring, high-volume work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the agent earns its place
&lt;/h2&gt;

&lt;p&gt;Claude Code is genuinely good at the iOS work that is mechanical but tedious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaffolding a new SwiftUI feature module in SPM, with the view, the view model, and a test target wired up the way the rest of the codebase already does it.&lt;/li&gt;
&lt;li&gt;Writing the first pass of unit tests against a protocol you just defined, so the human writes the interesting edge cases instead of the setup.&lt;/li&gt;
&lt;li&gt;Incremental migration work. On a legacy Objective-C and Swift codebase I moved to SwiftUI, the win was doing it release by release while shipping, and an agent is a good fit for the repetitive per-screen conversion once you have set the pattern for the first one. The judgment (incremental over rewrite, keep shipping) stays human. The typing does not have to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is "AI writes the app." It is the agent taking the 60% of iOS work that is pattern-following, so the senior time goes to the 40% that is actually a decision.&lt;/p&gt;

&lt;p&gt;One mechanic decides whether any of this is worth it: the build-and-test loop is only as fast as your build. XcodeBuildMCP lets the agent compile and run tests on its own, which is what makes it autonomous instead of a fancy autocomplete. But on a large app a cold build runs into minutes, and an agent that rebuilds the whole workspace after every one-line change will burn your afternoon and your patience faster than doing the work yourself. The fix is the same discipline you would want for a human: keep the agent working inside a small SPM module with its own fast test target, so its edit, build, test cycle is seconds, not minutes. A slow loop is a workflow you will quietly stop using by Thursday. The fast loop is the one that actually changes how the team works. This is also why the SPM structure I keep pushing is not architecture pedantry. It is what makes the agent usable at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust boundary is the workflow
&lt;/h2&gt;

&lt;p&gt;Here is the line that took months to draw, and it is the one thing I would tell any team adopting this.&lt;/p&gt;

&lt;p&gt;The failure mode is not the agent writing bad Swift. It writes fine Swift. The failure mode is the agent optimizing a proxy instead of the goal. Point it at "make the tests pass" and it will make the tests pass, sometimes by weakening the test. I have watched an agent elsewhere optimize ticket-close speed over customer value because that was the metric it could see. On iOS the same thing looks like an agent that satisfies the compiler and the test suite while quietly changing the concurrency model, or reaching for a third-party dependency to close a ticket faster.&lt;/p&gt;

&lt;p&gt;So the boundary I settled on: the agent owns anything where correctness is checkable by a machine and the intent is already encoded (module scaffolding, test generation, mechanical migration, boilerplate). A human owns anything where the real goal is not in the diff: architecture, concurrency decisions, dependency additions, and anything touching the release. The review layer is where I enforce that, and I wrote about the review side of this separately in &lt;a href="https://veheria.tech/blog/claude-code-code-review-workflow/" rel="noopener noreferrer"&gt;the Claude Code review workflow that saved 30 minutes per engineer a day&lt;/a&gt;. The number I actually measured was in that review loop, not in raw code generation, and that ordering is not an accident: the value came from encoding review taste into the agent, not from letting it type faster.&lt;/p&gt;

&lt;p&gt;If you want the longer argument for why some of these calls stay human no matter how good the model gets, that is &lt;a href="https://veheria.tech/blog/ios-architecture-decisions-ai-cant-make/" rel="noopener noreferrer"&gt;the architecture decisions AI cannot make for you&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The shape I have run into most on iOS is concurrency. Hand an agent a data-race warning during a SwiftUI migration off an older Objective-C and Swift codebase, tell it to get the build clean, and it will reach for the move that silences the compiler: wrap the call in &lt;code&gt;@MainActor&lt;/code&gt;, or hop everything to the main queue. The warning disappears, the tests stay green, and the actual threading model quietly gets worse. You have serialized work onto the main thread that had no business being there, and you will pay for it in a janky scroll three sprints later. The compiler was satisfied. The concurrency design was not. That is the whole risk in one sentence: the agent optimizes the signal it can see, and thread-safety is exactly the kind of intent that never shows up in the diff. So concurrency changes are on my side of the line, always.&lt;/p&gt;

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

&lt;p&gt;I deployed the agents first and defined how I would measure them second. That is backwards. Because I had no metric-of-record before the rollout, the early "is this even helping" conversations were vibes, not data, and I spent a week defending a workflow I could not yet prove. If I did it again I would set the number first: pick review-cycle time or per-engineer time saved, baseline it for a week with no agents, then turn them on. The tool is easy to adopt. The thing that makes adoption stick is being able to show a team a before and an after they believe. It's a pattern I keep running into outside iOS too: &lt;a href="https://veheria.tech/blog/llms-txt-implementation/" rel="noopener noreferrer"&gt;shipping &lt;code&gt;llms.txt&lt;/code&gt; on this site&lt;/a&gt; was the same mistake at a much smaller scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual takeaway
&lt;/h2&gt;

&lt;p&gt;The setup guides are not wrong, they are just answering the small question. Getting Claude Code to build and test an iOS project is a solved afternoon. Getting it to speed up a real team without quietly eroding quality is a months-long exercise in deciding what the agent is allowed to decide. The teams that get value are not the ones with the best CLAUDE.md. They are the ones who drew the trust boundary on purpose and measured the result. The same trust-boundary question, generalized past iOS to any engineering team, is the subject of &lt;a href="https://veheria.tech/blog/ai-agents-engineering-team-workflow/" rel="noopener noreferrer"&gt;AI agent workflows for engineering teams&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are standing up this workflow on an iOS team and want a second pair of eyes on where to draw that line before you roll it out, &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;that is the kind of thing I help with&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is the first piece of your iOS workflow you would actually hand to an agent, and what would you never let it touch?&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/claude-code-ios-development/" rel="noopener noreferrer"&gt;veheria.tech/blog/claude-code-ios-development&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AI Agent Workflows for Engineering Teams: What Actually Works</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Sat, 22 Aug 2026 15:43:17 +0000</pubDate>
      <link>https://dev.to/5uper0/ai-agent-workflows-for-engineering-teams-what-actually-works-6g8</link>
      <guid>https://dev.to/5uper0/ai-agent-workflows-for-engineering-teams-what-actually-works-6g8</guid>
      <description>&lt;p&gt;The first agent workflow I put in front of an engineering team optimized the wrong thing beautifully. It had a clean prompt, it closed tickets fast, the burndown looked great. It also shipped work that was technically done and missed what the customer actually needed, because "ticket closed" was the only signal it had. That failure taught me more about agent workflows than any of the ones that worked.&lt;/p&gt;

&lt;p&gt;Most of what you read about AI agents for engineering teams is written by people selling the platform. It describes the architecture diagram, not the Tuesday. I put Claude Code agents, MCP servers, and browser automation into the real review and test loop for a multinational iOS team, and in my own measurement it saved about 30 minutes per engineer per day without dropping review quality. Here's what actually moved that number, and what quietly wasted our time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake: automating output instead of judgment
&lt;/h2&gt;

&lt;p&gt;The seductive pitch is that agents write the code, so engineers write less. That is the part that works least well and matters least.&lt;/p&gt;

&lt;p&gt;An LLM gives you the average of the internet. In Swift, where there is less training data than in JavaScript or Python, that average is worse. So an agent left to generate freely produces plausible code that a senior engineer then has to read line by line to trust, which is not obviously faster than writing it. The time did not come from letting agents build. It came from letting them do the mechanical verification a human is slow at and bored by.&lt;/p&gt;

&lt;p&gt;Every PR review is really two jobs stacked on top of each other. Mechanical verification: does it build, are edge cases handled, did someone forget to localize a string, is the naming consistent with the module. And judgment: is this the right abstraction, does it fit where this code is heading, will it bite us in six months. Humans are slow at the first and irreplaceable at the second. Classic review forces senior engineers to do both, so the mechanical part crowds out the judgment part until reviewers skim, type LGTM, and architectural drift accumulates one skimmed PR at a time.&lt;/p&gt;

&lt;p&gt;The agent's job is the first stack. Never the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually worked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A first-pass reviewer on every PR.&lt;/strong&gt; Agents fan out over the diff before any human looks, one dimension each: correctness and edge cases, consistency with surrounding patterns, whether tests cover the behavior change or just mirror the implementation, and mobile-specific checks like hardcoded strings and touch targets under 44pt. Every finding has to cite a file, a line, and a concrete failure scenario. A finding with no failure scenario gets dropped. That one rule is the difference between useful output and "consider improving readability" noise. I wrote up the exact mechanics in &lt;a href="https://veheria.tech/blog/claude-code-code-review-workflow/" rel="noopener noreferrer"&gt;a separate post on the review workflow&lt;/a&gt;; the point here is that this is where the measured 30 minutes came from, not from code generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The metric decided before deployment.&lt;/strong&gt; My biggest process mistake: I set the metric of record after the agents were already running, so for the first stretch I was tuning against a feeling. Decide what you are optimizing before an agent touches the workflow. For us it was review-cycle time held against review quality, not lines generated, not tickets closed. An agent optimizes exactly the proxy you hand it, so the proxy has to be the real goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A human owns every architectural decision.&lt;/strong&gt; Module boundaries, offline-first, when to break MVVM, when not to rewrite. The agent executes those decisions faster once a person has made them. It does not make them. On a Williams-Sonoma build I stood up a modular SwiftUI codebase so two shopping apps could share it; that call, and the taste behind it, is not something I would ever hand to a model. Agents scaled the wiring underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not work, and what I would do differently
&lt;/h2&gt;

&lt;p&gt;The ticket-speed agent is the clean example of the general failure: an agent with a prompt but no encoded intent will optimize the nearest measurable proxy and confidently ship the wrong thing. The fix is not a better model. It is encoding review taste and product intent into the workflow itself, the same standards a senior reviewer would apply, so the agent is pointed at the real goal instead of a number that correlates with it on a good day.&lt;/p&gt;

&lt;p&gt;The second thing I would change is trust calibration. Early on I let agents touch too much at once and spent the saved time re-reviewing their output, which defeats the purpose. Draw the line explicitly: what the agent is trusted to do unattended, what it drafts for a human to approve, and what it never touches. That line is the whole design. Get it wrong toward trust and you inherit debt; get it wrong toward caution and you built an expensive linter. The same boundary question runs through my whole &lt;a href="https://veheria.tech/blog/claude-code-ios-development/" rel="noopener noreferrer"&gt;Claude Code iOS workflow&lt;/a&gt;: the setup is an afternoon, deciding where the agent may make decisions is the months-long part.&lt;/p&gt;

&lt;h2&gt;
  
  
  A framework you can actually apply
&lt;/h2&gt;

&lt;p&gt;If you lead a team and want agents in the workflow without the theater, four questions in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What is slow because it is mechanical, not because it is hard?&lt;/strong&gt; That is your first candidate. Review triage, test scaffolding, changelog and release notes, flagging missing localization. Not architecture, not product decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the metric of record, decided now?&lt;/strong&gt; Write it down before anything runs. If you cannot name it, you are not ready to deploy an agent against it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where is the human explicitly in the loop?&lt;/strong&gt; Name what the agent does unattended, what it drafts for approval, what it never touches. This is a design decision, not a default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What did you standardize versus leave autonomous?&lt;/strong&gt; Standardize the few things that compound, the review bar and the definition of done, and leave the rest to the team. When I ran mentorship and review standards across EU locations, standardizing everything would have killed local ownership; standardizing nothing meant quality drifted. Agents make this sharper, because whatever you standardize, the agent will enforce relentlessly and literally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this requires a swarm architecture or a control plane. It requires taking one pattern you already trust by hand, deciding what you are measuring, and moving it onto a trigger with a clear human boundary. Start with the smallest mechanical task you are sure about. Measure it against the number you wrote down first. Expand only where the measurement earns it.&lt;/p&gt;

&lt;p&gt;The teams that get value from agents are not the ones with the most agents. They are the ones that kept judgment human and were honest about which of the two review jobs they were actually automating.&lt;/p&gt;

&lt;p&gt;If you are working out where agents fit in your team's workflow and want a second opinion from someone who has measured it on a real product, &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;that is what I do in a strategy session&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is the one mechanical task on your team that everyone hates and no one would miss doing by hand? That is almost always where to start.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/ai-agents-engineering-team-workflow/" rel="noopener noreferrer"&gt;veheria.tech/blog/ai-agents-engineering-team-workflow&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>engineering</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Claude Code Review Workflow That Saved 30 Minutes Per Engineer a Day</title>
      <dc:creator>Oleh Veheria</dc:creator>
      <pubDate>Sat, 22 Aug 2026 15:43:16 +0000</pubDate>
      <link>https://dev.to/5uper0/a-claude-code-review-workflow-that-saved-30-minutes-per-engineer-a-day-52bd</link>
      <guid>https://dev.to/5uper0/a-claude-code-review-workflow-that-saved-30-minutes-per-engineer-a-day-52bd</guid>
      <description>&lt;p&gt;Code review is where mobile teams quietly lose a day per engineer per week. Not writing reviews. Waiting for them. I put Claude Code agents into the actual review loop for a multinational iOS team as the first pass on every PR, and in my own measurement it saved about 30 minutes per engineer per day. Review-cycle time came down and review quality held. Human reviewers went back to arguing about what actually matters: design.&lt;/p&gt;

&lt;p&gt;This is the exact workflow, including the parts that didn't work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with human-first review
&lt;/h2&gt;

&lt;p&gt;Every PR review mixes two very different jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mechanical verification.&lt;/strong&gt; Does it build, are edge cases handled, is the naming consistent, did anyone forget to localize a string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Judgment.&lt;/strong&gt; Is this the right abstraction, does it fit where the module is heading, will this bite us in six months.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Humans are slow at the first and irreplaceable at the second. Classic review forces senior engineers to do both, so the mechanical part crowds out the judgment part. Reviewers skim, LGTM, and the architectural drift accumulates one skimmed PR at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow
&lt;/h2&gt;

&lt;p&gt;I run Claude Code as a &lt;strong&gt;first-pass reviewer&lt;/strong&gt; on every PR, before any human looks at it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Agent review on PR open
&lt;/h3&gt;

&lt;p&gt;A multi-agent review fans out over the diff, one agent per dimension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Correctness:&lt;/strong&gt; edge cases, nil-handling, concurrency. The classics that slip through when a human skims 400 changed lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; does the code match surrounding patterns, naming, error-handling idioms, module conventions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests:&lt;/strong&gt; do the tests actually cover the behavior change, or do they just mirror the implementation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;i18n and accessibility&lt;/strong&gt; (mobile-specific): hardcoded strings, missing Dynamic Type support, touch targets under 44pt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each finding has to cite a file and line and describe a concrete failure scenario. A finding with no failure scenario gets dropped. That single rule is what keeps the output from turning into "consider improving readability" noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Author fixes before human review
&lt;/h3&gt;

&lt;p&gt;The author gets findings in minutes, not hours. Mechanical issues die before a senior engineer ever context-switches into the PR. By the time a human opens it, the diff is clean enough that the review is about design.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Human review, redefined
&lt;/h3&gt;

&lt;p&gt;Human reviewers now have one job: judgment. Module boundaries, API shape, whether this feature belongs here at all. The stuff I wrote about in &lt;a href="https://veheria.tech/blog/ios-architecture-decisions-ai-cant-make/" rel="noopener noreferrer"&gt;iOS Architecture Decisions AI Can't Make&lt;/a&gt; is still 100% human, and now it actually gets the attention it needs instead of losing the reviewer's last hour to a missing nil check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auto-merge on green agent review.&lt;/strong&gt; This is the one I regret shipping first. An agent with a prompt but no encoded intent optimizes the nearest proxy, "tests pass", not the real goal, "this change is correct and worth merging". It happily green-lit changes that satisfied the letter of the tests and missed the point. I pulled auto-merge and put a human back on the merge button. The agent advises, the human decides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One mega-agent instead of dimensions.&lt;/strong&gt; A single "review everything" pass produces shallow findings. Fan-out with narrow lenses is what surfaces the real bugs. The correctness agent is not distracted by naming, so it actually reasons about concurrency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploying the agents before I had a metric of record.&lt;/strong&gt; I measured the 30 minutes after the fact and had to reconstruct the baseline. I should have agreed the number I cared about, and how I would measure it, before the first agent ran. If I did this again, that would be step zero. I made the same mistake again at a much smaller scale shipping &lt;code&gt;llms.txt&lt;/code&gt; on this site, &lt;a href="https://veheria.tech/blog/llms-txt-implementation/" rel="noopener noreferrer"&gt;and what I'd do differently there&lt;/a&gt; is the same fix: decide how you'll know it worked before you ship it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually measured
&lt;/h2&gt;

&lt;p&gt;I am only going to quote what I measured, because a post like this lives or dies on that. On that multinational iOS team, over months of daily use: about 30 minutes saved per engineer per day, review-cycle time down, and review quality held (the human bar did not drop when the mechanical pass moved to an agent). I did not instrument escaped-defect rate or reclaimed senior hours cleanly enough to quote them, so I won't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start
&lt;/h2&gt;

&lt;p&gt;Don't automate your whole review culture in a week. Start with one dimension (consistency is the safest), one repo, findings as suggestions, not gates. Keep the human on the merge button. Expand only when the team starts trusting the signal on its own. The review loop is one instance of a broader pattern; I wrote up how to choose and bound the rest in &lt;a href="https://veheria.tech/blog/ai-agents-engineering-team-workflow/" rel="noopener noreferrer"&gt;AI agent workflows for engineering teams&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want help setting up an AI-assisted engineering workflow for your team, the architecture, the tooling, and the change management around it, that is exactly what I do in &lt;a href="https://veheria.tech/work/" rel="noopener noreferrer"&gt;strategy sessions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One question I am still working out: where is the line for you between an agent that advises and an agent you would actually let merge? I have not found a team comfortable moving that line yet, and I would like to know if yours is.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://veheria.tech/blog/claude-code-code-review-workflow/" rel="noopener noreferrer"&gt;veheria.tech/blog/claude-code-code-review-workflow&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>ios</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
