Automating Content Workflows Without Producing Slop
A practitioner’s guide to content automation that doesn’t produce slop: evidence-first briefs, CI quality gates, WordPress guardrails and metrics that matter.
We audited a content pipeline last spring that had shipped 214 posts in seven months. Eleven of them had ever received a single organic impression. The client was thrilled with the throughput dashboard and confused by the flat traffic line, which is a very specific kind of expensive.
The problem wasn’t the model. The drafts were grammatical, on-topic and structurally tidy. They were also interchangeable: every post opened with a definition, hit five headings pulled from the same SERP, and closed with a paragraph that encouraged the reader to “consider their unique needs.” Nothing in any of them could only have been written by that company. That’s slop, and no amount of prompt tuning fixes it, because the fault is in the pipeline design, not the generation step.
Good content automation is mostly plumbing and gates. The generation is the easy part now. What separates a pipeline that compounds from one that fills an index with dead pages is what you feed it, what you check before publish, and where you put the human.
- Slop is a sourcing failure, not a writing failure. If the model has nothing specific to work with (no internal data, no transcripts, no measurements) it will fill the gap with generic plausibility, every time, regardless of prompt quality.
- Automate research collation, formatting, schema, alt text, internal link suggestions and distribution. Do not automate the argument, the examples or the opening.
- Machine-checkable quality gates catch roughly 70 percent of slop signals before a human reads the draft: banned phrase lists, sentence length variance, unsourced numeric claims, heading-echo openings and intro duplication across the corpus.
- Never give the pipeline publish rights. A bot user with
draft-only enforcement at the REST layer costs ten lines of PHP and prevents the failure mode everyone eventually hits. - Kill volume as a KPI. Measure the percentage of posts that earn impressions within 90 days. If it’s under 60 percent you are producing liability, not assets.
What slop actually is, technically
“AI slop” gets used as a synonym for “written by a model”, which is lazy. Plenty of model-assisted writing is excellent. What people are reacting to is a cluster of measurable properties, and once you name them you can test for them.
- Unfalsifiable claims. “Performance improves significantly.” Improves by how much, measured with what, on which hardware? A sentence you cannot argue with carries no information.
- Structural sameness. Uniform paragraph length, uniform sentence length, every section three paragraphs, every list three items. Human prose is lumpy.
- Heading echo. The first sentence of each section restates the heading. It’s the single most reliable tell.
- Zero first-hand input. Nothing that required access: no support ticket, no log line, no client conversation, no failed deploy.
- Hedged everything. No position, no trade-off, no case where the advice fails.
Four of those five are detectable with a regex and a standard deviation. That’s the whole opportunity.

Automate the boring 80 percent, never the argument
Map your pipeline as discrete stages before you automate anything. Ours, on client retainers, looks like this: intake, source pack assembly, brief, draft, edit, format and markup, internal linking, media, publish, distribute, refresh.
Safe to fully automate: source pack assembly (pulling transcripts, analytics exports, GitHub issues and support tickets into one retrieval bundle), formatting and markup conversion, schema generation, image compression and alt drafting, internal link candidate suggestion, social variants, and the refresh queue that flags posts whose data has aged past a threshold.
Never automate end to end: the opening, the central claim, the worked example, and the “here’s where this advice breaks” paragraph. Those need someone with scars. On a technical post about database bloat, the value was one specific number from one specific client install: 148,000 autoloaded option rows adding 6MB to every page load. No model invents that. A model given that fact writes a good section around it.
The ratio we land on repeatedly is 80 percent machine time, 20 percent human time. The 20 percent is the expensive part. Do not try to shrink it.
Design the ai content workflow around evidence, not prompts
Most teams start at the prompt. Wrong end. Start with the input contract: a structured brief that cannot be filled in without specifics. If the brief is empty, the post doesn’t get written. That single rule eliminates more slop than any system prompt.
// briefs/wordpress-caching.json
{
"slug": "wordpress-caching-explained-layers",
"angle": "Most 'slow WordPress' tickets are object cache misses, not missing page cache.",
"mustincludefacts": [
{ "claim": "Redis object cache cut TTFB from 840ms to 190ms", "source": "client-a/newrelic-2026-01-14.csv" },
{ "claim": "Page cache hides the problem for anon traffic only", "source": "internal/notes/cache-audit.md" }
],
"counterpoint": "On a 12-page brochure site, object caching is not worth the Redis dependency.",
"internal_links": ["choosing-wordpress-hosting-guide", "choose-wordpress-theme-core-web-vitals"],
"banned_angles": ["generic 'why speed matters' intro"]
}
Every fact carries a source path. The generation step gets the brief plus the referenced files as context, and a rule: no numeric claim may appear in the draft unless it traces to mustincludefacts. This is retrieval, but scoped to your own material rather than the open web. That’s what makes the output yours instead of a remix of the top ten results.
Structure your prompts so they survive model swaps. We covered the durable patterns in prompt engineering for developers: separate instructions from data, demand structured output, and never encode model-specific incantations you’ll have to unpick in six months. If you’re wiring tools into the pipeline rather than pasting context by hand, MCP is now the least painful way to give a model read access to your analytics and repo without building a bespoke integration per tool.
Quality gates you can run in CI
Treat drafts like code. Ours live as Markdown in a repo, and nothing reaches an editor until it passes a check script. Here’s a trimmed version of what runs on every pull request.
// scripts/slop-check.js (node 22+, uses fs.globSync)
import { readFileSync, globSync } from "node:fs";
const BANNED = [/\bdelve\b/i, /\bin today's\b/i, /\bseamless(ly)?\b/i, /\brobust\b/i,
/\bgame[- ]changer\b/i, /it's important to note/i, /\bleverag(e|ing)\b/i];
const fail = [];
for (const file of globSync("content/**/*.md")) {
const raw = readFileSync(file, "utf8");
const body = raw.replace(/^---[\s\S]*?---/, ""); // strip front matter
const sentences = body.split(/(? s.length > 10);
const lengths = sentences.map(s => s.trim().split(/\s+/).length);
const mean = lengths.reduce((a, b) => a + b, 0) / lengths.length;
// Low variance = every sentence the same shape. Human prose sits well above 6.
const sd = Math.sqrt(lengths.reduce((a, l) => a + (l - mean) ** 2, 0) / lengths.length);
if (sd < 6) fail.push(${file}: sentence length SD ${sd.toFixed(1)} (monotone rhythm));
for (const re of BANNED)
if (re.test(body)) fail.push(${file}: banned phrase ${re});
// Heading echo: first sentence after an H2 reusing 3+ words from the heading.
for (const [, heading, next] of body.matchAll(/^##\s+(.+)\n+(.{0,160})/gm)) {
const words = heading.toLowerCase().match(/[a-z]{4,}/g) ?? [];
const hits = words.filter(w => next.toLowerCase().includes(w)).length;
if (hits >= 3) fail.push(${file}: heading echo under "${heading}");
}
// Numbers without a nearby citation marker.
for (const line of body.split("\n"))
if (/\b\d+(\.\d+)?\s?(%|ms|MB|GB|x)\b/.test(line) && !/\[\^|\[.+?\]\(/.test(line))
fail.push(${file}: unsourced figure -> ${line.trim().slice(0, 80)});
}
if (fail.length) { console.error(fail.join("\n")); process.exit(1); }
console.log("clean");
Add Vale on top for house style and you have two layers that cost nothing per run. The sentence-variance check is the one people are sceptical about until they run it across their archive. Model-drafted posts typically land at a standard deviation of 4 to 6 words. Posts by our senior writers sit between 8 and 13. Not a perfect proxy, but as a pre-human filter it is brutally effective.
One honest caveat: these gates produce false positives on reference documentation and changelogs, where uniformity is correct. Scope the check to content/blog/** and leave docs alone.
Put the human where the judgement is
The usual editorial setup is backwards: the machine drafts, the human tidies. Tidying is exactly the task machines are now better at, and it’s the task that burns out editors. Invert it.
Our two-pass model: the editor spends 20 minutes before generation writing the angle and the counterpoint into the brief, then 30 to 40 minutes after generation doing three things only. Check every sourced fact against its source. Rewrite the opening and the closing in their own voice. Add the paragraph about where the advice fails. Line editing, heading hierarchy, alt text and link formatting are machine work.
Cost-wise, this is what makes the maths work. A 1,800 word draft with a 40,000 token source pack costs well under a dollar at current frontier pricing, and if you care about the trade-offs between providers we went through them in choosing an LLM API. The editor hour is the real cost. Spending it on fact-checking and voice rather than comma placement is how you scale content quality instead of just output.
Publishing plumbing: never give the bot publish rights
Every team eventually has the incident where a half-finished draft goes live, or 40 posts publish at once because a loop didn’t break. Enforce it at the server, not in the script.
<?php
// mu-plugins/content-bot-guardrails.php
addfilter( 'restpreinsertpost', function ( $prepared, $request ) {
$bot = getuserby( 'login', 'content-bot' );
if ( $bot && getcurrentuser_id() === (int) $bot->ID ) {
$prepared->post_status = 'draft'; // pipeline can never publish
$prepared->post_author = (int) $bot->ID; // keeps provenance honest in the list table
}
return $prepared;
}, 10, 2 );
// Stop 300 machine drafts from bloating wp_posts with revisions nobody reads.
addfilter( 'wprevisionstokeep', function ( $num, $post ) {
return 'post' === $post->post_type ? 5 : $num;
}, 10, 2 );
Give the bot a custom role with editposts and uploadfiles only, authenticate with an application password scoped to that user, and rotate it. While you’re there, set the revision cap. A pipeline that writes back on every edit will happily generate 60 revisions per post, which is how you end up with a 400MB wp_posts table on a site with 200 articles.
Internal linking deserves its own guardrail. Let the pipeline suggest links from your existing taxonomy and let a human accept them, because automatic link injection produces the dense, meaningless link webs that make a site read like an SEO farm. The system we use is described in internal linking in WordPress.
Measure assets, not articles
Throughput dashboards lie. Swap them for these four numbers, reviewed monthly:
- 90-day impression rate. Share of posts published 90+ days ago with more than 100 Search Console impressions. Below 60 percent, stop publishing and fix the brief process.
- Correction rate. Factual errors caught after publish, per 100 posts. This is your trust metric. Ours has to stay at zero for client work, which is why every figure traces to a file.
- Editor minutes per published post. If this drops below 25, quality is slipping, not improving.
- Refresh coverage. Percentage of the top 20 traffic-earning posts updated in the last 12 months. Automation is far better spent here than on new posts, and search engines reward it more reliably. The mechanics of what gets rewarded versus flattened are covered in AI and SEO.
None of these is “posts published.” The moment volume becomes the target, someone will hit it, and they’ll hit it with slop.
Frequently Asked Questions
Does Google penalise AI-generated content?
No, Google’s stance since the 2023 guidance update has been that automation is fine and low-value content isn’t, regardless of how it was produced. What gets flattened is scaled content abuse: mass pages built to game search with no original value. A model-assisted post grounded in your own data and reviewed by a named editor is not that, and in our experience ranks exactly like any other post.
Are AI detectors worth running as part of the pipeline?
No. They produce false positives on clean human writing (especially technical prose and non-native English) and false negatives on lightly edited model output, so you’d be gating on noise. Test for the properties you actually care about instead: unsourced claims, monotone rhythm, missing counterpoints. Those correlate with reader value; detector scores don’t.
How many posts a month can one editor realistically handle?
With a working pipeline, 12 to 20 posts of 1,500 to 2,000 words, assuming roughly an hour of total editor time per post split before and after generation. Push past 25 and the fact-checking pass quietly becomes a skim. That is the exact point where corrections start appearing in your archive.
Should the drafts live in WordPress or in a Git repo?
Git, if you have any engineering capacity at all. You get diffs, pull request review, and the ability to run lint gates in CI before anything touches the CMS. Push to WordPress via the REST API only once the draft has passed, with the bot user locked to draft status as shown above. For non-technical teams, a Google Docs plus review-checklist workflow is a legitimate fallback, but you lose the automated gates.
What’s the single highest-leverage thing to automate first?
Source pack assembly. Pull the support tickets, analytics exports, call transcripts and issue threads relevant to a topic into one bundle before anyone writes anything. It’s unglamorous, it takes a day to build, and it changes output quality more than any prompt rewrite because it removes the vacuum that generic writing fills.
If you take one thing from this: the quality of a content automation pipeline is set at the input stage, not the generation stage. Before you touch another prompt, build the brief schema with mandatory sourced facts and a mandatory counterpoint, then refuse to run the pipeline on an incomplete brief. Do that this week. The gates, the guardrails and the metrics can follow, but without the evidence contract they’re just a nicer-looking way to produce the same 214 posts nobody reads.

