<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:media="http://search.yahoo.com/mrss/" >

<channel>
	<title>AI &#8211; Macronimous Blog</title>
	<atom:link href="https://www.macronimous.com/blog/category/ai/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.macronimous.com/blog</link>
	<description>Web design, web programming, Mobile apps, Opensource , SEO etc</description>
	<lastBuildDate>Wed, 21 Oct 2026 11:28:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>Spec-Driven Development: How We Use AI Without Gambling Your Budget</title>
		<link>https://www.macronimous.com/blog/spec-driven-development-with-ai/</link>
					<comments>https://www.macronimous.com/blog/spec-driven-development-with-ai/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 11:27:30 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Development]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[acceptance tests]]></category>
		<category><![CDATA[AI app development]]></category>
		<category><![CDATA[AI-assisted development]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[spec-driven development]]></category>
		<category><![CDATA[Vibe coding]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5425</guid>

					<description><![CDATA[<p>Spec-driven development with AI means you write the specification and the acceptance tests first, then let AI coding tools build against that document while an engineer checks every change. Vibe coding gets you a demo. A spec gets you a product someone is accountable for. For a paying client app, the spec is also what [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/spec-driven-development-with-ai/">Spec-Driven Development: How We Use AI Without Gambling Your Budget</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/10/Spec-Driven-Development-scaled.jpg"><img fetchpriority="high" decoding="async" width="2560" height="1352" src="https://www.macronimous.com/blog/wp-content/uploads/2026/10/Spec-Driven-Development-scaled.jpg" alt="Spec-Driven Development in the age of AI" class="aligncenter size-full wp-image-5433" /></a>
<div class="mac-direct-answer">
<p><strong>Spec-driven development with <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a></strong> means you write the specification and the acceptance tests first, then let <a href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">AI coding</a> tools build against that document while an engineer checks every change. <a href="https://www.macronimous.com/blog/is-vibe-coding-bad/">Vibe coding</a> gets you a demo. A spec gets you a product someone is accountable for. For a paying client app, the spec is also what keeps the budget from drifting.</p>
</div>
<div class="mac-toc">
<p class="mac-toc-title">What&#8217;s in this post</p>
<ul>
<li><a href="#demo-worked">The demo worked. Then somebody had to own it.</a></li>
<li><a href="#what-a-spec-is">What we mean by a spec</a></li>
<li><a href="#acceptance-tests">Acceptance tests are where &#8220;done&#8221; gets written down</a></li>
<li><a href="#how-we-build">How a spec-driven build runs at Macronimous</a></li>
<li><a href="#cost">Why the spec is the real cost saver</a></li>
<li><a href="#vibe-coding-wins">Where vibe coding still wins</a></li>
<li><a href="#comparison">Vibe coding vs spec-driven development</a></li>
<li><a href="#checklist">Is your spec ready? A short checklist</a></li>
<li><a href="#faq">FAQ</a></li>
</ul>
</div>
<h2 id="demo-worked">The demo worked. Then somebody had to own it.</h2>
<p>If you&#8217;ve been near software this year, you&#8217;ve seen one. Somebody opens a laptop, types a few sentences into an AI tool, and twenty minutes later there&#8217;s an app on the screen. It has a login page. It has a dashboard. The buttons do things. Everyone in the room is impressed, and honestly, they should be.</p>
<p>Then the questions start. What happens when two people edit the same record? Who decided the chatbot should answer pricing questions? Which version of this is the one we&#8217;re paying for? And nobody can answer, because there&#8217;s nothing to check the app against. There&#8217;s a chat history, and the chat history is the only record of what anyone wanted.</p>
<p>That&#8217;s the gap this post is about. We&#8217;ve built software for clients since 2002, and we build with AI every day now. What we won&#8217;t do is build a client&#8217;s product without a written spec. Here&#8217;s what that spec looks like, and why it&#8217;s the part of the project that saves you money.</p>
<h2 id="what-a-spec-is">What we mean by a spec</h2>
<p>Two definitions first, in plain words, because both terms get stretched.</p>
<p><strong>Vibe coding</strong> is prompting an AI until something seems to work, with no written plan and very little reading of the code it produces. Andrej Karpathy coined the term in February 2025, and the <a href="https://glossary.openssf.org/vibe-coding/" target="_blank" rel="noopener noreferrer">OpenSSF security glossary</a> puts the line in a sensible place: if a human reviews the AI-generated code, it isn&#8217;t vibe coding anymore.</p>
<p><strong>Spec-driven development</strong> is the opposite order. You write down what the software must do, and how you&#8217;ll prove it does it, before anyone (or anything) writes code. The AI then builds against that document. GitHub thinks the idea is solid enough that it published <a href="https://github.com/github/spec-kit" target="_blank" rel="noopener noreferrer">Spec Kit</a>, an open-source toolkit built around exactly this flow: specify, plan, break into tasks, implement.</p>
<p>A spec isn&#8217;t an 80-page requirements binder (we&#8217;ve written those, in the 2000s, and nobody read them). Ours are short, plain documents that cover features, user flows, the data model, the integrations, how any AI inside the product should behave, and the acceptance tests. Here&#8217;s a trimmed section from the kind of spec we&#8217;d write for a support assistant on a store. It&#8217;s an illustration, not a client document.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">## Feature: Order-status assistant

Purpose
The assistant answers order-status questions for signed-in customers.

Data it can read
- Orders for the signed-in customer only.
- The published shipping and returns policy pages.

Data it must not read
- Other customers' orders.
- Internal staff notes on any order.

AI behavior rules
1. Answer only from the order record and the policy pages.
2. If the answer is not in those sources, say so and offer a human handoff.
3. Never quote a refund amount. Link to the refund policy instead.
4. Never promise a delivery date that the carrier has not provided.

Done means
All acceptance tests AT-01 to AT-06 pass.</pre><p>&nbsp;</p>
<p>Notice what&#8217;s in there. Two rules say what the AI must <em>not</em> do. That&#8217;s the part a prompt almost never contains, because nobody thinks to ask for it until a customer gets a refund figure the chatbot made up.</p>
<h2 id="acceptance-tests">Acceptance tests are where &#8220;done&#8221; gets written down</h2>
<p>Most arguments on software projects aren&#8217;t about code. They&#8217;re about whether something is finished. The client thinks the feature is half done, the developer thinks it shipped last Tuesday, and both are right by their own definition.</p>
<p>Acceptance tests end that argument before it starts. Each one states a situation, an action, and the result you&#8217;ll accept. We write them in plain language first, so the client can read and sign them, and then engineers turn them into automated tests where it makes sense.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">AT-01  Given a signed-in customer with order #1042 marked "Shipped",
       when the customer asks "Where is my order?",
       then the assistant states "Shipped" and shows the carrier tracking link.

AT-03  Given a signed-in customer,
       when the customer asks about order #2077, which belongs to another customer,
       then the assistant refuses and reveals no detail of that order.

AT-05  Given a customer who asks "How much will my refund be?",
       when the assistant replies,
       then the reply contains no amount and links to the refund policy page.

AT-06  Given a question the sources cannot answer,
       when the assistant replies,
       then it says it does not know and offers a human handoff.</pre><p>&nbsp;</p>
<p>AT-03, AT-05 and AT-06 are wrong-answer tests. They check what the AI does when it shouldn&#8217;t answer. A demo never exercises those cases, because a demo is a sequence of questions somebody already knows will work. A product gets asked everything.</p>
<h2 id="how-we-build">How a spec-driven build runs at Macronimous</h2>
<p>This is the order every client build follows here, whether it&#8217;s a new AI app, an AI feature inside an existing Magento or <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> store, or one of the <a href="https://www.macronimous.com/services/ai-development/ai-automation-agency/">workflow automations we build</a> for operations teams.</p>
<ol>
<li>The client brings what they have. That can be a finished spec, a requirements document, a page of notes, or an idea explained on a call.</li>
<li>We turn it into a build-ready spec. If the client sent one, we review it and send back a gap list. Client specs usually arrive without acceptance tests or rules for AI behavior.</li>
<li>Senior engineers build against the spec with AI coding tools, Claude Code among them. The spec decides what gets built. The tool doesn&#8217;t.</li>
<li>An engineer reads every AI-written change and runs it against the acceptance tests before it goes in.</li>
<li>The spec stays with the client, in the client&#8217;s repository, as a working document.</li>
</ol>
<p>That last step matters more than it looks. When you add a phase next year, or move the work to another team (it happens, and we&#8217;d rather you could), the next people start from facts. They don&#8217;t start from a chat log and a guess.</p>
<p>I hold myself to the same order. I built <a href="https://thetamilbible.com/" target="_blank" rel="noopener noreferrer">TheTamilBible.com</a>, a PHP and MySQL web app you can install like a phone app, with Claude Code. It started as a written spec, not a prompt: navigation from Testament down to verse, search, light and dark themes, and offline reading. The AI wrote most of the code. The spec is why the result is the app I meant to build and not the app the AI guessed I wanted.</p>
<p>We&#8217;ve written separately about the review discipline behind step four, which we call <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled AI coding</a>.</p>
<h2 id="cost">Why the spec is the real cost saver</h2>
<p>AI made code cheap. That&#8217;s real, and anyone who tells you otherwise is protecting an hourly rate. A screen that took two days now takes an afternoon.</p>
<p>But cheap code moves the expensive mistake somewhere else. The costly thing used to be writing the code. Now it&#8217;s building the wrong thing quickly, discovering it in month three, and paying to unpick features that three other features already depend on. Speed doesn&#8217;t help you there. It just gets you to the wrong place sooner.</p>
<div class="mac-key-point">
<p>When code is cheap, the expensive mistake is building the wrong thing fast. The spec is how you find that mistake while it still costs a conversation instead of a rebuild.</p>
</div>
<p>The spec also changes how you pay. Once it&#8217;s locked, we can send a fixed-price proposal priced line by line against it, so the scope and the price live in the same document. Without a spec, a fixed price is a guess dressed up as a commitment, and somebody pays for the guess later. Usually the client.</p>
<p>Security is the other cost that hides until it doesn&#8217;t. Veracode&#8217;s <a href="https://www.veracode.com/news/llms-are-getting-smarter-but-not-safer-veracode-2026-genai-code-security-report-finds-ai-generated-code-security-has-stalled-at-56%25-pass-rate/" target="_blank" rel="noopener noreferrer">2026 GenAI Code Security Report</a> found the models it tested passed its security tests 56 percent of the time on average, barely better than a year earlier. I don&#8217;t read that as &#8220;AI writes insecure code, so avoid it.&#8221; I read it as: unreviewed AI code needs something to be checked against. A spec with access rules written into it, like AT-03 above, is that something.</p>
<h2 id="vibe-coding-wins">Where vibe coding still wins</h2>
<p>None of this means vibe coding is wrong. I vibe code myself, and I&#8217;d be lying if I said otherwise. It&#8217;s the right call when:</p>
<ul>
<li>You&#8217;re testing whether an idea deserves a budget at all. A rough prototype answers that faster than any meeting.</li>
<li>You&#8217;re building an internal tool that a handful of people use, that touches no money, and that nobody will mind rebuilding.</li>
<li>You want to show a developer or an investor what you mean, in place of describing it.</li>
<li>You&#8217;re learning. Breaking things you built yourself is still the fastest way to understand them.</li>
</ul>
<p>The line is simple. Once the software handles real customers, real money, personal data, or anything a regulator cares about, it needs a spec. We wrote up where that line fell on one of our own builds in <a href="https://www.macronimous.com/blog/is-vibe-coding-bad/">&#8220;Is Vibe Coding Bad?&#8221;</a>, if you want the longer version.</p>
<p>And a vibe-coded prototype is a fine place to start a spec. It&#8217;s a sketch. We&#8217;ll happily write the spec from it.</p>
<h2 id="comparison">Vibe coding vs spec-driven development</h2>
<table class="styled-table">
<thead>
<tr>
<th>Question</th>
<th>Vibe coding</th>
<th>Spec-driven development</th>
</tr>
</thead>
<tbody>
<tr>
<td>What is the build checked against?</td>
<td>The builder checks whether it seems to work.</td>
<td>The engineer checks it against written acceptance tests.</td>
</tr>
<tr>
<td>Who defines &#8220;done&#8221;?</td>
<td>Nobody writes it down.</td>
<td>The client signs the tests that define it.</td>
</tr>
<tr>
<td>What happens to AI behavior rules?</td>
<td>They exist only if someone remembered to prompt them.</td>
<td>The spec lists them, including what the AI must refuse.</td>
</tr>
<tr>
<td>Can the price be fixed?</td>
<td>A fixed price is a guess.</td>
<td>The price is set line by line against the locked spec.</td>
</tr>
<tr>
<td>What does a new team inherit?</td>
<td>The new team inherits code and a chat history.</td>
<td>The new team inherits code and the document that explains it.</td>
</tr>
<tr>
<td>Where does it fit best?</td>
<td>It fits prototypes, experiments and small internal tools.</td>
<td>It fits products that real customers and real money depend on.</td>
</tr>
</tbody>
</table>
<h2 id="checklist">Is your spec ready? A short checklist</h2>
<p>If you already have a spec, run it against this list before you send it to any team, us or anyone else.</p>
<ul class="mac-checklist">
<li>Every feature names the user who uses it and what that user is trying to do.</li>
<li>The data model lists each record type and who can read or change it.</li>
<li>Every integration says what happens when the other system is down or slow.</li>
<li>Any AI feature lists its sources, and what it must refuse to answer.</li>
<li>Each feature has at least one acceptance test written as given, when, then.</li>
<li>At least one test per AI feature checks a wrong or unanswerable question.</li>
<li>The spec states what is out of scope for this phase.</li>
</ul>
<h2 id="faq">FAQ</h2>
<div id="ai-wordpress-faq">
<div class="faq-item">
<h3>What is spec-driven development with AI?</h3>
<p>It&#8217;s a way of building software where the specification and acceptance tests come first, and AI coding tools build against them. An engineer reviews each AI-written change and runs it against the tests before it goes in. The spec stays with the client as the record of what the product must do.</p>
</div>
<div class="faq-item">
<h3>What is the difference between vibe coding and spec-driven development?</h3>
<p>Vibe coding prompts an AI until something seems to work, with no written plan to check it against. Spec-driven development writes the plan and the tests first. Vibe coding is good for prototypes and experiments. Spec-driven development is what a product needs once customers or money depend on it.</p>
</div>
<div class="faq-item">
<h3>Does writing a spec slow the project down?</h3>
<p>It adds days at the start and saves weeks later. AI tools build fast once they have clear instructions, and the spec is those instructions. The time you lose without one goes into rework, scope arguments and features nobody asked for.</p>
</div>
<div class="faq-item">
<h3>Can you build from a spec I already have?</h3>
<p>Yes. We read it first and send back a gap list, which usually covers missing acceptance tests and unclear AI behavior. Once you approve the fixes, the spec is locked and we send a fixed-price proposal. If you only have an idea, our Specification Building service writes the spec with you, and you own it outright.</p>
</div>
</div>
<h2 id="bottom-line">Where that leaves you</h2>
<p>Use AI to write the code. We do, every day. Just don&#8217;t let it decide what the code is for. That decision belongs in a document a person signed, and the document belongs to you. If you&#8217;ve run a spec-driven build with a different structure that worked better, I&#8217;d like to hear about it.</p>
<div class="mac-cta-box">
<h3>Have an idea or a draft spec for an AI app?</h3>
<p>Send what you have. We&#8217;ll tell you what&#8217;s missing from it, whether AI is the right tool, and how we&#8217;d price the build once the spec is locked.</p>
<p><a href="https://www.macronimous.com/services/ai-development/" class="mac-cta-button">Send Us Your Spec or Idea</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/spec-driven-development-with-ai/">Spec-Driven Development: How We Use AI Without Gambling Your Budget</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/spec-driven-development-with-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPress Alternatives for AI-Driven Websites: What to Consider Without Falling Into a Trap</title>
		<link>https://www.macronimous.com/blog/wordpress-alternatives-for-ai-driven-websites/</link>
					<comments>https://www.macronimous.com/blog/wordpress-alternatives-for-ai-driven-websites/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 06:48:06 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[AI Development]]></category>
		<category><![CDATA[Headless WordPress]]></category>
		<category><![CDATA[Kirby]]></category>
		<category><![CDATA[ProcessWire]]></category>
		<category><![CDATA[Statamic]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5427</guid>

					<description><![CDATA[<p>A good WordPress alternative for AI-driven websites is one your client can edit without help, a second developer can take over without guesswork, and an AI coding assistant can build and maintain from plain code. ProcessWire, Kirby and Statamic all qualify for small business sites. Judge them on those three things, not on how familiar [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/wordpress-alternatives-for-ai-driven-websites/">WordPress Alternatives for AI-Driven Websites: What to Consider Without Falling Into a Trap</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/10/WordPress-Alternatives-for-AI-Driven-Websites.jpg"><img decoding="async" width="2492" height="1316" src="https://www.macronimous.com/blog/wp-content/uploads/2026/10/WordPress-Alternatives-for-AI-Driven-Websites.jpg" alt="WordPress Alternatives for AI-Driven Websites" class="aligncenter size-full wp-image-5430" /></a>
<div class="mac-direct-answer">
<p><strong>A good <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> alternative for AI-driven websites</strong> is one your client can edit without help, a second developer can take over without guesswork, and an <a href="https://www.macronimous.com/blog/is-vibe-coding-bad/">AI coding</a> assistant can build and maintain from plain code. ProcessWire, Kirby and Statamic all qualify for small business sites. Judge them on those three things, not on how familiar the admin screen looks.</p>
</div>
<p>Twenty years ago we built our own CMS at Macronimous. It started in classic ASP, moved to ASP.NET, and we retired it when we moved our clients to WordPress and Drupal. It wasn&#8217;t a bad system. It just couldn&#8217;t keep up with a plugin ecosystem that was growing every week, and our clients didn&#8217;t want a CMS only we understood.</p>
<p>So it&#8217;s a little strange to be looking past WordPress again. But <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a> has changed the math. When a coding assistant can turn an approved design into templates in an afternoon, the things that made WordPress the safe default (themes, page builders, a plugin for everything) matter less. What matters more is everything that happens after launch.</p>
<p>This isn&#8217;t a ranking. We haven&#8217;t tested every CMS and we don&#8217;t intend to. It&#8217;s the list of things we now check before recommending anything that isn&#8217;t WordPress, plus what one real rebuild taught us.</p>
<h2>The first trap: judging a CMS by its admin screen</h2>
<p>We rebuilt <a href="https://www.promotefirst.com/" target="_blank" rel="noopener noreferrer">promotefirst.com</a>, our own small marketing site, on <a href="https://processwire.com/" target="_blank" rel="noopener noreferrer">ProcessWire</a>. Twenty pages, the same URLs, a contact form, an XML sitemap, and <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">SEO</a> fields on every page.</p>
<p>I logged in to the admin myself. My first reaction was that it looked a bit immature, and it reminded me of our old ASP.NET CMS. My second reaction, after an hour, was that I could live with it. It&#8217;s a plain page tree and plain forms. Nothing flashy, and nothing a client can break.</p>
<p>That first reaction is the trap. Anyone who has spent ten years in the WordPress dashboard will find every other admin &#8220;wrong&#8221; for a day or two. If you (or your client) can come at it without that prejudice, ProcessWire is a genuinely good alternative. If you can&#8217;t, no amount of technical merit will save the project, and it&#8217;s better to know that before you start.</p>
<h2>What one real rebuild actually showed us</h2>
<p>The design moved from static HTML to ProcessWire templates with no visual change at all. We checked that by screenshotting every page from both versions at phone and desktop widths and comparing them pixel by pixel. That&#8217;s possible because a ProcessWire template is just a PHP file that prints your HTML. There&#8217;s no theme layer adding its own markup.</p>
<p>The surprises were all in the details a client would hit:</p>
<ul>
<li><strong>The admin needed writing.</strong> Out of the box, field labels are developer labels. Every friendly name and hint (&#8220;Aim for 50 to 60 characters&#8221;) was written by hand. Budget for it.</li>
<li><strong>Images can fail in a confusing way.</strong> Images saved from many websites are WebP files with a .jpg name. ProcessWire trusts the file name, so the admin preview broke and showed &#8220;not a supported image type&#8221;. A client would assume the site was broken.</li>
<li><strong>Some basics cost extra.</strong> The official form builder and the full-page cache are paid Pro modules. That&#8217;s fair pricing, but it isn&#8217;t free like the WordPress equivalents.</li>
<li><strong>Staging behind a CDN needs care.</strong> Our password-protected test site sat behind Cloudflare, which cached a couple of files from it and served them publicly until we sent a &#8220;private&#8221; cache header. That&#8217;s a hosting lesson more than a CMS one, but every alternative you test will hit it.</li>
</ul>
<p>Our rough estimate for a developer new to ProcessWire: about 35 hours for a 20-page site the first time, against 25 to 30 for the same job in WordPress. The second project drops to around 20, because the setup script and templates carry over. Treat those as estimates from one project, not benchmarks.</p>
<h2>The second trap: pricing the licence and forgetting the people</h2>
<p>A free CMS can be the expensive choice. The real costs sit in three places: paid add-ons, the hours needed to make the admin friendly, and how many developers can maintain it after you.</p>
<table class="styled-table">
<thead>
<tr>
<th>Option</th>
<th>Built on</th>
<th>What you&#8217;ll pay for</th>
<th>Who can maintain it</th>
</tr>
</thead>
<tbody>
<tr>
<td>ProcessWire</td>
<td>PHP, MySQL</td>
<td>Free core; paid Pro modules for forms and caching</td>
<td>Any PHP developer, after a day of learning</td>
</tr>
<tr>
<td>Kirby</td>
<td>PHP, no database (content is files)</td>
<td>A paid per-site licence</td>
<td>Any PHP developer; content can live in Git</td>
</tr>
<tr>
<td>Statamic</td>
<td>Laravel (PHP 8.3+)</td>
<td>Free Core with one admin user; Pro is $349 per site</td>
<td>Developers with Laravel experience</td>
</tr>
<tr>
<td><a href="https://www.macronimous.com/blog/is-headless-wordpress-worth-it/">Headless WordPress</a></td>
<td>WordPress plus a JavaScript front end</td>
<td>Free software, but two codebases to host and maintain</td>
<td>Two skill sets, documented together</td>
</tr>
</tbody>
</table>
<p>Statamic deserves a note. It needs Laravel experience, which a WordPress-only team won&#8217;t have. That&#8217;s manageable, and Laravel developers are easy to hire, but check your hosting first. <a href="https://statamic.dev/requirements" target="_blank" rel="noopener noreferrer">Statamic requires PHP 8.3 or newer</a>, and the shared server we used for the ProcessWire trial was still on 8.2.</p>
<p>The people question is the one agencies skip. If the one developer who knows your chosen CMS leaves, your client is stuck. WordPress&#8217;s biggest advantage was never technical. It&#8217;s that you can hand a WordPress site to almost anyone.</p>
<h2>The third trap: forgetting who writes the code now</h2>
<p>Here&#8217;s the criterion that didn&#8217;t exist five years ago: how well can an AI coding assistant build and maintain this CMS?</p>
<p>It matters because more of the routine work (templates, field setup, content imports, fixes) now goes through an assistant, with a developer reviewing. A CMS where the important configuration lives in code is easy to work with that way. A CMS that&#8217;s mostly configured by clicking through admin screens isn&#8217;t, because an assistant can&#8217;t see those clicks, and neither can the next developer.</p>
<p>ProcessWire did well here. Every field, template, user role and imported page in our rebuild came from one script we could read, review and re-run. Kirby goes further, defining each page type in a short text file. We&#8217;ve written before about keeping <a href="https://www.macronimous.com/blog/controlled-ai-coding/">AI coding under control</a>, and the same rule applies: if you can&#8217;t review it as code, you can&#8217;t trust what the assistant did to it.</p>
<div class="mac-key-point">
<p>Pick the CMS whose setup you can read as code. That&#8217;s the one an AI assistant can maintain, and the one the next developer can understand.</p>
</div>
<h2>AI-generated HTML is a different problem</h2>
<p>There&#8217;s a second use case that keeps coming up. A client arrives with a site generated by an AI builder: clean enough HTML, no CMS, and they want to edit the text. Rebuilding it as CMS templates defeats the point of generating it.</p>
<p>For that, you want a tool that marks parts of existing HTML as editable instead of converting the whole site. Three worth a look, which we haven&#8217;t tested yet:</p>
<ul>
<li><strong>CouchCMS</strong> is self-hosted PHP. You wrap regions of your HTML in its tags and an admin appears (<a href="https://docs.couchcms.com/concepts/editable-regions.html" target="_blank" rel="noopener noreferrer">editable regions are explained in its docs</a>). It&#8217;s free, but the project is small.</li>
<li><strong>CloudCannon</strong> is hosted and Git-based. You add attributes to the HTML and clients edit directly on the page. It&#8217;s polished, and it&#8217;s a monthly subscription.</li>
<li><strong>Surreal CMS</strong> is hosted too. It connects to your existing server and lets clients click and type. There&#8217;s nothing to install.</li>
</ul>
<p>The question to ask all three: what happens when you regenerate the HTML next month? If the client&#8217;s edits vanish, the tool isn&#8217;t the answer. We compared AI builders and WordPress for search in an <a href="https://www.macronimous.com/blog/ai-website-builder-vs-wordpress-for-seo/">earlier post on AI website builders</a>, and editing after launch was the weak spot then too.</p>
<h2>Don&#8217;t close the door on WordPress</h2>
<p>Some people will tell you headless WordPress is pointless because newer headless systems are better. For a blank-page project, they may be right. But most sites don&#8217;t start from a blank page. They start with hundreds of posts, years of SEO metadata and an editorial team that already knows the dashboard.</p>
<p><a href="https://www.macronimous.com/services/cms-development/wordpress-to-headless/">Moving WordPress to a headless setup</a> keeps all of that and gives you a faster front end. It&#8217;s not the best headless CMS. It&#8217;s often the cheapest road to headless for a site that&#8217;s already on WordPress.</p>
<p>If you go that way, write the handoff document nobody writes: which WordPress fields and plugins the front end depends on, how a Publish reaches the live site, where the keys live, and how previews work. Without it, the next developer spends two weeks working out how the two halves talk. (Old WordPress sites carry their own <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">hidden technical debt</a>, so check that before you decide anything.)</p>
<h2>Before you pick a WordPress alternative for an AI-driven website</h2>
<ul class="mac-checklist">
<li>Have the client (not just the developer) use the admin for an hour before deciding.</li>
<li>List every paid add-on you&#8217;ll need: forms, caching, redirects, backups.</li>
<li>Check the hosting: PHP version, database, and whether a CDN sits in front.</li>
<li>Ask who else could maintain this site if your developer left.</li>
<li>Make sure fields, templates and roles are defined in code you can review.</li>
<li>Upload a real image from the client&#8217;s phone and from a website, and see what breaks.</li>
<li>Write down how a published change reaches the live site.</li>
</ul>
<p>For a 20-page business site that a client edits a few times a month, ProcessWire passed most of that list for us. For shops, plugin-heavy blogs, or clients who want to build their own layouts, we&#8217;d still choose WordPress. That&#8217;s the honest answer, and it&#8217;s the one we give clients.</p>
<div class="mac-cta-box">
<h3>Choosing between WordPress and an alternative?</h3>
<p>We&#8217;ll look at what your site needs after launch, who will edit it and who will maintain it, and recommend the platform that fits, even if that&#8217;s WordPress.</p>
<p><a href="https://www.macronimous.com/services/custom-web-development/" class="mac-cta-button">Get a platform recommendation</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/wordpress-alternatives-for-ai-driven-websites/">WordPress Alternatives for AI-Driven Websites: What to Consider Without Falling Into a Trap</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/wordpress-alternatives-for-ai-driven-websites/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Is Vibe Coding Bad? What a Real Invoice App Build Showed us</title>
		<link>https://www.macronimous.com/blog/is-vibe-coding-bad/</link>
					<comments>https://www.macronimous.com/blog/is-vibe-coding-bad/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Thu, 15 Oct 2026 06:31:46 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[agentic coding]]></category>
		<category><![CDATA[AI code review]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Vibe coding]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5416</guid>

					<description><![CDATA[<p>Is vibe coding bad? No. It&#8217;s a fast, cheap way to get a prototype or an internal tool working, and I use it most days. It goes wrong when the software has to follow rules the AI was never told about: tax law, money, permissions, two users at the same second. On our own invoice [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/is-vibe-coding-bad/">Is Vibe Coding Bad? What a Real Invoice App Build Showed us</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/10/Is-Vibe-Coding-Bad.jpg"><img decoding="async" width="1734" height="907" src="https://www.macronimous.com/blog/wp-content/uploads/2026/10/Is-Vibe-Coding-Bad.jpg" alt="Is Vibe Coding Bad" class="aligncenter size-full wp-image-5421" /></a>
<div class="mac-direct-answer">
<p><strong>Is <a href="https://www.macronimous.com/blog/testing-in-agentic-coding/">vibe coding</a> bad?</strong> No. It&#8217;s a fast, cheap way to get a prototype or an internal tool working, and I use it most days. It goes wrong when the software has to follow rules the <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">AI</a> was never told about: tax law, money, permissions, two users at the same second. On our own invoice app, four such problems came up. Each one looked like correct code, and each needed someone who knew the business to deal with it.</p>
</div>
<div class="mac-toc">
<p class="mac-toc-title">In this post</p>
<ul>
<li><a href="#what-it-is-good-at">Is vibe coding bad? It&#8217;s good at more than developers admit</a></li>
<li><a href="#the-app">The app: our own invoicing system</a></li>
<li><a href="#four-cases">Four things the AI got wrong, or would have</a></li>
<li><a href="#security">And vibe coding security risks?</a></li>
<li><a href="#comparison">A vibe coder alone vs. a seasoned developer using AI</a></li>
<li><a href="#replace-developers">Will AI replace web developers?</a></li>
<li><a href="#questions-to-ask">Questions to ask before you hand over a real system</a></li>
<li><a href="#faq">FAQ</a></li>
</ul>
</div>
<h2 id="what-it-is-good-at">Is vibe coding bad? It&#8217;s good at more than developers admit</h2>
<p>The pitch I keep hearing goes like this: AI writes the code now, so you don&#8217;t need web developers with ten or fifteen years behind them. You need one person who&#8217;s good at prompting.</p>
<p>I&#8217;m not going to tell you that&#8217;s nonsense, because half of it is true.</p>
<p>Vibe coding (Andrej Karpathy&#8217;s name for it, from early 2025) means describing what you want and accepting what the AI writes without reading much of it. For a prototype, or an internal tool that five people use, that&#8217;s fine. Better than fine. I&#8217;ve run a <a href="https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/">web development</a> company since 2002 and I build with Claude Code myself, and jobs that used to take my team two weeks now take an afternoon. Anyone who tells you the old way is still faster is protecting a rate card.</p>
<p>So the gap between a beginner with AI and a senior developer <em>is</em> shrinking, if you measure it by how much working code each can turn out in a day. Where it hasn&#8217;t shrunk is harder to see, and the only honest way I know to show it is with a real build. This will get a little technical (I&#8217;ll keep the code to one line, promise).</p>
<h2 id="the-app">The app: our own invoicing system</h2>
<p>Macronimous exports software services from India, which means our invoices follow rules that ordinary invoicing tools don&#8217;t model. We couldn&#8217;t find an off-the-shelf product that tied a bank&#8217;s remittance certificate to the invoice it paid, so we built our own in PHP and MySQL, with an AI agent doing most of the typing. It was quick. The code was clean.</p>
<p>I&#8217;ve already written up the full story for developers, with commits and diffs, in <a href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">our post on agentic coding mistakes</a>. What follows is the shorter version, for people who pay for software instead of writing it.</p>
<p>Four things happened. Not one of them threw an error.</p>
<h2 id="four-cases">Four things the AI got wrong, or would have</h2>
<h3>1. The Void button</h3>
<p>Ask any AI for invoicing software and it&#8217;ll handle a wrong invoice the way every accounting tutorial does: mark it void, keep the number, never delete anything. Ours built exactly that, with a button and a confirmation box, and it worked perfectly in the demo.</p>
<p>It was also wrong for us. In our reading of Indian GST (Goods and Services Tax), an issued tax invoice creates a liability whether you later mark it void or not. (That&#8217;s our working understanding, not tax advice; ask your accountant.) A wrongly issued invoice has to be removed and its proforma put back. I caught it in review, and only because I&#8217;ve lived with these rules for years. A perfectly good vibe coder who has never run an export business would have shipped it, and as far as I can tell the first sign of trouble would&#8217;ve been a notice from the tax department.</p>
<h3>2. The April 1 problem</h3>
<p>Here&#8217;s the one line of code I promised. It&#8217;s from the first version of the function that numbers our invoices:</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">return sprintf('%s-%s-%03d', $row['prefix'], date('Y', strtotime($issueDate)), $seq);</pre><p>&nbsp;</p>
<p>There&#8217;s nothing wrong with it. <code>date('Y')</code> is the calendar year, which is what most of the world wants. But India&#8217;s financial year starts on April 1, and our invoice numbers restart with it. The fix began with one sentence from me in review: &#8220;every business year, April 1st, we change the invoice numbers.&#8221;</p>
<p>You can&#8217;t find that bug by reading the code, because the code is correct. You find it by knowing something the code doesn&#8217;t.</p>
<h3>3. Two people, one invoice number</h3>
<p>This one I didn&#8217;t catch by knowing anything. I asked a question: what if someone on my team creates an invoice on their machine at the same moment I do?</p>
<p>Nobody knew. So we tested it with twelve at once, and eleven failed. The numbering code read the counter and then updated it in a second step, and under simultaneous writes MySQL <a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-deadlocks.html" target="_blank" rel="noopener noreferrer">deadlocks on that pattern</a> (two requests each wait for the other, and one gets thrown out). The fix was a single atomic statement, meaning one database command that reads and increments together so nothing can squeeze in between.</p>
<p>I&#8217;d love to say experience handed me the answer. It didn&#8217;t. It handed me the question, because I&#8217;ve seen &#8220;it works on my machine&#8221; turn into a support call before.</p>
<h3>4. The bug that was never written</h3>
<p>AI tools like to store a payment as a yes-or-no flag on the invoice. Ours never did, and I was half expecting it to. Before it wrote a line, our spec said every foreign payment must carry its FIRC (Foreign Inward Remittance Certificate, the bank&#8217;s proof that the money arrived from abroad). A yes-or-no flag can&#8217;t hold a certificate, so the AI built a proper payments table from the very first commit.</p>
<div class="mac-key-point">
<p>The only mistake that cost us nothing was the one the spec prevented, and the spec was written by someone who knew the business.</p>
</div>
<h2 id="security">And vibe coding security risks?</h2>
<p>Fair question, since security is what most people asking about vibe coding are really worried about. The four cases above aren&#8217;t security bugs. Two others from our internal apps are, and I&#8217;ll be straight with you: my notes don&#8217;t say who spotted them, so I&#8217;m not going to claim them for experience.</p>
<ul>
<li>A read-only &#8220;viewer&#8221; role showed up in the interface and was never enforced on the server. Viewers could create and delete records.</li>
<li>A spreadsheet export would have <a href="https://owasp.org/www-community/attacks/CSV_Injection" target="_blank" rel="noopener noreferrer">run a formula on opening</a> if a client&#8217;s name began with an equals sign.</li>
</ul>
<p>Both passed a click-through. And both are the sort of thing an AI won&#8217;t raise unless you ask, which you only do if you&#8217;ve been bitten.</p>
<h2 id="comparison">A vibe coder alone vs. a seasoned developer using AI</h2>
<p>Look at the heading on the third column before you read the table. It doesn&#8217;t say &#8220;developer without AI,&#8221; because that person is losing ground too. People frame this as vibe coding vs traditional coding, and I don&#8217;t think that&#8217;s the real choice anymore. Everyone&#8217;s using the AI. What differs is whether anybody who understands the business reads what comes out.</p>
<table class="styled-table">
<thead>
<tr>
<th>Area</th>
<th>Vibe coder alone</th>
<th>Seasoned developer using AI</th>
<th>What it costs you</th>
</tr>
</thead>
<tbody>
<tr>
<td>Requirements and business rules</td>
<td>Builds the textbook version of the prompt.</td>
<td>Knows where your industry or country differs.</td>
<td>Our Void button would have created a tax liability.</td>
</tr>
<tr>
<td>Architecture</td>
<td>Accepts the AI&#8217;s first design.</td>
<td>Weighs hosting cost and upkeep.</td>
<td>You outgrow the design and pay twice.</td>
</tr>
<tr>
<td>Database</td>
<td>Accepts the generated tables.</td>
<td>Checks indexes and simultaneous writes.</td>
<td>Eleven of twelve invoices failed in our test.</td>
</tr>
<tr>
<td>Performance</td>
<td>Fixes it when users complain.</td>
<td>Spots the expensive query before launch.</td>
<td>The slowdown arrives with your busiest week.</td>
</tr>
<tr>
<td>Security</td>
<td>Trusts the generated login and roles.</td>
<td>Logs in as each role and tries to misbehave.</td>
<td>Our &#8220;viewer&#8221; could delete records.</td>
</tr>
<tr>
<td>Testing</td>
<td>Runs the tests the AI offered.</td>
<td>Decides what&#8217;s risky and tests that.</td>
<td>Customers find the bugs for you.</td>
</tr>
<tr>
<td>Faults on the live site</td>
<td>Pastes the error back into the AI.</td>
<td>Reads the logs and finds the cause.</td>
<td>The outage runs longer than it should.</td>
</tr>
<tr>
<td>Existing code</td>
<td>Wants to rebuild it.</td>
<td>Can change a site somebody else built.</td>
<td>You fund a rebuild you didn&#8217;t need.</td>
</tr>
<tr>
<td>Search visibility</td>
<td>Ships pages that only render in the browser.</td>
<td>Checks what Google and AI crawlers receive.</td>
<td>The site works and nobody finds it.</td>
</tr>
<tr>
<td>Ownership</td>
<td>Says the AI wrote it.</td>
<td>Signs off on it.</td>
<td>There&#8217;s nobody to call when it breaks.</td>
</tr>
</tbody>
</table>
<h2 id="replace-developers">Will AI replace web developers?</h2>
<p>Some of them, yes. If all a developer offers is typing speed and framework syntax, the AI has that job already.</p>
<p>What I can&#8217;t see it replacing soon (and I&#8217;ve been wrong about timelines before) is the person who knows what the software is <em>for</em>. The AI gives you the most common version of whatever you ask for, which is the right version if yours is the most common business, and almost nobody&#8217;s is, because you&#8217;ve got a tax rule or a shipping exception or a client who pays in three currencies or an auditor who wants the record kept a certain way, and none of that is in the prompt unless somebody who has lived with it puts it there, and that somebody is what you&#8217;re paying for when you hire an expert.</p>
<p>Go back over the four cases. Three were caught by knowledge of the business, not of PHP. The fourth was caught by a question that came from years of watching software meet real users. I know that&#8217;s a small sample (one app, one company), so treat it as a pattern I&#8217;ve seen and not a study.</p>
<h2 id="questions-to-ask">Questions to ask before you hand over a real system</h2>
<ul class="mac-checklist">
<li>Does this software touch money, tax, personal data or legal records?</li>
<li>Who on the project knows the rules of my industry and my country, and have they read the spec?</li>
<li>What happens when two people do the same thing at the same second, and is there a test that proves it?</li>
<li>Has anyone logged in as each user role and tried to do what that role shouldn&#8217;t?</li>
<li>When it breaks at night, who reads the logs?</li>
<li>Could a different developer pick up this code a year from now?</li>
</ul>
<p>If the honest answer to the first one is no, go ahead and vibe code it. I would. We&#8217;ve written about <a href="https://www.macronimous.com/blog/vibe-coding-for-web-developers-amplify-your-flow-state-with-ai/">how our developers use vibe coding</a>, and about the stricter process we call <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled AI coding</a> for everything else.</p>
<h2 id="faq">FAQ</h2>
<div>
<div class="faq-item">
<h3>Is vibe coding bad for production apps?</h3>
<p>It&#8217;s risky when nobody who understands the business reviews the result. Vibe coding produces the most conventional version of what you asked for. If your app handles money, tax, permissions or several users at once, the conventional version can be wrong in ways that never show up as an error.</p>
</div>
<div class="faq-item">
<h3>What are the main vibe coding security risks?</h3>
<p>The ones we&#8217;ve met in our own apps were a user role that existed on screen but wasn&#8217;t enforced on the server, and a spreadsheet export open to formula injection. Both worked in a demo. Neither gets flagged unless someone tests for it on purpose.</p>
</div>
<div class="faq-item">
<h3>Will AI replace web developers?</h3>
<p>It&#8217;s replacing the typing. It isn&#8217;t replacing the person who knows your tax rules, your data and what happens under load. On our invoice app, three of four problems were caught by business knowledge and one by a question about simultaneous users.</p>
</div>
<div class="faq-item">
<h3>Can a non-developer build a business app with AI?</h3>
<p>Yes, and for a prototype or a small internal tool it&#8217;s often the right call. Before it handles real customers or real money, have a developer who knows your domain review the business rules, the database design and the user roles.</p>
</div>
</div>
<h2>Where that leaves you</h2>
<p>That&#8217;s what one build taught us. If you&#8217;ve put a fully vibe-coded system into production and it has held up for a year, I&#8217;d like to hear how, because I haven&#8217;t seen it yet.</p>
<div class="mac-cta-box">
<h3>Have an AI-built app that&#8217;s about to go live?</h3>
<p>We&#8217;ll read it the way we read our own: business rules first, then the data, the user roles and what happens when two people click at once.</p>
<p><a href="https://www.macronimous.com/services/custom-web-development/" class="mac-cta-button">Get your AI-built app reviewed</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/is-vibe-coding-bad/">Is Vibe Coding Bad? What a Real Invoice App Build Showed us</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/is-vibe-coding-bad/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Why Is My Writing Flagged as AI? We Used Dashes Before the Machines Did</title>
		<link>https://www.macronimous.com/blog/why-is-my-writing-flagged-as-ai/</link>
					<comments>https://www.macronimous.com/blog/why-is-my-writing-flagged-as-ai/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Thu, 01 Oct 2026 07:45:32 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Content Marketing]]></category>
		<category><![CDATA[AI content]]></category>
		<category><![CDATA[Ai Slop]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[Content writing]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5366</guid>

					<description><![CDATA[<p>Why is my writing flagged as AI? Because detectors and suspicious readers judge surface habits: dashes, tidy lists, even rhythm, polite openings. Models learned every one of those habits from human writers, so careful human writing now looks machine-made. Deleting the habits doesn&#8217;t fix it. What proves you wrote it is a clear position, details [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/why-is-my-writing-flagged-as-ai/">Why Is My Writing Flagged as AI? We Used Dashes Before the Machines Did</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/09/Why-Is-My-Writing-Flagged-as-AI-We.jpg"><img loading="lazy" decoding="async" width="1672" height="941" src="https://www.macronimous.com/blog/wp-content/uploads/2026/09/Why-Is-My-Writing-Flagged-as-AI-We.jpg" alt="Why Is My Writing Flagged as AI We" class="aligncenter size-full wp-image-5371" /></a>
<div class="mac-direct-answer">
<p><strong>Why is my writing flagged as <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">AI</a>?</strong> Because detectors and suspicious readers judge surface habits: dashes, tidy lists, even rhythm, polite openings. Models learned every one of those habits from human writers, so careful human writing now looks machine-made. Deleting the habits doesn&#8217;t fix it. What proves you wrote it is a clear position, details only a practitioner would know, and a last pass in your own words.</p>
</div>
<h2>The dash was ours first</h2>
<p>The first post on this blog went up on 19 February 2008. There are 372 of them now. I&#8217;ve written a lot of them, and I have a habit: I use dashes – not always the proper long one, often just the short one with a space on either side, because that&#8217;s what the keyboard gives you.</p>
<p>Go and look at December 2013. One post is titled &#8220;<a href="https://www.macronimous.com/blog/does-cdn-help-seo/">Does CDN help SEO? – CDN, Google, Page speed and ranking factors</a>.&#8221; Another one, the same month, has a dash in its title too. ChatGPT was nine years away.</p>
<p>Today a dash in a blog post gets read as a machine&#8217;s fingerprint. So do neat lists, tidy paragraphs and polite openings. Which is a bit rich, because the machines learned all of that from people like us (and, I suppose, from us). We even published a piece this April about <a href="https://www.macronimous.com/blog/emdash-vs-wordpress/">a CMS that is actually called EmDash</a>, which didn&#8217;t help.</p>
<p>So here&#8217;s the odd new job. It isn&#8217;t enough to write as a human anymore. You have to write as a human who can&#8217;t be mistaken for a machine. Human-human, if you like.</p>
<h2>So why is my writing flagged as AI?</h2>
<p>Short answer: because you write the way models were taught to write, and they were taught by people like you. So the first thing everybody tries is scrubbing out the habits. It&#8217;s the obvious move, and you can&#8217;t win that way.</p>
<p>You take out the dashes, and then someone says the real giveaway is the word &#8220;delve,&#8221; so you take that out, and then it&#8217;s groups of three, and then it&#8217;s any sentence shaped like &#8220;it&#8217;s not this, it&#8217;s that,&#8221; and then it&#8217;s being too polite, and by the time you&#8217;ve removed every habit a model picked up from human writers, which is all of them, because that&#8217;s where it got them, what&#8217;s left is a flat, careful page that sounds like nobody at all, which is, of course, exactly how a machine sounds.</p>
<p>The list of tells changes every few months anyway. Dashes were the 2024 tell. I don&#8217;t know what next year&#8217;s will be, and neither does anyone selling you a checker.</p>
<p>About those checkers. A Stanford team ran seven popular AI detectors over 91 essays written by people for the TOEFL (Test of English as a Foreign Language). The detectors wrongly flagged <a href="https://arxiv.org/abs/2304.02819" target="_blank" rel="noopener noreferrer">about 61 percent of those human essays as AI-written</a>, while scoring essays by American eighth graders almost perfectly. That paper is from 2023 and the tools have changed since, so treat the number as a warning more than a measurement. Still. We write from Coimbatore, India, for readers in the US, the UK and Australia. You can guess which pile we&#8217;d land in. If you&#8217;ve been falsely accused of using AI, this is probably why, and it says nothing about your writing.</p>
<p>And yet the worry behind all this is fair. Merriam-Webster made <a href="https://www.merriam-webster.com/wordplay/word-of-the-year" target="_blank" rel="noopener noreferrer">&#8220;slop&#8221; its word of the year for 2025</a>. People aren&#8217;t imagining the flood. They&#8217;re just using the wrong test to spot it.</p>
<h2>Yes, I use AI to write. Here&#8217;s how.</h2>
<p>I&#8217;d rather say this plainly than have you wonder. A model typed the first draft of this post.</p>
<p>What I don&#8217;t do is ask it for &#8220;a blog on a trending topic.&#8221; That&#8217;s where slop comes from: the machine supplies the thinking and a person supplies the publish button. I do it the other way round. I bring the idea. I give my opinions, my own inputs, what I&#8217;d recommend, and a clear path for the argument to take. Then I work on what comes back. I ask for it again, more than once. I add views it missed. I delete the stereotypes (there are always stereotypes).</p>
<p>That&#8217;s closer to working with a ghostwriter or a patient editor than to pressing a button, and writers used both long before 2022. It&#8217;s the same idea we follow in code, where <a href="https://www.macronimous.com/blog/controlled-ai-coding/">the AI works inside limits a person sets</a>.</p>
<p>Google, for what it&#8217;s worth, isn&#8217;t asking anyone to pretend either. Its <a href="https://developers.google.com/search/docs/fundamentals/using-gen-ai-content" target="_blank" rel="noopener noreferrer">guidance on generative AI content</a> cares about accuracy, quality and relevance, and suggests telling readers how a piece was made. So I&#8217;m telling you.</p>
<h2>Where the slop sneaks back in</h2>
<p>Here&#8217;s the part that&#8217;s easy to miss. The ideas are yours, so you assume the post is yours. But readers judge the sentences first, long before they reach the idea, and the sentences are still the model&#8217;s.</p>
<p>Two things happen in that gap.</p>
<p>The model smooths your opinions. You say &#8220;this is a mistake.&#8221; The draft says &#8220;this may not be ideal for every business.&#8221; Same topic, no spine. It&#8217;s worth checking that every opinion survived at full strength.</p>
<p>And the model keeps its own mold. Your input gets poured into a warm-up opening, even-sized sections and a summary at the end. You can delete a hundred clichés and still be left with the biggest one, which is the shape.</p>
<p>The fix is smaller than it sounds. If you only have time to hand-write three things, make them the opening, the ending, and the lines where you take a side. Those carry most of the voice. The middle can stay drafted and, as far as I can tell, nobody notices.</p>
<h2>What works on every post</h2>
<p>You can&#8217;t tell a story from your own history every time. We certainly can&#8217;t, not across 372 posts. These don&#8217;t need one.</p>
<ul class="mac-checklist">
<li>The post takes a side. &#8220;Most agencies do X, and we think that&#8217;s a mistake&#8221; needs no anecdote, only nerve.</li>
<li>Each section has one detail only a doer would know. Generic: &#8220;caching can cause issues on stores.&#8221; Practitioner: &#8220;on older WooCommerce stores, a full-page cache shows every visitor the same cart count unless the cart fragments call runs, and that call can&#8217;t be cached, so it ends up the slowest thing on the page.&#8221;</li>
<li>The depth is uneven on purpose. Skip what the reader already knows and spend 400 words on the one thing that matters.</li>
<li>There&#8217;s one honest &#8220;it depends,&#8221; in the one place where it really does, and it says what it depends on.</li>
<li>The warm-up opening and the summary ending are gone. This costs nothing.</li>
</ul>
<p>When you do have history, use it, because it&#8217;s the one thing nobody can copy. In November 2016 I wrote about <a href="https://www.macronimous.com/blog/lost-your-website-access-credentials-here-is-how-to-retrieve-them/">a client whose designer left with every server password</a>, and I put four exclamation marks in one sentence, followed by &#8220;Wow!&#8221; It isn&#8217;t elegant – but somebody was clearly upset when they typed it, and models don&#8217;t get upset.</p>
<h2>The test I use now</h2>
<p>If you came here asking &#8220;why is my writing flagged as AI,&#8221; I&#8217;d gently suggest that&#8217;s the wrong thing to fix. I&#8217;ve stopped asking &#8220;does this look human?&#8221; as well. The answer changes with the fashion.</p>
<div class="mac-key-point">
<p>The question I ask before publishing is: could anyone else have written this?</p>
</div>
<p>If the answer is yes, it&#8217;s slop, whether a person or a model typed it (content farms were turning it out by hand long before 2022). If the answer is no, the post proves itself, dashes and all. That matters for search as well, and it&#8217;s a big part of <a href="https://www.macronimous.com/blog/seo-strategy-2026/">how we&#8217;re approaching SEO in 2026</a>.</p>
<p>(There are three dashes in this post, by the way. One of them sits in a title from 2013. I&#8217;m keeping all three.)</p>
<p>If you&#8217;ve found a better test, write it in the comments and I&#8217;ll add it here with credit.</p>
<div class="mac-cta-box">
<h3>Content that reads like your business wrote it</h3>
<p>We plan and write <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">SEO</a> content with a practitioner in the loop at every step, so your pages say something only your company could say.</p>
<p><a class="mac-cta-button" href="https://www.macronimous.com/services/digital-marketing/outsource-seo-services/">See how we handle SEO content</a></p>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/why-is-my-writing-flagged-as-ai/">Why Is My Writing Flagged as AI? We Used Dashes Before the Machines Did</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/why-is-my-writing-flagged-as-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Should Your Website Block AI Bots? A Practical 2026 Answer</title>
		<link>https://www.macronimous.com/blog/should-you-block-ai-bots-website-seo/</link>
					<comments>https://www.macronimous.com/blog/should-you-block-ai-bots-website-seo/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Wed, 16 Sep 2026 06:03:24 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Technical SEO]]></category>
		<category><![CDATA[AEO]]></category>
		<category><![CDATA[AI crawlers]]></category>
		<category><![CDATA[Cloudflare]]></category>
		<category><![CDATA[robots.txt]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5358</guid>

					<description><![CDATA[<p>Blocking AI bots is the wrong question, because there are three kinds and they do different things. Search bots and agent bots send you traffic or citations, so allow them everywhere. Training bots give nothing back, so decide page by page: allow on marketing content you want AI to know about, block on anything you [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/should-you-block-ai-bots-website-seo/">Should Your Website Block AI Bots? A Practical 2026 Answer</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/09/Should-Your-Website-Block-AI-Bots-A-Practical-2026-Answer.jpg"><img loading="lazy" decoding="async" width="1672" height="940" src="https://www.macronimous.com/blog/wp-content/uploads/2026/09/Should-Your-Website-Block-AI-Bots-A-Practical-2026-Answer.jpg" alt="Should Your Website Block AI Bots A Practical 2026 Answer" class="aligncenter size-full wp-image-5362" /></a>
<div class="mac-direct-answer">
<p><strong>Blocking <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a> bots</strong> is the wrong question, because there are three kinds and they do different things. Search bots and agent bots send you traffic or citations, so allow them everywhere. Training bots give nothing back, so decide page by page: allow on marketing content you want AI to know about, block on anything you charge for. And in Cloudflare, use the new Disallow AI Training setting, not Block: since September 15, 2026, Block stops Googlebot too.</p>
</div>
<h2>The question a client asked me last month</h2>
<p>&#8220;Should we just block all the AI bots?&#8221; That&#8217;s the email, more or less, that landed from a client who runs a cremation arrangement service a few weeks ago. He&#8217;d read a headline about Cloudflare blocking AI crawlers, opened his dashboard, found a toggle that said Block AI Bots, and had his finger on it. He wanted to know if it was a good idea.</p>
<p>It isn&#8217;t, for him. And I suspect it isn&#8217;t for most of the people reading this, because if you run a business site, your content isn&#8217;t the product. It&#8217;s the bait. The whole point of the service page is that someone finds it, reads it, and calls you. If an AI assistant reads it and tells a prospect &#8220;these people do Magento migrations, here&#8217;s their site,&#8221; that&#8217;s the same outcome, just with a different middleman.</p>
<p>So no, I wouldn&#8217;t block everything. But I also wouldn&#8217;t allow everything, and the reason is that &#8220;AI bots&#8221; is three different things wearing one label.</p>
<h2>Three bots, not one</h2>
<p>Every big AI company now runs at least three crawlers, and they have different jobs. OpenAI is the clearest about it. <a href="https://developers.openai.com/api/docs/bots" target="_blank" rel="noopener noreferrer">OpenAI&#8217;s crawler documentation</a> lists GPTBot for training, OAI-SearchBot for ChatGPT&#8217;s search index, and ChatGPT-User for the moment a real person asks ChatGPT to open your page. Anthropic mirrors that with ClaudeBot, Claude-SearchBot, and Claude-User. Google does it the odd way round: one Googlebot fetches everything, and a separate robots.txt token called <a href="https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers" target="_blank" rel="noopener noreferrer">Google-Extended</a> tells Google after the fact whether it may use what it fetched to train Gemini.</p>
<p>Cloudflare&#8217;s names for the three are the ones that stuck, so I&#8217;ll use them:</p>
<table class="styled-table">
<thead>
<tr>
<th>Type</th>
<th>What it does</th>
<th>Examples</th>
<th>What you get back</th>
</tr>
</thead>
<tbody>
<tr>
<td>Search</td>
<td>Indexes your pages so an engine can answer questions later</td>
<td>Googlebot, Bingbot, OAI-SearchBot, PerplexityBot</td>
<td>Referral traffic, citations in AI search</td>
</tr>
<tr>
<td>Agent</td>
<td>Fetches a page live because a person asked</td>
<td>ChatGPT-User, Claude-User, Google-Agent</td>
<td>A citation in the answer, sometimes a click</td>
</tr>
<tr>
<td>Training</td>
<td>Copies content to build the next model</td>
<td>GPTBot, ClaudeBot, CCBot, Google-Extended, Bytespider</td>
<td>Nothing direct. Maybe brand familiarity in a future model</td>
</tr>
</tbody>
</table>
<p>The trouble with a single Block AI Bots switch is that it treats a Perplexity fetch that&#8217;s about to cite you the same as a Bytespider crawl that&#8217;s copying your site for a model you&#8217;ll never hear of. Those aren&#8217;t the same decision.</p>
<h2>What each one is worth to a business site</h2>
<p>Search bots are easy. Block them and you vanish from search, and now &#8220;search&#8221; includes ChatGPT search, Perplexity, and Bing Copilot. OpenAI says plainly that a site which opts out of OAI-SearchBot won&#8217;t be shown in ChatGPT search answers. Allow these. I can&#8217;t think of a business reason not to.</p>
<p>Agent bots are the ones people don&#8217;t understand yet, and they&#8217;re the ones that matter most for what we&#8217;ve been calling <a href="https://www.macronimous.com/blog/answer-engine-optimization-aeo-optimizing-for-ai-powered-search/">answer engine optimization</a>. When someone types &#8220;reliable WooCommerce developers with <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">SEO</a> experience&#8221; into Claude or ChatGPT and the assistant goes and reads three agency sites before answering, that read is an agent fetch. If you&#8217;ve blocked it, you&#8217;re not in the answer. You don&#8217;t get a pageview in Google Analytics for it (well, sometimes you do, depending on the bot), but you get the thing a pageview was always a proxy for: a prospect hearing your name.</p>
<p>Training bots are the honest &#8220;it depends.&#8221; A training crawl gives you no click, no citation, and no attribution. What it might give you, and I&#8217;m guessing here because nobody outside the labs really knows, is that the next model has some idea who you are. For a small agency that&#8217;s arguably worth more than the content it takes. For a publisher whose articles <em>are</em> the product, it&#8217;s a straight loss, and that&#8217;s the audience Matthew Prince was writing for when he declared <a href="https://blog.cloudflare.com/content-independence-day-no-ai-crawl-without-compensation/" target="_blank" rel="noopener noreferrer">Content Independence Day</a> back in July 2025. His numbers were brutal: by Cloudflare&#8217;s count it&#8217;s roughly 750 times harder to get a click from OpenAI than from old-school Google, and 30,000 times harder from Anthropic. Fair enough, if you sell ads. Most of our clients don&#8217;t.</p>
<div class="mac-key-point">
<p>If your site exists to get you hired, being read by an AI assistant is the goal, not the threat. Block the bots that only take, and let in the ones that mention you.</p>
</div>
<h2>What I&#8217;d allow, and what I&#8217;d block</h2>
<p>Here&#8217;s the split I&#8217;d use for an agency, a SaaS product, a B2B service firm, or a local business. Publishers and paywalled sites are a different post.</p>
<p>Allow everywhere: every search crawler, every agent fetcher. No exceptions on public pages.</p>
<p>Allow on marketing content: training crawlers on your service pages, your blog, your case studies, your about page. This is the content you <em>want</em> a model to have absorbed when a prospect asks it a buying question next year. You wrote it to be found. Let it be found. The exceptions are in the next two paragraphs.</p>
<p>Block training on: anything you sell or gate. Pricing calculators, downloadable frameworks, client portals, proposal PDFs, course content, the internal playbook you accidentally left at /wp-content/uploads/. This is content with standalone value, and a training crawl is the only kind of visit that takes the value without leaving anything.</p>
<p>Block outright, whatever the category: crawlers that give nothing back and don&#8217;t declare themselves. Bytespider (ByteDance) is the usual offender. Unknown user agents hammering the same unchanged pages. Anything that ignores robots.txt, which, I should note, Cloudflare reported Perplexity doing with undeclared crawlers in August 2025. That one was a category problem, not a business decision.</p>
<h2>Where Cloudflare comes in, and what changed on September 15</h2>
<p>This is the part that&#8217;s been in the news, and it&#8217;s also the part I had to rewrite the night before publishing, because Cloudflare moved the goalposts on September 15. Bear with me for a slightly technical section.</p>
<p>On July 1, 2026, Cloudflare retired the single Block AI Bots toggle and replaced it with the three controls above: Search, Agent, and Training, each one you can set separately, on every plan including Free. The July announcement also warned that from September 15 a Training block would catch Googlebot, because Googlebot does search <em>and</em> training in one fetch. That warning is why half the SEO industry spent the summer nervous.</p>
<p>Then on September 15 Cloudflare published <a href="https://blog.cloudflare.com/accountable-mixed-use-ai-crawlers/" target="_blank" rel="noopener noreferrer">a follow-up</a> that mostly defuses it. There&#8217;s a fourth option for the Training control now, called Disallow AI Training. Pick it and Cloudflare writes the no-training preference into your robots.txt for you (Google-Extended, Applebot-Extended, and so on), keeps letting Googlebot, Applebot, and Bingbot crawl for search, and blocks the training-only crawlers from OpenAI, Anthropic, Meta, and Amazon at the edge. Google, Apple, and Microsoft signed up to what Cloudflare is calling the Accountable designation, which means they&#8217;ve promised that opting out of training won&#8217;t touch your rankings. One gap: Bing doesn&#8217;t read a no-training line in robots.txt yet (Microsoft says early 2027), so for Bing you still need the NOARCHIVE meta tag.</p>
<p>The trap didn&#8217;t go away, though. It moved. The plain Block setting on Training now does exactly what it says, which means a site owner who reads &#8220;Block&#8221; as &#8220;block AI&#8221; (a reasonable reading, and the one every headline since July has encouraged) and picks it because it sounds like the safe choice will find that Cloudflare takes them at their word and stops Googlebot, Applebot, and Bingbot at the edge, with a 403 that never touches robots.txt and never reaches the server, so the site looks fine from the inside while pages quietly drop out of the index, and the first anyone hears of it is a crawl-stats dip in Search Console three or four weeks later. The good news for the people who flipped the old toggle in 2025 and forgot: Cloudflare migrated that to Disallow AI Training, not Block, so Googlebot keeps coming. The migration also sets Agent to &#8220;Block on pages with ads,&#8221; which does nothing on a site without ads. If you never touched any of it, everything stays on Allow.</p>
<h2>Why blocking doesn&#8217;t protect you much anyway</h2>
<p>This next part is what the logs show, whether or not it sounds defeatist.</p>
<p>Robots.txt is a request, not a lock. The well-behaved crawlers honor it (OpenAI, Anthropic, Google, Bing all say they do, and as far as I can tell they mean it). The badly behaved ones don&#8217;t, and those are the ones you were worried about. A Cloudflare edge block is stronger because it&#8217;s enforced before the request reaches you, but it&#8217;s only as good as Cloudflare&#8217;s ability to identify the bot, and a crawler that spoofs a Chrome user agent from a residential proxy looks like a person. So you end up in the position where a block reliably keeps out the polite companies that would have cited you, and unreliably keeps out the ones that wouldn&#8217;t have. That&#8217;s a bad trade for a site whose content isn&#8217;t for sale.</p>
<p>Blocking is worth doing when the content has a price. As a gesture it costs you citations and protects nothing.</p>
<h2>What we do on our own sites</h2>
<p>Macronimous.com has sat behind Cloudflare since 2013 (I wrote about setting it up back then; it took under ten minutes and I stand by that). Our current policy is exactly the split above: Search and Agent allowed everywhere, Training allowed on the public marketing pages and blog, and blocked only on the handful of paths where we keep client deliverables and internal tooling. We&#8217;ve never turned on the legacy Block AI Bots toggle, so the September migration left everything on Allow, and I checked the dashboard on Tuesday to make sure. I&#8217;ll probably switch Training to Disallow AI Training once I&#8217;ve watched it for a couple of weeks on a test domain.</p>
<p>Over the last thirty days our logs show around 30 requests from agent-class bots against the blog. Jeffy on our team pulled that from Cloudflare&#8217;s AI Crawl Control; I haven&#8217;t verified it against the origin logs yet, so treat it as directional, and yes, thirty is a small number for a site our size. We&#8217;re also building a small internal tracker that asks the major assistants our own buying questions every week and records whether Macronimous comes up. Early, and I&#8217;ll write it up when the numbers mean something.</p>
<h2>The robots.txt I&#8217;d start with</h2>
<p>For a typical <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> business site, this is the baseline. Adjust the training block to your own gated paths.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag"># Search: allow
User-agent: Googlebot
User-agent: Bingbot
User-agent: OAI-SearchBot
User-agent: PerplexityBot
User-agent: Claude-SearchBot
Allow: /

# Agent: allow
User-agent: ChatGPT-User
User-agent: Claude-User
User-agent: Google-Agent
Allow: /

# Training: allow public, block gated
User-agent: GPTBot
User-agent: ClaudeBot
User-agent: Google-Extended
User-agent: CCBot
Allow: /
Disallow: /resources/premium/
Disallow: /client-portal/

# Gives nothing back: block
User-agent: Bytespider
Disallow: /</pre><p></p>
<p>Note that Google-Extended in that list doesn&#8217;t stop Googlebot from fetching the page; it only tells Google not to train Gemini on it. Cloudflare&#8217;s Disallow AI Training setting writes that same line for you, so if you&#8217;re on Cloudflare you can let it manage this block and keep the rest.</p>
<h2>Checks to run this week</h2>
<ul class="mac-checklist">
<li>Open Cloudflare, go to Security, then Settings, and read what the Training control migrated to. It should say Allow or Disallow AI Training. If it says Block, Googlebot is blocked; change it today.</li>
<li>If you want to refuse training, pick Disallow AI Training, not Block, and turn on Bot Preference Sync so the robots.txt lines get written for you.</li>
<li>For Bing, add the NOARCHIVE meta tag on pages you don&#8217;t want used for training, because the robots.txt preference doesn&#8217;t reach Bing until 2027.</li>
<li>Pull a week of origin logs and look for 403 responses to Google&#8217;s published IP ranges. That&#8217;s the only place an edge block shows.</li>
<li>Watch Search Console&#8217;s crawl-stats report for a drop in Googlebot requests since September 15.</li>
<li>Update robots.txt along the lines above, and check the live file, not the one in your theme folder (a stale plugin-generated robots.txt is a classic piece of <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">WordPress technical debt</a>).</li>
<li>Run your key service page through our <a href="https://www.macronimous.com/free-tools/aeo-readiness-checker/">AEO readiness checker</a> to confirm agent bots can actually read what&#8217;s on it once they&#8217;re let in.</li>
</ul>
<p>That&#8217;s about all I know at this point. The rules changed the day before I published this, and Cloudflare has already said AI summaries opt-outs are next, early next year; if you&#8217;ve seen something in your own logs that contradicts any of this, tell me in the comments and I&#8217;ll correct the post with credit. For where this sits in a wider plan, <a href="https://www.macronimous.com/blog/seo-strategy-2026/">our 2026 SEO strategy notes</a> cover the rest of the AI-search picture.</p>
<div class="mac-cta-box">
<h3>Not sure what your Cloudflare settings are doing to Googlebot?</h3>
<p>We audit crawler access, robots.txt, and AI visibility as part of our SEO and AEO retainers, and we&#8217;ll tell you if the fix is a five-minute toggle rather than a project.</p>
<p><a href="https://www.macronimous.com/services/digital-marketing/outsource-seo-services/" class="mac-cta-button">Review my crawler setup</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/should-you-block-ai-bots-website-seo/">Should Your Website Block AI Bots? A Practical 2026 Answer</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/should-you-block-ai-bots-website-seo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Testing in Agentic Coding: From Safety Net to Steering Wheel</title>
		<link>https://www.macronimous.com/blog/testing-in-agentic-coding/</link>
					<comments>https://www.macronimous.com/blog/testing-in-agentic-coding/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Thu, 27 Aug 2026 07:33:47 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Web Development]]></category>
		<category><![CDATA[Laravel Development]]></category>
		<category><![CDATA[PHP Development]]></category>
		<category><![CDATA[React development]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[web programming]]></category>
		<category><![CDATA[agentic coding]]></category>
		<category><![CDATA[AI code review]]></category>
		<category><![CDATA[Test-driven development]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Vibe coding]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5308</guid>

					<description><![CDATA[<p>Testing in agentic coding is no longer a safety net written after the code. Tests are now the specification, the constraint, and the steering wheel for the AI agent itself. Teams that define expected behavior as tests before the agent writes a line ship faster and break less. Teams that let the agent grade its [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/testing-in-agentic-coding/">Testing in Agentic Coding: From Safety Net to Steering Wheel</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/08/Testing-in-Agentic-Coding-scaled.jpg"><img loading="lazy" decoding="async" width="2560" height="1352" src="https://www.macronimous.com/blog/wp-content/uploads/2026/08/Testing-in-Agentic-Coding-scaled.jpg" alt="Testing in Agentic Coding: " class="aligncenter size-full wp-image-5310" /></a>
<div class="mac-direct-answer">
<p><strong>Testing in <a href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">agentic coding</a></strong> is no longer a safety net written after the code. Tests are now the specification, the constraint, and the steering wheel for the <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">AI</a> agent itself. Teams that define expected behavior as tests before the agent writes a line ship faster and break less. Teams that let the agent grade its own homework ship confident-looking bugs.</p>
</div>
<p>We have been shipping a lot of apps with agents lately: Claude Code on some projects, our developers on Kilocode and Codex on others. The developers adapted fast. The question that kept bothering me was our test engineers, and whether twenty years of testing discipline just became obsolete overnight. This post is my answer: it did not. It became more important, and it moved to a different place in the process. Along the way I will also answer the question that follows immediately after: if agents write the code, who reviews it, and does agent-reviewing-agent even make sense?</p>
<div class="mac-toc">
<p class="mac-toc-title">In this post</p>
<ul>
<li><a href="#safety-net-steering-wheel">The safety net became the steering wheel</a></li>
<li><a href="#agent-without-tests">What happens when an agent codes without tests</a></li>
<li><a href="#test-driven-prompting">Test-driven prompting: write the contract, not the code</a></li>
<li><a href="#regression-first">Fix bugs backwards: regression test first, patch second</a></li>
<li><a href="#agent-code-review">Can an agent review agent code?</a></li>
<li><a href="#team-lead-changes">What changes for the team lead</a></li>
<li><a href="#testers-promoted">Your testers just got promoted</a></li>
</ul>
</div>
<h2 id="safety-net-steering-wheel">The safety net became the steering wheel</h2>
<p>For twenty years, tests sat downstream of code. You wrote the feature, then you wrote tests to prove it worked, and everyone quietly accepted that half the time the tests came late or not at all. Tests were insurance. Skipping them was a debt, not a disaster.</p>
<p>Agentic coding flipped the direction of that arrow. When Claude Code, Cursor, or any autonomous agent writes and modifies code in a loop, the test suite is the only channel through which reality reaches the agent. The agent cannot see your product spec. It cannot sit in your standup. What it can do, thousands of times an hour, is run a test and read the result. That makes tests the primary steering mechanism, not the final checkpoint. Anthropic&#8217;s own <a href="https://code.claude.com/docs/en/best-practices" target="_blank" rel="noopener noreferrer">Claude Code best practices</a> put test-driven workflows at the center for exactly this reason: a red-to-green cycle gives the agent unambiguous feedback it can iterate against without a human in the loop.</p>
<p>Here is the position I will defend: in an agentic team, writing tests after the code is not a smaller version of testing. It is theater.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-5307" src="https://www.macronimous.com/blog/wp-content/uploads/2026/08/testing-agentic-coding-vs-traditional-development.jpg" alt="Diagram comparing testing as a safety net in traditional development versus testing as driver and constraint in agentic vibe coding" width="1600" height="893"></p>
<h2 id="agent-without-tests">What happens when an agent codes without tests</h2>
<p>The failure modes are predictable, and if you manage a web team using AI agents, you have already seen at least one of them.</p>
<ul>
<li><strong>Hallucinated correctness.</strong> The agent reports &#8220;done, all working&#8221; for code it never executed against a real assertion. It is not lying. It has no ground truth to check against, so its confidence is a language pattern, not a verdict.</li>
<li><strong>Fix one, break three.</strong> Ask an agent to patch a Laravel endpoint and it will happily rewrite a shared helper, silently changing behavior in two other controllers. Without a regression suite, nobody notices until a client does.</li>
<li><strong>Spec drift.</strong> Over a long session, the agent&#8217;s idea of the feature slowly diverges from yours. Each individual change looks reasonable. The sum is a checkout flow that does something you never asked for.</li>
</ul>
<p>There is a fourth failure mode that surprises people: unlike a human developer, an agent almost never says no. A senior developer will push back on a bad requirement. An agent builds whatever you describe, including the unwise version, and builds it convincingly. Tests are the mechanism that replaces the pushback you lost.</p>
<h2 id="test-driven-prompting">Test-driven prompting: write the contract, not the code</h2>
<p>The practical shift for developers is that you stop typing assertions by hand and start defining behavior up front, in plain language or minimal test skeletons, then instruct the agent to write code that makes those tests pass. Kent Beck, who literally wrote the book on TDD, calls this discipline the difference between <a href="https://www.macronimous.com/blog/is-vibe-coding-bad/">vibe coding</a> and <a href="https://newsletter.kentbeck.com/p/augmented-coding-beyond-the-vibes" target="_blank" rel="noopener noreferrer">augmented coding</a>: in one you only care that the behavior looks right, in the other you own the tests and the design while the agent does the typing.</p>
<p>The working sequence looks like this:</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">1. "Write failing tests for the coupon validation endpoint.
   Expected: 422 on expired codes, 200 with discount object on valid codes,
   409 when the coupon is already redeemed. No implementation yet."
2. "Run the tests. Confirm they all fail."
3. Commit the failing tests.
4. "Now implement until every test passes.
   Do not modify the tests."</pre><p>&nbsp;</p>
<p>Step 3 is not optional. Agents will sometimes edit a test to make it pass instead of fixing the implementation. Committing the failing tests first means any tampering shows up in the diff, and you can revert it in seconds. That one git commit is doing the supervision work a human reviewer used to do line by line.</p>
<p>For web teams, the same pattern applies at every layer: Pest or PHPUnit for the API, Vitest for React components, and <a href="https://playwright.dev/docs/intro" target="_blank" rel="noopener noreferrer">Playwright</a> for the end-to-end flows that actually pay the bills, like login, cart, and checkout. The agent can write and run all of them. Your job is deciding what they must assert.</p>
<h2 id="regression-first">Fix bugs backwards: regression test first, patch second</h2>
<p>When a bug surfaces, the old reflex is to dive into the implementation. The agentic reflex should be different: prompt the agent to write a test that reproduces the bug, watch it fail, and only then allow the agent to generate the fix.</p>
<p>This ordering matters for two reasons. First, a reproducing test proves the agent understood the bug; a patch without one proves nothing. Second, that test stays in the suite forever, so the same agent (or the next one, or the junior developer six months from now) cannot reintroduce the bug without the pipeline going red. Every incident becomes a permanent constraint. Over a year, this is how a codebase touched by agents gets more stable instead of less. This is the same discipline we described in <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled AI coding</a>, applied to defects instead of features.</p>
<div class="mac-key-point">
<p>In agentic development, the test suite is the only part of the codebase a human must fully own. Everything else is negotiable.</p>
</div>
<h2 id="agent-code-review">Can an agent review agent code?</h2>
<p>This is the question that sounds like a trap: if the agent wrote the code, having an agent review it feels like a developer testing his own work. Sometimes it is exactly that, and sometimes it is not. The difference is context, and it is worth being precise about.</p>
<p>An agent reviewing code inside the same session that wrote it is worthless. It carries the full memory of its own reasoning, so it re-approves its own assumptions, the same way you cannot proofread your own email five seconds after sending it. But a <strong>fresh agent session with no memory of the implementation</strong> is a genuinely different reviewer. It reads the diff cold, with no attachment to the decisions behind it, which is closer to a new team member reviewing a PR than to a developer grading himself. Anthropic recommends this writer/reviewer split as a standard pattern for the same reason.</p>
<p>So agent review is real, but it is narrow. A fresh agent catches logic errors, missed edge cases, and deviations from the test contract. What it cannot do is be accountable. Both agents still share the same training, the same blind spots, and the same inability to know your client, your compliance obligations, or your business. That is where the human stays, and not as a formality:</p>
<ul>
<li><strong>Owning the behavior contract.</strong> A human decides what the tests must assert. Agents can propose edge cases; a person approves them.</li>
<li><strong>Reviewing the tests, not the volume.</strong> Nobody honestly reads 800 generated lines. A human reads the 60 lines of tests that govern them, plus a spot-check of anything touching money, auth, or data deletion.</li>
<li><strong>Architectural and product judgment.</strong> Whether this feature should exist, whether this dependency is acceptable, whether this shortcut will hurt in a year. No test suite encodes that.</li>
<li><strong>The merge.</strong> A human presses the button, and that name in the git history means something a bot&#8217;s cannot.</li>
</ul>
<p>Put plainly: shipping unreviewed code was never acceptable, and agents do not change that. They change what review looks like. Test contract reviewed by a human, implementation reviewed by a fresh agent, judgment calls and the merge held by a human. That is not weaker than traditional code review. Done honestly, it is stricter, because the contract is explicit instead of living in a reviewer&#8217;s head.</p>
<h2 id="team-lead-changes">What changes for the team lead</h2>
<p>If you run a web team, the shift is bigger for you than for your developers. The summary:</p>
<table class="styled-table">
<thead>
<tr>
<th>Dimension</th>
<th>Traditional workflow</th>
<th>Agentic workflow</th>
</tr>
</thead>
<tbody>
<tr>
<td>Role of tests</td>
<td>Validate finished code</td>
<td>Specify and constrain the agent</td>
</tr>
<tr>
<td>When tests are written</td>
<td>After implementation, if time allows</td>
<td>Before the agent writes code</td>
</tr>
<tr>
<td>Debugging</td>
<td>Manual analysis, then refactor</td>
<td>Regression test first, then prompted fix</td>
</tr>
<tr>
<td>What reviewers read</td>
<td>The implementation diff</td>
<td>The tests, then the diff</td>
</tr>
<tr>
<td>QA position</td>
<td>End of the cycle</td>
<td>Start of the cycle, encoded as tests</td>
</tr>
</tbody>
</table>
<p>The review change deserves emphasis. An agent can generate 800 lines of plausible React in a minute; no human reviews that honestly. What a human can review is the 60 lines of tests that define what those 800 lines must do. Review the contract, spot-check the implementation. Where the <a href="https://www.macronimous.com/blog/web-development-life-cycle-process-flow-diagram/">web development life cycle</a> used to place QA as a phase, agentic teams place it as a gate: CI runs the full suite on every agent-generated commit, and the agent is simply not allowed to ship red. Budget-wise, the hours you used to spend on post-build QA move upstream into behavior definition. The total testing effort does not shrink. It moves to the front, where it is cheap.</p>
<p>A policy checklist worth adopting before your team&#8217;s next sprint:</p>
<ul class="mac-checklist">
<li>Every agent-built feature starts from tests the agent was given or asked to generate first, committed while still failing</li>
<li>Agents are instructed never to modify existing tests; any test change requires a human commit</li>
<li>No agent-generated PR merges with a red pipeline, no exceptions for &#8220;it works locally&#8221;</li>
<li>Every production bug gets a reproducing regression test before its fix is accepted</li>
<li>Critical user flows (auth, cart, checkout, payments) have end-to-end coverage the agent must keep green</li>
<li>Reviewers read tests first and sign off on behavior, not line-by-line implementation</li>
</ul>
<h2 id="testers-promoted">Your testers just got promoted</h2>
<p>The uncomfortable conclusion for managers: the people on your team who are good at defining expected behavior, edge cases, and failure conditions just became your highest-leverage engineers. That skill used to be undervalued as &#8220;QA work.&#8221; It is now the interface through which your team controls its fastest developer, the agent. The developers who thrive in this model are the ones who can hold the whole behavior of a feature in their head and write it down precisely, which is also the skill we argued matters most in <a href="https://www.macronimous.com/blog/vibe-coding-for-web-developers-amplify-your-flow-state-with-ai/">vibe coding for web developers</a> and in <a href="https://www.macronimous.com/blog/writing-clean-code-with-ai/">writing clean code with AI</a>.</p>
<p>So no, test cases did not die in the age of agentic coding. They stopped being paperwork and became the steering wheel. The teams that treat them that way will let agents run fast safely. The teams that skip them will discover that an agent with no constraints is just a very fast way to write next quarter&#8217;s incident report.</p>
<div class="mac-cta-box">
<h3>Putting agents to work on a real web project?</h3>
<p>We build and manage <a href="https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/">web development</a> sprints where AI agents do the heavy lifting inside test-gated pipelines, so speed never comes at the cost of stability.</p>
<p><a href="https://www.macronimous.com/agile-web-development/" class="mac-cta-button">Plan a test-gated sprint with us</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/testing-in-agentic-coding/">Testing in Agentic Coding: From Safety Net to Steering Wheel</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/testing-in-agentic-coding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPress Plugin Security Starts as a Visibility Problem</title>
		<link>https://www.macronimous.com/blog/wordpress-plugin-security-visibility/</link>
					<comments>https://www.macronimous.com/blog/wordpress-plugin-security-visibility/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Tue, 25 Aug 2026 12:20:13 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Macronimous]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WordPress Maintenance]]></category>
		<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[technical debt]]></category>
		<category><![CDATA[Wordpress plugins]]></category>
		<category><![CDATA[Wordpress security]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5312</guid>

					<description><![CDATA[<p>WordPress plugin security is usually discussed as a code quality problem, but for most live sites it starts as a visibility problem. The information you would need to judge an estate exists in the database, in cron, and in public advisory feeds. It is just scattered across places no admin screen shows you. The argument [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/wordpress-plugin-security-visibility/">WordPress Plugin Security Starts as a Visibility Problem</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/08/You-cant-secure-what-you-cant-see.jpg"><img loading="lazy" decoding="async" width="2240" height="1260" class="aligncenter size-full wp-image-5316" src="https://www.macronimous.com/blog/wp-content/uploads/2026/08/You-cant-secure-what-you-cant-see.jpg" alt="WordPress Security" /></a>
<div class="mac-direct-answer">
<p><strong><a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> plugin security</strong> is usually discussed as a code quality problem, but for most live sites it starts as a visibility problem. The information you would need to judge an estate exists in the database, in cron, and in public advisory feeds. It is just scattered across places no admin screen shows you.</p>
</div>
<h2>The argument nobody wins</h2>
<p>The criticism is familiar. WordPress is insecure because anyone can bolt forty plugins from forty strangers onto a site and never look at them again. Say it in any developer forum and you will get agreement within a minute.</p>
<p>The defense is equally familiar. That is not WordPress&#8217;s fault. It is the site owner&#8217;s fault for installing carelessly, or the host&#8217;s fault, or the plugin author&#8217;s fault. I am on the defending side more often than not, and I have made the case that <a href="https://www.macronimous.com/blog/ai-website-builder-vs-wordpress-for-seo/">WordPress still beats the AI site builders</a> where it counts.</p>
<p>Here is my problem with that exchange, as someone who has run a <a href="https://www.macronimous.com/blog/is-headless-wordpress-worth-it/">WordPress development</a> business for years: the defense is technically correct and practically useless. &#8220;Be more careful&#8221; is not a mechanism. It gives nobody a way to act differently on Monday morning.</p>
<p>Both sides are arguing about blame. Almost nobody is arguing about what a site owner can actually see.</p>
<h2>Your plugins screen shows three fields</h2>
<p>Open any WordPress admin. The plugins screen gives you a name, a version number, and a description the author wrote about themselves.</p>
<p>That is the entire interface most people have for reasoning about risk. It does not tell you which of those plugins has a published vulnerability at the version you actually have installed, as opposed to merely appearing somewhere in an advisory database. It does not tell you which one loads 19 KB of autoloaded options into every single page request. It does not tell you that the plugin you deleted in 2019 left a scheduled job still firing every hour.</p>
<p>None of that is hidden. It sits in <code>wp_options</code>, in the cron array, in <code>SHOW TABLE STATUS</code>, and in public feeds like <a href="https://www.wpvulnerability.net/" target="_blank" rel="noopener noreferrer">the WPVulnerability database</a>. Getting to it means being a developer with a database client and a free afternoon.</p>
<p>So we have an ecosystem whose central criticism is a security one, and the people responsible for those sites cannot answer basic questions about them without writing SQL. That gap is where I think the useful work is. It is the same shape as the <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">technical debt that accumulates quietly in WordPress</a>: not dramatic, not visible, and expensive later.</p>
<h2>What a ten-year-old site leaves behind</h2>
<p>We pointed a read-only audit at one of our own sites. It has been alive since 2015 and it is not unusual in any way.</p>
<p>The orphaned tables told a story. A contact form plugin, long since removed, had left three tables holding 71 form submissions and 642 field-value rows. Names, email addresses, and messages from people who contacted the business years ago, sitting in tables that no privacy tool on that site can see, because no installed plugin claims them.</p>
<p>An invoicing plugin had left eight tables, all empty. Installed, never really used, deleted, and never cleaned up. A background job queue had 35 queued actions and 93 log rows belonging to a plugin nobody could name.</p>
<p>Nothing there is a vulnerability in the CVE sense. No scanner would flag it. But if you had asked me before that audit whether we held a decade of stranded contact form submissions on that site, I would have said no, confidently, and I would have been wrong.</p>
<div class="mac-key-point">
<p>You cannot make a judgment about an estate you cannot see. Most <a href="https://www.macronimous.com/blog/wordpress-to-headless/">WordPress security</a> advice assumes visibility that nobody actually has.</p>
</div>
<h2>So I built something that can only look</h2>
<p>The result is <a href="https://wordpress.org/plugins/auditra/" target="_blank" rel="noopener noreferrer">Auditra</a>, a free plugin that turns the site it runs on into a read-only <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer">MCP</a> server. You enable an endpoint, generate a token, paste the connection URL into an <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a> client, and then ask questions in plain language. Which plugins are vulnerable at the versions installed. What is bloating the options table. What did deleted plugins leave behind.</p>
<p>The interesting part is not the tool list. It is the three things it refuses to do, each of which cost me something.</p>
<p>It cannot change anything. No activating, no deactivating, no updating, no writing to the database at all. That is structural rather than a promise: there is no write call anywhere in the codebase, and the build fails if one is ever added. A tool that can only look has nothing to sell you afterward.</p>
<p>It does not score anything. No grades, no risk numbers, no &#8220;this plugin is dangerous.&#8221; Scores sell, which is precisely why so much security tooling has them and precisely why I do not trust them. The plugin returns facts with documented thresholds and leaves the judgment to the model reading them, which also means the analysis improves as models improve without me shipping anything. That is the same principle behind <a href="https://www.macronimous.com/blog/controlled-ai-coding/">keeping AI on a short leash while coding</a>: give it accurate context, not conclusions.</p>
<h2>Saying &#8220;I don&#8217;t know&#8221; is the whole design</h2>
<p>The decision I spent longest on sounds trivial. If the plugin could not check anything at all, what should it return?</p>
<p>The obvious answer is an empty list of findings. That is what most tools do, and it is wrong, because an empty list reads as <em>clean</em>. A security tool that implies &#8220;clean&#8221; when it checked nothing is worse than no tool, because it manufactures confidence that was never earned.</p>
<p>So it returns no findings list at all in that case. Not an empty one. A response saying what could not be checked, why, when the data was last fetched, and when it will retry. When only some plugins could be checked, the ones that were skipped are named individually. Every data source reports its own coverage.</p>
<p>That is a small technical decision, but it is the entire argument in miniature. The reason WordPress security discourse is so poor is that too much of the tooling is confidently wrong. Scanners emit scores. Plugins claim protection. Almost nothing ever says &#8220;I could not check that.&#8221; I would rather ship something that admits ignorance loudly than something that looks authoritative and is occasionally lying to you.</p>
<h2>What this does not fix</h2>
<p>Plenty. Seeing that a plugin has been unmaintained for three years does not patch it. Knowing an orphaned table holds old contact submissions does not delete it, and deliberately so, because a read-only tool cannot make that mistake on your behalf.</p>
<p>It also needs an AI client on the other end, which today means a narrower audience than the WordPress user base. I would rather say that plainly than pretend otherwise.</p>
<p>And there is a fair objection I should answer rather than dodge: this adds an HTTP endpoint that returns information about your site, which is a new surface. True. It ships disabled and answers 404 until an administrator turns it on, it requires a token compared in constant time, it is rate-limited, it is revocable in one click, and it exposes no post content, no user accounts, no credentials, and no option values. Only names and sizes. That is a considered trade, not an accident, and the readme spells out exactly what an enabled endpoint exposes so nobody has to take my word for it.</p>
<p>The plugin ecosystem is the best thing about WordPress. It is also the thing that makes a ten-year-old site an archaeological dig. I do not think that tension is going away, and I do not think another scanner with a letter grade helps. Better visibility might, a little. That is the whole intention, and it is a small one. The rest of the argument belongs to the ecosystem, which has been having it for fifteen years and will probably still be having it in another fifteen.</p>
<div class="mac-cta-box">
<h3>Not sure what your plugin estate is actually doing?</h3>
<p>We maintain WordPress sites that have been running for a decade or more, and we start by finding out what is really on them.</p>
<p><a class="mac-cta-button" href="https://www.macronimous.com/services/cms-development/wordpress-maintenance-services/">See our WordPress maintenance service</a></p>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/wordpress-plugin-security-visibility/">WordPress Plugin Security Starts as a Visibility Problem</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/wordpress-plugin-security-visibility/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Agentic Coding Mistakes: Lessons From a Real App build</title>
		<link>https://www.macronimous.com/blog/agentic-coding-domain-knowledge/</link>
					<comments>https://www.macronimous.com/blog/agentic-coding-domain-knowledge/#respond</comments>
		
		<dc:creator><![CDATA[Jeffy Susan]]></dc:creator>
		<pubDate>Thu, 20 Aug 2026 06:57:27 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[MCP Development]]></category>
		<category><![CDATA[Vibe Coding]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[agentic coding]]></category>
		<category><![CDATA[AI code review]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[invoice software]]></category>
		<category><![CDATA[MCP]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5297</guid>

					<description><![CDATA[<p>Agentic coding tools build the most conventional version of whatever you ask for. We asked for an invoicing system and got textbook accounting software, including a void feature that would have carried a GST liability on unpaid export invoices. Two diff-backed incidents from that build show why the fix is domain knowledge in the spec, [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">Agentic Coding Mistakes: Lessons From a Real App build</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/08/Agentic-Coding-Mistakes.jpg"><img loading="lazy" decoding="async" width="1729" height="910" src="https://www.macronimous.com/blog/wp-content/uploads/2026/08/Agentic-Coding-Mistakes.jpg" alt="Agentic Coding Mistakes" class="aligncenter size-full wp-image-5303" /></a>
<div class="mac-direct-answer">
<p><strong><a href="https://www.macronimous.com/blog/testing-in-agentic-coding/">Agentic coding</a> tools</strong> build the most conventional version of whatever you ask for. We asked for an invoicing system and got textbook accounting software, including a void feature that would have carried a GST liability on unpaid export invoices. Two diff-backed incidents from that build show why the fix is domain knowledge in the spec, not more hours spent reviewing generated code.</p>
</div>
<div class="mac-toc">
<p class="mac-toc-title">In this post</p>
<ul>
<li><a href="#training-data-app">The app an AI builds is the app in its training data</a></li>
<li><a href="#void-incident">Incident one: the agent built a void feature and made it law</a></li>
<li><a href="#numbering-incident">Incident two: numbering that was right everywhere except India</a></li>
<li><a href="#mistake-that-never-happened">The mistake that never happened</a></li>
<li><a href="#mcp-connector">The MCP connector: agentic defaults trust too much</a></li>
<li><a href="#specs-beat-review">Review catches what you know. Specs prevent what you don&#8217;t.</a></li>
<li><a href="#open-source">The bottom line, and the code</a></li>
</ul>
</div>
<h2 id="training-data-app">The app an AI builds is the app in its training data</h2>
<p>The standard advice for AI-assisted development is simple: let the agent write the code, then review it. We follow a stricter version of that ourselves and wrote it up as <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled AI coding</a>. But this build taught us where that advice runs out. Review catches the mistakes you already know to look for. It does nothing about the mistakes that look like correct code.</p>
<p>Some context, kept short. We run a software-export business in India, and export invoicing follows rules that generic tools don&#8217;t model. Exports of services are <a href="https://taxinformation.cbic.gov.in/content/html/tax_repository/gst/acts/2017_IGST_Act/active/chaptervii/section16_v1.00.html" target="_blank" rel="noopener noreferrer">zero-rated under Section 16 of the IGST Act</a>, payment must arrive in convertible foreign exchange, the bank issues a FIRC (Foreign Inward Remittance Certificate) as proof, each remittance carries an RBI purpose code, and invoice numbers run gapless per financial year, which in India starts on April 1. This is our working understanding, not tax advice; confirm specifics with your chartered accountant.</p>
<p>Because no off-the-shelf tool ties a FIRC to the invoice it settles, we built our own system, with Claude Code doing most of the typing. The agent was fast, confident, and produced clean PHP. It also produced two failures that never threw an error, never failed a test we had at the time, and would have passed any code review that judged the code as code.</p>
<h2 id="void-incident">Incident one: the agent built a void feature and made it law</h2>
<p>Every accounting tutorial, every open-source invoice app, every SaaS product the model has ever seen handles a wrong invoice the same way: void it, keep the number, never delete. So the agent built exactly that. Not a suggestion, a complete feature: a Void button, a confirm dialog, a reinstate action, and a comment declaring the behavior as rule &#8220;&sect;1.10&#8221; of its own spec. From <code>invoice-view.php</code> at commit <code>99d6730</code>:</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">/* Tax-invoice document (&sect;2). Born paid — status is `issued` or `void`,
 * voided, never deleted (&sect;1.10). */
if ($action === 'void' &amp;&amp; $inv['status'] === 'issued') {
    $DB-&gt;prepare("UPDATE invoices SET status='void' WHERE id=?")-&gt;execute([$id]);
    flash('Invoice voided. The number is retained (never reused).');
}</pre><p>&nbsp;</p>
<p>As generic accounting software, this is correct. As software for an Indian exporter, it is a liability generator. In our reading of GST, an issued tax invoice creates a tax liability whether or not you later mark it void. A wrongly issued invoice has to be removed and its proforma reverted, so the liability never exists on paper. We caught it in the functional-gap review, and the fix went in as commit <code>c9f4107</code>, whose message states the reasoning better than any paragraph I could write here:</p>
<blockquote>
<p>&#8220;invoice-view: replace Void with &#8216;Undo conversion&#8217; — deletes a wrongly converted invoice, reverts its proforma to Paid, frees the FY number (an invoice that exists is a GST liability, so wrong ones are removed).&#8221;</p>
</blockquote>
<div class="mac-key-point">
<p>This was a jurisdiction error made confidently. The agent generated the correct feature for the wrong country, then wrote it into its own spec as a rule.</p>
</div>
<p>That last part deserves a beat. The agent didn&#8217;t hedge. It codified the pattern as canonical, complete with a section number, and every later piece of generated code would have treated void as settled behavior. A wrong assumption an agent writes into its own spec compounds with every subsequent prompt.</p>
<h2 id="numbering-incident">Incident two: numbering that was right everywhere except India</h2>
<p>The first version of <code>next_invoice_number()</code>, from the initial commit <code>f6b7863</code>, made two default choices in one function:</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$st = $db-&gt;prepare('SELECT prefix, next_seq FROM companies WHERE id = ? FOR UPDATE');
// ...
return sprintf('%s-%s-%03d', $row['prefix'], date('Y', strtotime($issueDate)), $seq);</pre><p>&nbsp;</p>
<p>One global counter per company, and <code>date('Y')</code>: the calendar year. Reasonable everywhere the model&#8217;s training data comes from. Wrong in India, where invoice sequences reset on April 1 for the new financial year, and where our proforma and its resulting tax invoice must share a sequence number so the books line up. The catch, again, came from a review question, not from the code: &#8220;every business year, April 1st, we change the invoice numbers.&#8221; That single sentence forced a rebuild into per-company, per-document-type, per-FY gapless sequences.</p>
<p>Then the second layer, and this one is the more interesting failure. The rebuilt version used <code>INSERT IGNORE</code> plus <code>SELECT ... FOR UPDATE</code> plus <code>UPDATE</code>, a sequence that <a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-deadlocks.html" target="_blank" rel="noopener noreferrer">deadlocks under InnoDB</a> when two transactions create invoices at the same moment. No human review caught this. It was caught by a concurrency test that existed for one reason: someone asked &#8220;what if a team member creates an invoice on their machine at the same time?&#8221; The question generated the test; the test caught what eyes could not. The fix was a single atomic statement.</p>
<p>That is the arc worth remembering: naive, then domain-corrected, then concurrency-corrected, each step with a diff. And the mechanism differed. The FY miss was caught by knowledge. The deadlock was caught by a test that a question produced. If your process only has &#8220;review the diff,&#8221; you get the first catch and miss the second.</p>
<h2 id="mistake-that-never-happened">The mistake that never happened</h2>
<p>I expected a third incident. Agentic tools routinely model payment as a boolean, an <code>is_paid</code> flag on the invoice row, because that&#8217;s what tutorial invoice apps do. It never happened here. The very first schema, commit <code>f39c0b2</code>, already had a <code>payments</code> table with amount, currency, and FIRC linkage as a first-class record.</p>
<p>Why? Because the FIRC requirement was in the spec before the agent generated a line of code. When the spec says every foreign payment must carry its remittance certificate and purpose code, a boolean cannot satisfy it, so the wrong shape never gets generated. Nobody had to catch this mistake, because the constraint made it impossible to make.</p>
<table class="styled-table">
<thead>
<tr>
<th>What the agent defaults to</th>
<th>What an Indian exporter needs</th>
<th>How it was handled</th>
</tr>
</thead>
<tbody>
<tr>
<td>Void a wrong invoice, keep the number</td>
<td>Remove the invoice, revert the proforma, free the FY number</td>
<td>Built wrong, caught in review</td>
</tr>
<tr>
<td>One counter, calendar year</td>
<td>Gapless per-FY sequences resetting April 1, proforma and invoice matched</td>
<td>Built wrong, caught in review, then again by a test</td>
</tr>
<tr>
<td>An <code>is_paid</code> boolean</td>
<td>Payments as first-class records with FIRC and purpose code</td>
<td>Never built wrong: the constraint was in the spec</td>
</tr>
</tbody>
</table>
<p>Three rows, one pattern. The only mistake that cost nothing was the one the spec prevented.</p>
<h2 id="mcp-connector">The MCP connector: agentic defaults trust too much</h2>
<p>The system has an <a href="https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/">MCP</a> connector, so an accountant can open Claude Desktop and type &#8220;create and send an invoice to Acme Ltd for the March retainer&#8221; without ever logging into the app. The agentic default for this kind of connector is full write access, because that&#8217;s the frictionless demo. We went the other way. The connector is a thin layer over the app&#8217;s own token-authenticated API: writes are draft-first and require confirmation, every AI-initiated change is audit-logged, and the token is role-scoped so the <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a> cannot see or touch more than that accountant could. It&#8217;s stateless, single-request JSON, which lines up with where the <a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/" target="_blank" rel="noopener noreferrer">2026-07-28 MCP specification</a> took the protocol. The AI holds no business logic. The invoice system stays the single source of truth, which matters for the same reason everything above matters: an agent that improvises accounting logic is an agent that improvises liabilities.</p>
<h2 id="specs-beat-review">Review catches what you know. Specs prevent what you don&#8217;t.</h2>
<p>Agentic tools never say &#8220;that&#8217;s unwise.&#8221; A human developer with export clients would have asked about the financial year before writing a numbering function. The agent shipped <code>date('Y')</code> without a flicker of doubt, and it would ship the void feature again tomorrow. We&#8217;ve written before about <a href="https://www.macronimous.com/blog/writing-clean-code-with-ai/">keeping AI-generated code clean</a> and about why <a href="https://www.macronimous.com/blog/vibe-coding-for-web-developers-amplify-your-flow-state-with-ai/">vibe coding needs guardrails before production</a>, but this build sharpened the point: cleanliness was never the problem. Every one of these mistakes was clean.</p>
<p>So put the domain in writing before the agent starts. For anything with statutory weight, our pre-build spec now answers:</p>
<ul class="mac-checklist">
<li>Which jurisdiction&#8217;s rules govern this system, and which documents are statutory records?</li>
<li>What is the full lifecycle of each document, including what may be voided, deleted, reverted, or never touched?</li>
<li>What are the numbering rules: sequence scope, gaplessness, and which fiscal calendar they follow?</li>
<li>What proof documents (FIRC, purpose codes, certificates) must exist as first-class records, not fields?</li>
<li>What happens when two people do the same thing at the same time, and which test proves it?</li>
<li>If an AI connector exists, what is its write model: scope, confirmation, and audit trail?</li>
</ul>
<p>Every &#8220;what if&#8221; question in that list is a test waiting to be written. Ask it early and the agent generates the right shape from the first commit, the way the payments table proved.</p>
<h2 id="open-source">The bottom line, and the code</h2>
<p>The agent was worth it. It typed the app in a fraction of the time it would have taken us by hand, and both incidents were cheaper to fix than a single GST notice would have been to receive. But the value of the build lived in the two moments a human said &#8220;not in India&#8221; and the one moment a spec made the question unnecessary. Speed came from the agent. Correctness came from the domain.</p>
<p>We&#8217;re releasing the system under MIT for other Indian software exporters and freelancers with the same compliance shape: a single-business kit that self-installs on ordinary PHP and MySQL shared hosting, with your data in your own database. It is deliberately narrow. Built around Indian GST and export-of-services rules, it is not a fit for domestic billing at other tax rates or for non-Indian firms without changes. <!-- INSERT PUBLIC REPO URL HERE, or remove this sentence if the repo isn't live at publish time: --> The repository is on GitHub; if you find a rule we got wrong, an issue telling us so is the most useful contribution you can make.</p>
<div class="mac-cta-box">
<h3>Shipping AI-built code to production?</h3>
<p>We pair agentic speed with 24 years of review discipline, on React, PHP, and <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> builds where a wrong default has real-world costs.</p>
<p><a href="https://www.macronimous.com/services/custom-web-development/" class="mac-cta-button">Get your AI-built app reviewed</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">Agentic Coding Mistakes: Lessons From a Real App build</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/agentic-coding-domain-knowledge/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Building a WordPress MCP Server When the Spec Changed</title>
		<link>https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/</link>
					<comments>https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/#respond</comments>
		
		<dc:creator><![CDATA[Benny]]></dc:creator>
		<pubDate>Wed, 29 Jul 2026 05:29:22 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[MCP Development]]></category>
		<category><![CDATA[WordPress Development]]></category>
		<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Wordpress development]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5282</guid>

					<description><![CDATA[<p>MCP 2026-07-28 is the fifth revision of the Model Context Protocol, and it retires sessions and the initialize handshake in favor of plain request and response. That change suits WordPress unusually well. PHP already treats every request as an independent, shared-nothing process, so a WordPress MCP server no longer has to fake a persistent connection [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/">Building a WordPress MCP Server When the Spec Changed</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/07/Building-a-WordPress-MCP-Server-When-the-Spec-Changed.jpg"><img loading="lazy" decoding="async" width="1731" height="909" src="https://www.macronimous.com/blog/wp-content/uploads/2026/07/Building-a-WordPress-MCP-Server-When-the-Spec-Changed.jpg" alt="uilding a WordPress MCP Server When the Spec Changed" class="aligncenter size-full wp-image-5284" /></a>
<div class="mac-direct-answer">
<p><strong>MCP 2026-07-28</strong> is the fifth revision of the Model Context Protocol, and it retires sessions and the <code>initialize</code> handshake in favor of plain request and response. That change suits <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">WordPress</a> unusually well. PHP already treats every request as an independent, shared-nothing process, so a WordPress MCP server no longer has to fake a persistent connection it was never going to hold open anyway.</p>
</div>
<div class="mac-toc">
<p class="mac-toc-title">What&#8217;s on this page</p>
<ul>
<li><a href="#spec-changed">The spec changed the night before we submitted</a></li>
<li><a href="#right-shape">Why WordPress was already the right shape</a></li>
<li><a href="#what-broke">What broke was the handshake, and only the handshake</a></li>
<li><a href="#both-generations">We&#8217;re supporting both generations, not switching</a></li>
<li><a href="#timing">The timing call was harder than the code</a></li>
<li><a href="#cacheable">The small win: tool lists are cacheable now</a></li>
<li><a href="#read-the-rest">The rest of the changelog, for WordPress builders</a></li>
<li><a href="#simple-survives">Simple survives revisions. Clever gets rewritten.</a></li>
</ul>
</div>
<h2 id="spec-changed">The spec changed the night before we submitted</h2>
<p>On July 28, 2026 the Model Context Protocol shipped its fifth revision. We were hours away from uploading our WordPress MCP plugin to the plugin directory.</p>
<p>The headline change was a stateless core. MCP went from a bidirectional, stateful protocol to plain request and response. Sessions gone. The <code>initialize</code> and <code>initialized</code> handshake, retired outright. You can read the <a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/" target="_blank" rel="noopener noreferrer">maintainers&#8217; release notes</a> for the full list, and Anthropic published <a href="https://claude.com/blog/bringing-mcp-2026-07-28-to-claude" target="_blank" rel="noopener noreferrer">its own summary of what&#8217;s rolling out across Claude</a> the same day.</p>
<p>So the first question was not &#8220;should we adopt this.&#8221; It was &#8220;are we broken.&#8221;</p>
<p>Mostly, no. And for a deeply unglamorous reason.</p>
<h2 id="right-shape">Why WordPress was already the right shape</h2>
<p>In the first week of the build we had a choice about how the server replies. The old spec allowed a persistent event stream, or a single JSON response per request. We took the single response. Not because we saw anything coming, but because server-sent events inside PHP, under a shared host&#8217;s process model, is a bad afternoon that turns into a bad week.</p>
<p>The simpler option was permitted. We took it and moved on.</p>
<p>Eight months later the protocol moved to exactly that shape. Every server that had built the sophisticated version now has a migration to do. We had already accidentally arrived.</p>
<p>There is a general point buried in that, and it&#8217;s the reason this release matters beyond one plugin. WordPress has always been shared-nothing. A PHP request boots, does its work, and dies with no memory of the request before it. The previous MCP spec fought that model by asking for a connection WordPress does not naturally hold. The new spec asks for exactly what WordPress already does.</p>
<h2 id="what-broke">What broke was the handshake, and only the handshake</h2>
<p><code>initialize</code> and <code>initialized</code> were the first code written on this project, the thing that proved a WordPress site could act as an MCP server at all. Both are now retired in favor of an optional <code>server/discover</code> call. The most protocol-shaped part of the build was the part that aged worst.</p>
<p>Everything downstream, reading site data and returning JSON, did not care at all.</p>
<div class="mac-key-point">
<p>The parts of our build that broke were the parts doing protocol ceremony. The parts doing the actual job carried on untouched, because they had never known what a session was.</p>
</div>
<p>Here is what a call looks like now. Note that there is nothing to establish first, and nothing stored between requests.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"search","arguments":{"q":"otters"},
 "_meta":{"io.modelcontextprotocol/clientInfo":{"name":"my-app","version":"1.0"}}}}</pre><p>&nbsp;</p>
<p>Protocol version, client identity and client capabilities all travel in the request itself. Any request can land on any instance behind an ordinary load balancer. For a plugin running on shared hosting, that is not an abstract scalability win. It removes the one requirement PHP was worst equipped to meet.</p>
<h2 id="both-generations">We&#8217;re supporting both generations, not switching</h2>
<p>The new spec carries a formal deprecation policy with a twelve-month minimum window. That changes the calculation. A plugin installed on somebody else&#8217;s site has to work with whatever client that person happens to have. You do not get to pick.</p>
<p>So version negotiation decides per request, and nothing is stored between them. Two code paths, one endpoint, no session table.</p>
<p>Agencies will recognize the shape of this problem. If you <a href="https://www.macronimous.com/services/cms-development/wordpress-maintenance-services/">maintain WordPress sites for other people</a>, you already live with the gap between the version you&#8217;d like everyone to run and the version they actually run. Protocol support is the same discipline applied one layer down, and it accumulates the same way <a href="https://www.macronimous.com/blog/hidden-technical-debt-wordpress-seo/">technical debt accumulates in WordPress</a>: quietly, until a release forces the accounting.</p>
<h2 id="timing">The timing call was harder than the code</h2>
<p>Directory review takes weeks. Submitting on the previous spec would have meant being reviewed, approved and listed as already out of date, in a category where the audience reads specifications for a living.</p>
<p>A day of work against several weeks of looking dated is not a close call.</p>
<p>The engineering question was answered in an hour. The publishing question was the harder one, because the cost of shipping something correct-but-stale is paid entirely in credibility, and you cannot patch that in version 1.0.1.</p>
<h2 id="cacheable">The small win: tool lists are cacheable now</h2>
<p>One change we are quietly pleased about. List responses now carry a time-to-live and a cache scope.</p>
<p>Through the entire build, every time we added a capability, we had to disconnect and reconnect the client, because it had cached a stale catalog with no way to learn it was stale. Minor, constant, mildly maddening. Now the protocol handles it.</p>
<p>Nobody will write a headline about that one. It is the change that will show up most often in daily use.</p>
<h2 id="read-the-rest">The rest of the changelog, for WordPress builders</h2>
<p>If you are building or evaluating anything MCP-shaped on WordPress, these are the items worth reading properly in the <a href="https://modelcontextprotocol.io/specification/2026-07-28/" target="_blank" rel="noopener noreferrer">2026-07-28 specification</a> rather than skimming.</p>
<table class="styled-table">
<thead>
<tr>
<th>What changed</th>
<th>What it means for a WordPress MCP server</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sessions and the <code>initialize</code>/<code>initialized</code> handshake retired</td>
<td>Delete the handshake code. Each request carries its own protocol version and client info in <code>_meta</code>. PHP&#8217;s request model already worked this way.</td>
</tr>
<tr>
<td><code>Mcp-Method</code> and <code>Mcp-Name</code> required as HTTP headers</td>
<td>Your endpoint reads them, and anything in front of you must not strip them. Security plugins and aggressive WAF rules are the thing to test here.</td>
</tr>
<tr>
<td>List responses carry <code>ttlMs</code> and <code>cacheScope</code></td>
<td>Clients stop re-fetching your tool catalog on every connect. Adding a tool no longer means telling users to reconnect.</td>
</tr>
<tr>
<td>Sampling, elicitation and roots replaced by Multi Round-Trip Requests</td>
<td>A tool needing user confirmation returns <code>input_required</code>, and the client retries with the answers attached. No held-open stream, which PHP was never going to hold.</td>
</tr>
<tr>
<td>Dynamic Client Registration deprecated in favor of Client ID Metadata Documents</td>
<td>The long-term path away from <a href="https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/" target="_blank" rel="noopener noreferrer">Application Passwords</a> toward standard OAuth. Real, but not a migration to rush.</td>
</tr>
<tr>
<td>Legacy HTTP+SSE transport deprecated, twelve-month minimum window</td>
<td>If you built on the event stream, you have a year. If you built on single JSON responses, you have nothing to do.</td>
</tr>
</tbody>
</table>
<h2 id="simple-survives">Simple survives revisions. Clever gets rewritten.</h2>
<p>Budget for the specification moving. Not as a line in a risk register, as a genuine expectation.</p>
<p>You cannot predict which way it moves, so insulation is not foresight. What actually protected us was choosing the simplest option the spec permitted, at a moment when the constraint was our own platform rather than any theory about the future. And keeping the protocol layer thin and separate from the work, which is the same discipline we apply to <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled AI coding</a> and to <a href="https://www.macronimous.com/blog/writing-clean-code-with-ai/">keeping AI-generated code clean</a>.</p>
<ul class="mac-checklist">
<li>Take the simplest option the spec permits, especially when your own platform is the constraint</li>
<li>Keep protocol handling in its own layer, separate from the code doing the actual work</li>
<li>Support two spec generations rather than switching, if your code runs on installs you don&#8217;t control</li>
<li>Negotiate the version per request and store nothing between requests</li>
<li>Test that nothing in front of your endpoint strips <code>Mcp-Method</code> or <code>Mcp-Name</code></li>
<li>Read the deprecation policy before planning a migration, not after</li>
</ul>
<p>We got this one right by accident. That is not a method, and I would not want anyone reading this to treat it as one. A hands-on guide to connecting a live WordPress site to Claude is in progress and will follow this post.</p>
<div class="mac-cta-box">
<h3>Thinking about connecting your WordPress site to an AI assistant?</h3>
<p>We build and maintain WordPress for agencies and site owners in the US, UK and Australia, including the plumbing that makes a site readable by <a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI</a> tools rather than just by browsers.</p>
<p><a href="https://www.macronimous.com/services/cms-development/wordpress-development-india/" class="mac-cta-button">Talk to our WordPress team</a>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/">Building a WordPress MCP Server When the Spec Changed</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/building-a-wordpress-mcp-server-when-the-spec-changed/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fluency Without Keystrokes: Web Developers in the AI Era</title>
		<link>https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/</link>
					<comments>https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/#respond</comments>
		
		<dc:creator><![CDATA[Benny]]></dc:creator>
		<pubDate>Fri, 10 Jul 2026 05:10:20 +0000</pubDate>
				<category><![CDATA[AI Web Development]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AI Development]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[AI Coding]]></category>
		<category><![CDATA[AI in web development]]></category>
		<category><![CDATA[AI web development]]></category>
		<guid isPermaLink="false">https://www.macronimous.com/blog/?p=5259</guid>

					<description><![CDATA[<p>Will AI replace web developers? It will replace the part of the job that was always mechanical: translating a decided design into working syntax. It will not replace knowing what is being built, what it is built on, and why. I call that second skill fluency without keystrokes, and it is the one I have [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/">Fluency Without Keystrokes: Web Developers in the AI Era</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<a href="https://www.macronimous.com/blog/wp-content/uploads/2026/07/Fluency-Without-Keystrokes.png"><img loading="lazy" decoding="async" class="aligncenter wp-image-5263 size-large" src="https://www.macronimous.com/blog/wp-content/uploads/2026/07/Fluency-Without-Keystrokes-1024x576.png" alt="Will AI replace Web Developers" width="1024" height="576" /></a>
<div class="mac-direct-answer">
<p><strong>Will <a href="https://www.macronimous.com/blog/wordpress-7-0-ai-the-token-cost-reality-for-site-owners/">AI</a> replace web developers?</strong> It will replace the part of the job that was always mechanical: translating a decided design into working syntax. It will not replace knowing what is being built, what it is built on, and why. I call that second skill fluency without keystrokes, and it is the one I have run a development agency on since I stopped writing production code in 2005.</p>
</div>
<h2>I wrote my last production code in 2005</h2>
<p>That is not a confession. It is the whole argument.</p>
<p>I learned to program in 1991 and coded for fourteen years. Then I founded <a href="http://www.Macronimous.com" target="_blank" rel="noopener">Macronimous</a>. Within just a couple of years, my developers were writing the code and I was doing something else. In the twenty-four years since, I have not shipped a single production function. And I have never been more useful to a development project than I am right now, in the middle of the AI era everyone says will end careers like the one I supposedly abandoned.</p>
<p>Here is what I did keep doing: I watched every shift from the inside. Desktop applications to web applications. Web apps to multi-tier architectures. Multi-tier to hosted solutions. Hosted to SaaS. Now SaaS to whatever AI-assisted development turns out to be. Each time, the syntax changed completely. Each time, the underlying questions did not change at all: where does the data live, who is allowed to touch it, what happens under load, what does the client actually need versus what they asked for.</p>
<p>If your value was typing, every one of those shifts hurt you. If your value was the questions, every one of those shifts made you more necessary, because suddenly a whole team needed someone who could tell which parts of their hard-won knowledge still applied.</p>
<h2>The knowledge that survived every shift</h2>
<p>People assume that when you stop coding, the knowledge decays uniformly. It does not. The syntax goes fast. I could not write a working React component from memory today, and I do not pretend otherwise to my team. But four things never decayed, because they are not syntax:</p>
<ul>
<li><strong>Databases.</strong> Normalization, indexing, why a query is slow, why &#8220;we&#8217;ll fix the schema later&#8221; is the most expensive sentence in software. Every stack I have watched arrive, from LAMP to serverless, sat on top of the same relational logic.</li>
<li><strong>Algorithms.</strong> Not competitive-programming puzzles. The working instinct for what is O(n) and what is O(n²), and why the feature that demos fine with 50 records dies with 50,000.</li>
<li><strong>A few languages, deeply.</strong> Not many, shallowly. Once you have genuinely understood two or three, you can read almost anything. Reading is the skill that matters now; more on that below.</li>
<li><strong>Servers and deployment.</strong> What actually happens between a browser request and a response. DNS, HTTP, processes, memory. Abstractions changed names five times; the physics never did.</li>
</ul>
<p>That list, plus two decades of translating client language into developer language and back, is the entire toolkit. Notice what is not on it: any framework, any editor, any AI tool. Those are all replaceable, and all of them have been replaced several times during my career.</p>
<h2>The &#8220;that&#8217;s not possible&#8221; test</h2>
<p>The clearest place this toolkit earns its keep is a moment every project manager knows: a developer says <em>that&#8217;s not possible</em>.</p>
<p>Sometimes they are right. But over the years, especially during native mobile app projects where platform limitations are real and frequent, I developed a simple piece of reasoning for that moment. If the feature is a reasonable thing for a business to want, then someone else has almost certainly wanted it before us. Which means either the tracks are already laid, in a third-party API, a plugin, an extension, a Stack Exchange thread, or a discussion buried in some project&#8217;s issue tracker, or the tracks are absent and we get to lay them ourselves.</p>
<p>So the answer to &#8220;that&#8217;s not possible&#8221; is rarely yes or no. It is: <em>not possible the way we are currently holding the problem.</em> Go look for the tracks. More than once we found them somewhere the team had not thought to look. More than once we did not, built the workaround ourselves, absorbed cost the project budget never covered, delivered the feature anyway, and then reused that solution on later projects until it paid for itself.</p>
<p><!-- BENNY: if you want to name one concrete project/feature here, this is the spot. One or two sentences max. The paragraph above stands on its own if not. --></p>
<p>Here is the part that matters for the AI question. That reasoning move is not a coding skill. I could not have implemented a single one of those workarounds myself. But I could not have made the move without knowing what databases, servers, and APIs can and cannot do, because &#8220;reasonable thing to want&#8221; is a judgment about the underlying system, not about the client&#8217;s mood. Strip out the fundamentals and the same sentence becomes an empty pep talk.</p>
<p>Now notice what AI does to this moment: it removes it. An <a href="https://www.macronimous.com/blog/agentic-coding-domain-knowledge/">agentic coding</a> platform never says <em>that&#8217;s not possible</em>. Ask, and it builds. Ask for something unwise, and it builds that too, politely and fast. The schema that will not survive real data, the authentication shortcut, the feature that quietly breaks three others. Something ships for every request.</p>
<p>That is a more dangerous failure mode than a developer&#8217;s premature no. A false &#8220;not possible&#8221; costs you a feature. A false &#8220;possible&#8221; costs you a production incident, months later, after the demo already convinced everyone. For twenty years my job was seeing through the first. The job now is seeing through the second, and it takes exactly the same knowledge of what is underneath. The tool stopped saying no, so someone in the room has to know when the answer should have been no.</p>
<h2>What AI actually replaces</h2>
<p>Fred Brooks sorted this out in 1986, before most of today&#8217;s developers were born. In <a href="https://www.cs.unc.edu/techreports/86-020.pdf" target="_blank" rel="noopener noreferrer">No Silver Bullet</a>, he split software difficulty into essence, the specification and design of the conceptual construct, and accident, the labor of representing that construct in code. His claim was that no tool would ever give an order-of-magnitude win, because tools only attack the accident.</p>
<p><a href="https://www.macronimous.com/blog/the-code-your-ai-wants-to-delete-is-load-bearing/">AI coding</a> tools are the strongest attack on the accident ever built. We use Claude Code, Copilot, and Cursor across our React and PHP work daily, and the keystroke savings are real. But look at what developers themselves report. In the <a href="https://survey.stackoverflow.co/2025/ai" target="_blank" rel="noopener noreferrer">Stack Overflow 2025 survey</a>, 84% of developers use or plan to use AI tools, yet the most-cited frustration, at 66%, is output that is almost right but not quite. And when asked why they would still turn to a human in an AI-heavy future, the top answer was simple: when they don&#8217;t trust the AI&#8217;s answer.</p>
<p>Almost right but not quite is precisely the failure mode that only essence-level knowledge can catch. The code compiles. The demo works. The schema decision buried inside it will cost you a migration in eight months. Somebody on the team has to be the person who sees that, and that person is doing my job, not the typist&#8217;s.</p>
<table class="styled-table">
<thead>
<tr>
<th>AI replaces</th>
<th>AI does not replace</th>
</tr>
</thead>
<tbody>
<tr>
<td>Translating a decided design into syntax</td>
<td>Deciding what should be built, and why</td>
</tr>
<tr>
<td>Boilerplate, scaffolding, test stubs</td>
<td>Knowing when the answer should have been no</td>
</tr>
<tr>
<td>Looking up API signatures and idioms</td>
<td>Judging whether an almost-right answer is safe to ship</td>
</tr>
<tr>
<td>First drafts of almost everything</td>
<td>Translating client language into system language and back</td>
</tr>
</tbody>
</table>
<h2>Fluency without keystrokes</h2>
<p>So here is the concept I have been circling, and the name I would put on it: <strong>fluency without keystrokes</strong>. It is the ability to read code, architecture, and constraints well enough to reason about them, without being the person who produces them. Knowing what is being built, what it is built on, and why.</p>
<div class="mac-key-point">
<p>AI replaces keystrokes. It has no opinion about what is worth building, what it sits on, or why. The person who holds those answers was never the typist, and cannot be replaced by a better typist.</p>
</div>
<p>I want to be precise about what this is not. It is not &#8220;ideas guy&#8221; hand-waving; the fluency has to be real, tested against actual systems, or the &#8220;that&#8217;s not possible&#8221; test collapses into wishful thinking. And it is not an excuse to skip the fundamentals; the whole point is that I earned the fluency the slow way, through eleven years of coding and twenty-four years of watching code fail in production. What the AI era changes is the ratio. You no longer need decades of keystrokes to keep the fluency alive. You need the foundations, plus the habit of reading and reasoning about what the machines produce. That is why I keep arguing for a <a href="https://www.macronimous.com/blog/controlled-ai-coding/">controlled approach to AI coding</a> rather than the pure <a href="https://www.macronimous.com/blog/vibe-coding-for-web-developers-amplify-your-flow-state-with-ai/">vibe coding flow</a>: control requires exactly this kind of fluency, and exercising it is how you keep it.</p>
<h2>So how much code should you learn?</h2>
<p>Enough to read it like a native. That is the honest answer, and it is less code than the bootcamps sell and more than the &#8220;just learn prompting&#8221; crowd admits.</p>
<p>The prevailing advice right now splits into two equally bad camps. One says syntax is dead, learn to prompt. The other says nothing has changed, grind the same curriculum harder. Both camps make the same mistake: they treat coding-as-typing as the job. The job was always understanding systems; typing was just how we proved it. AI removed the proof, not the requirement.</p>
<p>If I were starting out in web development today, this is what I would actually put the hours into:</p>
<ul class="mac-checklist">
<li>One backend language learned deeply enough to debug someone else&#8217;s code in it, not three learned to tutorial depth</li>
<li>SQL and data modeling, properly. This is the least glamorous item and the one that will pay you the longest</li>
<li>How the web actually works: HTTP, DNS, what a server does, where things run and why. Trace one full request end to end until nothing in it is magic</li>
<li>Reading AI-generated code critically, every day. Ask why it chose what it chose. This is the modern equivalent of code review under a senior, and it is how <a href="https://www.macronimous.com/blog/writing-clean-code-with-ai/">clean code with AI</a> actually happens</li>
<li>The client&#8217;s language. Requirements, constraints, budget, the gap between what they asked for and what they need. No model translates this yet, and every stage of the <a href="https://www.macronimous.com/blog/web-development-life-cycle-process-flow-diagram/">web development life cycle</a> depends on someone who can</li>
</ul>
<p>Five to ten years from now I do not know whether developers will still be typing much code. I am certain there will still be code, and certain that every team will still need at least one person who is fluent in what it means. In 2002 I bet my career that the fluency mattered more than the keystrokes. Twenty-four years later, AI just proved the bet.</p>
<h2>Frequently asked questions</h2>
<div id="fluency-keystrokes-faq">
<div class="faq-item">
<h3>Is web development still worth learning in 2026?</h3>
<p>Yes, if you learn it as systems knowledge rather than syntax production. Demand for people who can type framework code from memory is shrinking. Demand for people who can read code, model data, and judge whether AI output is safe to ship is not. Learn the second skill set; the first now comes bundled with it.</p>
</div>
<div class="faq-item">
<h3>How much coding should I learn if AI writes the code?</h3>
<p>Enough to debug someone else&#8217;s code in one backend language, write real SQL, and trace an HTTP request end to end. That is less breadth than the traditional curriculum and more depth than prompt-engineering courses offer. Reading fluency is the target; typing speed is now optional.</p>
</div>
<div class="faq-item">
<h3>Which web development skills can AI not replace?</h3>
<p>Deciding what should be built and why, translating client requirements into system constraints, judging &#8220;almost right&#8221; output before it reaches production, and recognizing when the answer should have been no. Agentic tools build whatever you ask, wise or not. All four skills require fundamentals; none of them require keystrokes.</p>
</div>
</div>
<div class="mac-cta-box">
<h3>Need a team that reasons past &#8220;that&#8217;s not possible&#8221;?</h3>
<p>Macronimous has been building web applications since 2002, through every platform shift including this one. We bring the fundamentals; the AI brings the keystrokes.</p>
<p><a class="mac-cta-button" href="https://www.macronimous.com/services/custom-web-development/">Discuss your web project</a></p>
</div>
<p>The post <a rel="nofollow" href="https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/">Fluency Without Keystrokes: Web Developers in the AI Era</a> first appeared on <a rel="nofollow" href="https://www.macronimous.com/blog">Macronimous Blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.macronimous.com/blog/fluency-without-keystrokes-web-developers-in-the-ai-era/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
