<?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: Grant PS</title>
    <description>The latest articles on DEV Community by Grant PS (@grantps).</description>
    <link>https://dev.to/grantps</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%2F4047885%2Fbf5e0e9a-03bc-49c3-b7ff-d29b167b6108.png</url>
      <title>DEV Community: Grant PS</title>
      <link>https://dev.to/grantps</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grantps"/>
    <language>en</language>
    <item>
      <title>Engineers Are Becoming Mechanics</title>
      <dc:creator>Grant PS</dc:creator>
      <pubDate>Fri, 13 Nov 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/grantps/engineers-are-becoming-mechanics-48ip</link>
      <guid>https://dev.to/grantps/engineers-are-becoming-mechanics-48ip</guid>
      <description>&lt;p&gt;Every engineer I know is trying to work out where they fit now. One camp says engineering is dead. The other says fundamentals matter more than ever. I don't think either camp has it quite right, and I want to put down a prediction, so I can reflect on it later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bar has moved
&lt;/h2&gt;

&lt;p&gt;Things that used to need an engineer don't anymore. A personal website, a small web app, an internal tool: someone with an idea and an AI model can build it themselves, and it will comfortably handle the load that a personal site or small business actually sees. Tell the model "my site is slow" and it will go and find out why.&lt;/p&gt;

&lt;p&gt;That's not a toy. The models lay down a genuinely decent foundation. How far a non-engineer can take an idea, without real engineering practices and without an engineer looking at it, has gone up a lot, and it keeps going up.&lt;/p&gt;

&lt;p&gt;And it isn't only the models. People are now sharing basic agentic harnesses: starter kits with the conventions, checks and guardrails an engineer would have put in place. A non-engineer can pick one up and get a sensible setup on day one. Depending on what they're building, they may never need an engineer at all. The harness raises the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "we'll just do more" argument
&lt;/h2&gt;

&lt;p&gt;The optimistic counterargument is that engineers won't shrink, we'll just do ten or a hundred times more.&lt;/p&gt;

&lt;p&gt;I don't buy it, and the reason isn't technical. Maybe you can now engineer a hundred ideas. But someone still has to hold each idea in their head, see it through, put it in front of the market, watch what happens, and iterate. That's product work, and it runs on human attention.&lt;/p&gt;

&lt;p&gt;My guess, and it is a guess, is that a person can take on maybe five times more than before. Not a hundred. The build capacity has exploded, but the thinking capacity hasn't. So demand for engineering doesn't grow to match supply. It shrinks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineers as a luxury item
&lt;/h2&gt;

&lt;p&gt;Here's where I think it goes. Having full-time engineers becomes a luxury. Only the biggest companies, the ones that can afford to overspend or that run at genuinely critical load, will keep them in-house. And even there, the numbers will come down.&lt;/p&gt;

&lt;p&gt;Think about cars. Almost everyone drives, but almost nobody employs a mechanic. Only a company with a big fleet keeps mechanics on staff. Everyone else takes their car to a workshop.&lt;/p&gt;

&lt;p&gt;And plenty of people will happily drive a car with a rattle or a warning light on, as long as it gets them where they want to go. Software will be the same. A lot of products will run with faults nobody ever fixes, and that will be fine for their owners.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workshop model
&lt;/h2&gt;

&lt;p&gt;Agencies aren't new. Workshops have always existed, and plenty of engineers already work in them. What I think changes is where most engineers sit. Today the majority work in-house on a single product, and agencies are the smaller side of the industry. I think that flips.&lt;/p&gt;

&lt;p&gt;We're going to see a lot more agencies, and engineers will centralise into them. Most will stop working on one product and start working like mechanics.&lt;/p&gt;

&lt;p&gt;Someone brings their product into the workshop. The engineers look at where the AI keeps getting stuck, tune the agentic harness, fix the problems, put the current best practices in place, and send it back out. Then they might not see that product again for a year.&lt;/p&gt;

&lt;p&gt;And then, like a car, it comes back for its annual service. The engineers check it's still following best practice, talk through the problems the owner has hit, and bring it up to date with whatever the industry has learned since.&lt;/p&gt;

&lt;p&gt;This is where the shared harness comes back in. The workshop is for when the off-the-shelf harness stops being enough, and the annual service is where you swap in the latest harness.&lt;/p&gt;

&lt;p&gt;And it works the other way too. Every repair teaches the workshop something. When the same fault keeps coming through the door, the engineers fix it in the harness itself, the way car makers learn from what garages keep seeing and fix it in the next model. A workshop that sees hundreds of products learns faster than any single team or any static starter kit, so its harness stays ahead.&lt;/p&gt;

&lt;p&gt;The analogy isn't perfect. Software changes faster than cars do, so I'd expect plenty of these relationships to be retainers rather than one-off visits: a mechanic you can call, not just one you book. But the shape is the same. The engineer is outside the business, serving many clients, and the business model is the agency model: your income depends on how many cars come through the door.&lt;/p&gt;

&lt;p&gt;Yes, some people will never bring their car in. But that lower starting point also means far more drivers than before. More people building products means more products that eventually hit something the harness can't handle. So in a sense it balances out: fewer in-house engineers, but a lot more cars on the road needing the occasional mechanic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for engineers
&lt;/h2&gt;

&lt;p&gt;If I'm right, the question for an engineer isn't "will AI replace me". It's "do I want to work in a fleet garage or a high street workshop". The skills that matter shift towards diagnosis, towards knowing current best practice across many codebases, and towards being good at getting a stranger's product healthy quickly.&lt;/p&gt;

&lt;p&gt;That's my prediction. I could be wrong, and I'd like to hear why. But I'm looking at what people around me can now build without me, and this is the picture I keep coming back to.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>engineering</category>
      <category>career</category>
      <category>agents</category>
    </item>
    <item>
      <title>Align on the what. Let the tooling handle the how.</title>
      <dc:creator>Grant PS</dc:creator>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/grantps/align-on-the-what-let-the-tooling-handle-the-how-5g9l</link>
      <guid>https://dev.to/grantps/align-on-the-what-let-the-tooling-handle-the-how-5g9l</guid>
      <description>&lt;p&gt;I asked Codex to add a rule to a project's AGENTS.md, and to get aligned with me before touching the file. The rule: any development is done by sub-agents, and another sub-agent reviews the changes.&lt;/p&gt;

&lt;p&gt;It read AGENTS.md and the docs, wrote a short ledger, and came back with one question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The goal is to make delegation and independent review mandatory in AGENTS.md. I propose:

  • All repository changes, including docs and configuration, are implemented by sub-agents.
  • The primary agent coordinates the work.
  • A separate sub-agent reviews the changes, and findings are addressed before completion.
  • This update follows that process too. Only AGENTS.md changes; no commit or push.

I'll choose the wording and placement.

Q1: Does that match your intent?

  1. Yes, apply to all repository changes.
  2. Apply only to application code.

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

&lt;/div&gt;



&lt;p&gt;I had typed "any development". I hadn't thought about whether a one-line README fix counts as development. That question made me stop and work out what I actually meant.&lt;/p&gt;

&lt;p&gt;I went with all repository changes, because I was curious how well that would work.&lt;/p&gt;

&lt;p&gt;That's the whole idea behind two skills I've been using. &lt;code&gt;get-aligned&lt;/code&gt; interviews me about the goal and outcome. &lt;code&gt;auto-alignment-before-action&lt;/code&gt; checks for gaps before the agent changes anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agree on the what, leave the how
&lt;/h2&gt;

&lt;p&gt;When I work with an agent, I want us to agree on the outcome: the goal, what will be different when it's done, what's in and out of scope, and how I'll know it worked. How it gets built is the agent's call.&lt;/p&gt;

&lt;p&gt;That only works because I'm not relying on the agent's taste for the how. Linters catch style. A mutation gate catches tests that don't really test anything. &lt;a href="https://github.com/NEXL-LTS/agent-apropos" rel="noopener noreferrer"&gt;agent-apropos&lt;/a&gt; injects the project's conventions at the moment the agent touches a file they apply to. If the implementation comes out wrong in a way none of those catch, that's a gap in the harness, and I fix the harness.&lt;/p&gt;

&lt;p&gt;Without that layer I'd have to review the how myself, and then I'd want to agree on it up front too. With it, my attention goes where tooling can't help: what I actually mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only ask what changes the outcome
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;get-aligned&lt;/code&gt; interviews me one multiple-choice question at a time, with its recommendation first so I can accept in a click. Before it asks anything, it checks two things. Could it find the answer itself? Would a different answer change what I end up with? If it can look the answer up, it does. If the answer wouldn't change the outcome, it decides.&lt;/p&gt;

&lt;p&gt;Look at the Codex exchange again. It read the files before asking. It said "I'll choose the wording and placement" instead of asking me where the rule should go. One question survived, and it was about scope.&lt;/p&gt;

&lt;p&gt;When an implementation question does matter, it asks about the consequence, not the mechanism: "should a reviewer see every retry?" rather than "should retries get their own table?"&lt;/p&gt;

&lt;h2&gt;
  
  
  A gate before anything changes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;auto-alignment-before-action&lt;/code&gt; runs before the agent changes state: editing files, running commands with side effects, committing, publishing. It silently checks the goal, outcome, scope, constraints and what "done" means. Every answer has to trace back to something I said or a settled source like AGENTS.md. An answer it inferred doesn't count.&lt;/p&gt;

&lt;p&gt;If there's a gap, it asks one question, or runs a full &lt;code&gt;get-aligned&lt;/code&gt; session for anything bigger or hard to undo. If there's no gap, it opens with one line naming what it's about to produce. That line is my last cheap chance to stop it.&lt;/p&gt;

&lt;p&gt;It also lists its out clauses up front, so we agree which problems it hands back and which it solves. This is a made-up example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Out clauses:
- npm registry unreachable → stop and tell you
- lint fails on files I didn't touch → leave them, mention at the end
- feed validator rejects the dates → I'll fix the formatting myself

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

&lt;/div&gt;



&lt;p&gt;After that it keeps going. It only stops mid-task for a blocker an out clause says to hand back, or before changing the outcome we agreed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try them
&lt;/h2&gt;

&lt;p&gt;I've been tuning these in my personal repo &lt;a href="https://github.com/grantspeelman/skills" rel="noopener noreferrer"&gt;grantspeelman/skills&lt;/a&gt;, alongside a dev container skill and &lt;code&gt;unslop&lt;/code&gt;. If the idea fits how you want to work, install mine to try it, or build your own tweaked version.&lt;/p&gt;

&lt;p&gt;If you catch yourself reviewing implementation details your linters could have caught, that's a harness problem. If you catch yourself reviewing a correct implementation of the wrong thing, that's an alignment problem. These two skills are my fix for the second one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>skills</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>I gave an AI agent three hours to build my blog</title>
      <dc:creator>Grant PS</dc:creator>
      <pubDate>Mon, 05 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/grantps/i-gave-an-ai-agent-three-hours-to-build-my-blog-17h9</link>
      <guid>https://dev.to/grantps/i-gave-an-ai-agent-three-hours-to-build-my-blog-17h9</guid>
      <description>&lt;p&gt;I gave an AI agent a written plan and a three-hour budget. This is everything it took to get this site live.&lt;/p&gt;

&lt;p&gt;I was about to write another blog post and realised that I can now have my own custom blog with minimal effort. Until now my writing has lived on Medium, in NEXL Engineering, and more recently on dev.to. Both work fine, but I don't have absolute creative freedom over the URL, design or how the article appears on the page.&lt;/p&gt;

&lt;p&gt;So I moved it to my own domain. Rather than pick a platform, I made it an experiment. Can an AI agent build a personal blog in an afternoon, with a publishing workflow I actually like?&lt;/p&gt;

&lt;p&gt;This post is the first one on the blog it describes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the plan first
&lt;/h2&gt;

&lt;p&gt;Before the agent wrote any code, I had Claude interview me with a grill-me skill until we agreed on how the blog should work. The result was &lt;code&gt;PLAN.md&lt;/code&gt;: seventeen settled decisions, each chosen over the alternatives I turned down. That interview is the part of this build anyone can copy, because changing your mind during an interview costs nothing. The plan splits the work into eight phases and lists what the agent is not allowed to do. One phase ends with a checkpoint where the agent has to stop and wait for me.&lt;/p&gt;

&lt;p&gt;The core idea fits in four lines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markdown is the source of truth for every post.&lt;/li&gt;
&lt;li&gt;The agent writes each page's HTML by hand from that markdown, following a design brief. There is no static site generator and no template.&lt;/li&gt;
&lt;li&gt;Plain Ruby scripts build everything that must be exact, which is the RSS feed, the sitemap and a fidelity guard.&lt;/li&gt;
&lt;li&gt;Cloudflare serves the committed files as they are. The deploy has no build step and no API keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second point is the unusual one. Because the agent writes every page by hand, each post can get its own design touches. I can also redesign the whole site later by having the agent regenerate every page from the markdown, since no theme ties the pages together.&lt;/p&gt;

&lt;p&gt;It also means I have to trust an agent with my words, which is why the guard exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  A guard for my words
&lt;/h2&gt;

&lt;p&gt;The plan tells the agent never to alter, add to, reorder or omit my prose. I have written before about how often agents forget instructions like that, so I didn't rely on it.&lt;/p&gt;

&lt;p&gt;The fidelity guard renders the markdown, pulls the post body out of the agent's HTML, and compares the two block by block. It checks headings, paragraphs, list items and every line of code. Whitespace may change and nothing else may. If a curly quote turns straight or a code line goes missing, the guard fails and prints a diff that shows the agent what to fix.&lt;/p&gt;

&lt;p&gt;The guard runs in a pre-commit hook, so neither the agent nor I can commit a page that changes my words. In the end-to-end test, it blocked a commit where one word on the page differed from the markdown.&lt;/p&gt;

&lt;p&gt;Later the home page intro got the same treatment. A redesign rewrites the home page, so the intro now has its own markdown file and the guard checks it too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three designs, then a fourth
&lt;/h2&gt;

&lt;p&gt;The checkpoint was the design. The agent built three directions, each with a home page and a sample post. One was an editorial serif, one was an engineering notebook, and one was loud, in cobalt, coral and lemon.&lt;/p&gt;

&lt;p&gt;I asked for a fourth that combined the notebook with the loud one, then picked the original notebook anyway. I had two conditions, mobile first and proper web accessibility. The agent rewrote the stylesheet mobile first and worked through the accessibility details one at a time. The blinking cursor now stops after four blinks, and screen readers skip the decorative shell prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the guard could not see
&lt;/h2&gt;

&lt;p&gt;This was the most useful lesson of the build.&lt;/p&gt;

&lt;p&gt;The guard proves the words are right, but it can't tell whether the page reads well. Screenshots at phone and desktop width found eight bugs that no text check would catch. Four of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paragraphs had no gap between them, because one CSS rule outranked another on specificity.&lt;/li&gt;
&lt;li&gt;My name overflowed the screen on a phone.&lt;/li&gt;
&lt;li&gt;The font had no glyph for a non-breaking hyphen.&lt;/li&gt;
&lt;li&gt;Code ligatures merged &lt;code&gt;#{&lt;/code&gt; into a single glyph, so the code on screen didn't match the code in the post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the agent wrote a second checker, &lt;code&gt;bin/check-pages&lt;/code&gt;. It runs axe-core accessibility checks in light and dark mode, checks for sideways scrolling at three widths, and saves screenshots that the agent has to look at before it hands me a page. The plan never asked for it, and I'd now keep it over almost anything else in the repo.&lt;/p&gt;

&lt;p&gt;In its build log the agent wrote that it should have built the screenshot checker in phase 2 instead of phase 5. I agree. I made the same point in &lt;a href="https://dev.to/grantps/tooling-every-ai-software-harness-should-have-4512"&gt;my tooling post&lt;/a&gt;, that a tool only helps if the agent reads its output.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;The build took 2 hours 35 minutes of wall time, including the time the agent spent waiting for me to pick a design. That left 25 minutes of the budget. At the end the repo had 42 passing tests and a pre-commit hook proven against every failure case in the plan. It also had two Claude Code skills, &lt;code&gt;/publish&lt;/code&gt; and &lt;code&gt;/regenerate-site&lt;/code&gt;, and a finished site that nobody could see yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it live
&lt;/h2&gt;

&lt;p&gt;I decided to set up Cloudflare myself, since it was simple enough to do by hand. The agent walked me through it and checked each step from its side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I think more people will build their own
&lt;/h2&gt;

&lt;p&gt;One thought kept coming back while I did this.&lt;/p&gt;

&lt;p&gt;I could have used Medium, Ghost, WordPress, or a static site generator with a theme. Any of them would have worked, and each would have made me accept someone else's idea of what a blog is.&lt;/p&gt;

&lt;p&gt;What I have instead matches how I want to work. I write in markdown, and a guard I can read checks every page against it. The agent can redesign every page without touching a post, and the deploy just copies files. No product will add that combination to its roadmap, because I'm probably the only person who wants exactly this.&lt;/p&gt;

&lt;p&gt;Building your own used to cost weeks of evenings, and next to that a monthly subscription looked cheap. Now it costs an afternoon of agent time and a plan worth following, and I think that changes the answer for a lot of people.&lt;/p&gt;

&lt;p&gt;I expect more and more people to build their own software instead of buying off the shelf. I don't think that holds for everything. When many people share the same problem and mistakes are expensive, a product built and maintained by a team will still win. For the tools closest to how you work every day, I think building your own will become the default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this costs
&lt;/h2&gt;

&lt;p&gt;Building your own has real costs, and I don't want to skip them.&lt;/p&gt;

&lt;p&gt;I own all of it. If something breaks or needs a security fix, no vendor will do it for me. I kept that small on purpose, since the site is static files with no server code and no database. A bigger system would cost a lot more to look after.&lt;/p&gt;

&lt;p&gt;The plan did a lot of the work. The agent moved fast because I had already made the decisions. Without the plan, I would have made those same decisions halfway through the build, when each one costs more to change.&lt;/p&gt;

&lt;p&gt;I also had to build my trust in the site myself. The guard and the page checks were a large part of the engineering, and without them I'd be reviewing every page by eye.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves things
&lt;/h2&gt;

&lt;p&gt;The site is live at grant-ps.com, and the source is public at &lt;a href="https://github.com/grantspeelman/grant-ps.com" rel="noopener noreferrer"&gt;github.com/grantspeelman/grant-ps.com&lt;/a&gt;. Every post links to the markdown it was generated from. Next, dev.to will import posts from the RSS feed and point back to this site as the original. After that I want to build an editor app, and that will be the second post.&lt;/p&gt;

&lt;p&gt;It's a wonderful feeling to be able to dream up something and see it come to life within a few hours. If you've put off building your own version of something because an off-the-shelf one was close enough, it might be worth another look. Happy coding.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>blogging</category>
      <category>cloudflare</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Tooling every AI software harness should have</title>
      <dc:creator>Grant PS</dc:creator>
      <pubDate>Sat, 22 Aug 2026 16:08:43 +0000</pubDate>
      <link>https://dev.to/grantps/tooling-every-ai-software-harness-should-have-4512</link>
      <guid>https://dev.to/grantps/tooling-every-ai-software-harness-should-have-4512</guid>
      <description>&lt;p&gt;When an agent writes the code, you stop reading every line. You can pretend otherwise for a while, but on any real codebase you end up skimming a 600 line diff and approving it because nothing jumped out. Nothing jumping out is not the same as nothing being wrong.&lt;/p&gt;

&lt;p&gt;Documentation and a well tended CLAUDE.md only take you so far. The longer an agent runs, the more those instructions get crowded out of context and quietly forgotten. Instructions are advisory. Tooling is not.&lt;/p&gt;

&lt;p&gt;Two ideas run through everything below.&lt;/p&gt;

&lt;p&gt;The first is that the economics of enforcement have changed. Every quality threshold we set as an industry was really a judgement about how much human time it was worth spending. 100% branch coverage was not wrong, it was expensive, so we called it diminishing returns and settled at 80%. That cost is now paid in agent time, which is cheap and which you are not spending your evening on. Thresholds that were uneconomic five years ago are now just settings. Turn them up.&lt;/p&gt;

&lt;p&gt;The second is that a tool only counts if the agent sees the output. A linter that fails in CI thirty minutes after the agent stopped is a message to you. A linter the agent runs itself, reads, and fixes before you ever see the branch is part of the harness. Same tool, completely different value. Everything on this list should be reachable by the agent with one command, and should fail loudly enough that it cannot be ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The obvious one, but push it further than you would for a human team. Have a testing framework, and set minimum line and branch coverage to 100%.&lt;/p&gt;

&lt;p&gt;That number is doing something specific. At 80%, an agent will happily leave the awkward branch untested, because the awkward branch is exactly the one that is annoying to set up. At 100% there is no judgement call left to get wrong, and no negotiation to have.&lt;/p&gt;

&lt;p&gt;On an older codebase this is not feasible in one go. What does work is applying the 100% minimum only to files touched in a PR. Coverage ratchets up as the agent works through the code, and you get the high standard on new work immediately.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://rspec.info/" rel="noopener noreferrer"&gt;https://rspec.info/&lt;/a&gt; and &lt;a href="https://github.com/simplecov-ruby/simplecov" rel="noopener noreferrer"&gt;https://github.com/simplecov-ruby/simplecov&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutation testing
&lt;/h2&gt;

&lt;p&gt;Agents love writing code. Left alone they add checks that look defensive and do nothing. An empty check before looping over an array is the classic: looping over an empty array already does nothing, at the same speed, so the check is pure noise that a reviewer now has to read and reason about.&lt;/p&gt;

&lt;p&gt;Coverage will not catch this. The line is executed by your tests, so it counts as covered. Mutation testing will, because it changes that line and finds no test cares. It is the only tool I know that answers both halves of the question at once: is every concept actually covered by a test, and does every piece of code actually add value.&lt;/p&gt;

&lt;p&gt;Have a look at &lt;a href="https://stryker-mutator.io/docs/" rel="noopener noreferrer"&gt;https://stryker-mutator.io/docs/&lt;/a&gt; for the basics.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://github.com/mbj/mutant" rel="noopener noreferrer"&gt;https://github.com/mbj/mutant&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Type checking
&lt;/h2&gt;

&lt;p&gt;A quick win, and useful to agents in a way it is not to humans. An agent generating code from a half remembered API will produce a method call that looks entirely plausible and does not exist. Type checking closes that gap statically, before anything runs, and gives the agent a precise error to act on rather than a stack trace it has to interpret.&lt;/p&gt;

&lt;p&gt;Even dynamic languages have a route in now. TypeScript for JavaScript, Sorbet for Ruby.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://sorbet.org/" rel="noopener noreferrer"&gt;https://sorbet.org/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Linters and custom linters
&lt;/h2&gt;

&lt;p&gt;Every mature language has tooling that flags patterns that are outdated or actively harmful. This matters more with agents than it did with people, because an agent's instinct comes from its training data, and its training data is full of code written years ago. It will reach for the idiom that was correct in 2019 with total confidence.&lt;/p&gt;

&lt;p&gt;Rubocop catches exactly this. In a Rails codebase it will flag &lt;code&gt;Time.now&lt;/code&gt; where you want &lt;code&gt;Time.current&lt;/code&gt;, the timezone safe equivalent. That is not a style preference, it is a bug, and it is the sort of bug an agent will reintroduce every few weeks unless something stops it.&lt;/p&gt;

&lt;p&gt;There are linters for CSS, HTML, Go, JavaScript and most other things. If the language is mature, one exists.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://github.com/rubocop/rubocop" rel="noopener noreferrer"&gt;https://github.com/rubocop/rubocop&lt;/a&gt;, &lt;a href="https://github.com/Shopify/erb_lint" rel="noopener noreferrer"&gt;https://github.com/Shopify/erb_lint&lt;/a&gt;, &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;https://eslint.org/&lt;/a&gt;, &lt;a href="https://github.com/remarkjs/remark-validate-links" rel="noopener noreferrer"&gt;https://github.com/remarkjs/remark-validate-links&lt;/a&gt;, &lt;a href="https://github.com/hadolint/hadolint" rel="noopener noreferrer"&gt;https://github.com/hadolint/hadolint&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Security checkers
&lt;/h2&gt;

&lt;p&gt;Agents write insecure code. The saving grace is that they are insecure in well documented ways, because they learned it from existing codebases, and those mistakes already have detectors built for them. String interpolation into a query, a secret pasted into a config file, an over permissive workflow permission: all findable automatically.&lt;/p&gt;

&lt;p&gt;Non negotiable on any codebase where agents write a meaningful share of the code.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://brakemanscanner.org/" rel="noopener noreferrer"&gt;https://brakemanscanner.org/&lt;/a&gt;, &lt;a href="https://github.com/gitleaks/gitleaks" rel="noopener noreferrer"&gt;https://github.com/gitleaks/gitleaks&lt;/a&gt;, &lt;a href="https://github.com/zizmorcore/zizmor/" rel="noopener noreferrer"&gt;https://github.com/zizmorcore/zizmor/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Duplication detection
&lt;/h2&gt;

&lt;p&gt;Agents take copy paste to the next level, and this is one of the few problems that gets harder specifically because you did not write the code yourself. When you duplicate a block, you know you did it, and you feel the itch. When an agent does it in a file you have not opened, there is nothing to notice. The diff looks like new code, because to you it is.&lt;/p&gt;

&lt;p&gt;A detector gives you the thing your memory would have given you if you had been typing.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://jscpd.dev/" rel="noopener noreferrer"&gt;https://jscpd.dev/&lt;/a&gt; and &lt;a href="https://github.com/seattlerb/flay" rel="noopener noreferrer"&gt;https://github.com/seattlerb/flay&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hooks
&lt;/h2&gt;

&lt;p&gt;This is where the list turns into a harness.&lt;/p&gt;

&lt;p&gt;Every tool above is worth ten times more when the agent runs it, sees the failure, and fixes it, versus when it fails in CI and waits for you. Hooks are the cheapest way to force that, because they sit at points the agent cannot route around.&lt;/p&gt;

&lt;p&gt;The part worth taking advantage of is that there is more than one such point. An agent's work has natural stages, editing a file, committing, pushing, and you can attach different checks to each. Feedback is cheapest at the earliest stage where the check can meaningfully run, because the further the agent gets from the code it wrote, the more context it has to rebuild to fix it. So push each check as early as it will go, and let cost decide how much further it slides.&lt;/p&gt;

&lt;p&gt;Post edit is the tightest loop available. If your type checker is fast, run it here rather than waiting for the commit: the agent gets the error while the file it just wrote is still the thing it is thinking about, which is a much cheaper fix than discovering it three files later. Same for linters, if they are fast or can be pointed at a single file. Immediate feedback on one file beats a list of twenty violations at the end.&lt;/p&gt;

&lt;p&gt;Pre-commit is for anything that needs the whole change rather than one file, or is too slow to run on every edit. The full lint pass, the formatter, secret scanning, the fast part of the test suite.&lt;/p&gt;

&lt;p&gt;Pre-push is the last cheap stop before CI. Full tests, duplication detection, the slower security scanners. Getting a failure here still costs the agent a minute. Getting it from CI costs a round trip and usually costs you as well.&lt;/p&gt;

&lt;p&gt;Set up right, the agent commits, the hook fails, the agent reads the output and tries again, and you find out about none of it. Green CI first time, or at the very least the common problems caught before a human is involved.&lt;/p&gt;

&lt;p&gt;If you take one thing from this article, take this section.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://lefthook.dev/" rel="noopener noreferrer"&gt;https://lefthook.dev/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code formatters
&lt;/h2&gt;

&lt;p&gt;Worth having for the usual reason, that all code should look like one person wrote it. There is a second reason with agents: formatting noise is the enemy of skim reading, and skim reading is what you are now doing. Every gratuitous whitespace change is a line of diff competing for attention with a line that actually changed behaviour.&lt;/p&gt;

&lt;p&gt;Cheapest item on the list too, since most formatters auto correct without the agent needing to do anything.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://github.com/rubocop/rubocop" rel="noopener noreferrer"&gt;https://github.com/rubocop/rubocop&lt;/a&gt;, &lt;a href="https://prettier.io" rel="noopener noreferrer"&gt;https://prettier.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Just in time documentation injection
&lt;/h2&gt;

&lt;p&gt;Context is the scarce resource. Filling it with only what is needed is often the difference between an agent that acts smart and one that acts stupid, and the usual failure is not too little documentation but too much, loaded up front, crowding out the thing that mattered.&lt;/p&gt;

&lt;p&gt;So having a way to inject context only at the point the agent needs it is worth building. I could not find one that worked the way I wanted, so I wrote agent-apropos, which does just in time context injection across Claude Code, OpenCode, Gemini CLI and Copilot CLI.&lt;/p&gt;

&lt;p&gt;I use: &lt;a href="https://github.com/NEXL-LTS/agent-apropos" rel="noopener noreferrer"&gt;https://github.com/NEXL-LTS/agent-apropos&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom checkers
&lt;/h2&gt;

&lt;p&gt;If you have a practice that is non standard, or nuanced enough that no off the shelf tool encodes it, write your own. Most linters let you extend them with custom rules, and writing a standalone checker has never been easier, not least because you can get an agent to write it.&lt;/p&gt;

&lt;p&gt;This is also the highest leverage item here over time. The off the shelf tools encode what everyone knows. Custom checkers encode what your team knows, which is the part an agent has no other way of learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this costs
&lt;/h2&gt;

&lt;p&gt;Worth being straight about the trade offs, because they are real.&lt;/p&gt;

&lt;p&gt;Mutation testing is slow. It is not something you run on every commit on a large suite, and you will need to think about where in the workflow it fits.&lt;/p&gt;

&lt;p&gt;100% coverage can buy you test shaped noise if you are not careful, tests written to satisfy the threshold rather than to describe behaviour. Mutation testing is the counterweight, which is part of why those two belong together.&lt;/p&gt;

&lt;p&gt;Hooks that take too long will get bypassed, by you as much as by the agent. Keep the pre-commit set fast and push the slow things later.&lt;/p&gt;

&lt;p&gt;None of that changes the conclusion. It just means picking the order. If you are starting from nothing: hooks and a formatter first, because they cost almost nothing and make everything after them enforceable. Then coverage, then security. Mutation testing when you can afford it.&lt;/p&gt;

&lt;p&gt;Hopefully you, or your agent, found this useful.&lt;/p&gt;

</description>
      <category>agenticdev</category>
      <category>ruby</category>
      <category>software</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
