Introduction
Our blog posts are written by the people who did the work. The process is simple: someone picks a topic, writes a draft, and opens a pull request. From there it goes through two passes, a review that looks for correctness issues, gaps, and overstated claims, followed by a QA pass that checks the final polish: that the whole thing ties together, there are no typos, images render correctly, and links go where they say they go.
Like a lot of teams, we started leaning on AI to help our authors get ideas onto the page. Posts get written faster and people get past their writer’s block quicker. It comes with its downsides though. Asked to fill in a gap, it will make an assumption. Asked to make a paragraph read better, it will rewrite a carefully hedged sentence into a cleaner one that means something slightly different, or expand it into a claim that can’t be sustained. So AI helped our authors move faster, but it created a good deal more work for the reviewers. It didn’t remove a bottleneck, it moved it downstream.
To help with this, I built an assistant for our blog writing process. In this article, I’ll talk through why I built it, how I decided what it should be, and what it has done for our writing process so far.
Solving the AI problem with more AI is a bit counterintuitive, but some battles we are not going to win, so it’s better to make it work for us than to try to prevent it from being used. The useful thing to build here was a properly constrained version of the tool people were already using. It has two pieces: an MCP (Model Context Protocol) server that knows our blogs: what we have published and how we write, and a Claude Code plugin the team uses to suggest topics, plan a post, draft it and review it before a pull request is ever opened. The whole thing took about ten hours to put together, which is most of the point. It was cheap, it was easy, and so far it looks like it’s working. AI solutions don’t have to be complex, and not everything needs to be a custom agent.
The problem to solve
We are committed to the quality of our content, and reviews are thorough and done by experts on the topic. Naturally, for some topics, we have fewer reviewers than authors. This means what looked like a productivity gain driven by AI was in fact a productivity decrease. Reviewers received more posts, saw more things to flag, posts saw more rounds of reviews, reviews took longer. That came back around to the authors too: more feedback to work through and more back and forth before a post could ship.
Not only that, but the style of writing started to shift. AI introduced its own way of writing and organizing information, and most reviewers won’t flag every little instance of this happening. It feels like a nitpick, and at the end the content reads just fine. This is a problem though. Our content stopped sounding like us, like our voice.
On top of that, with more than 400 articles published across OmbuLabs.ai and FastRuby.io , it’s very hard for one person to keep track of everything we’ve published. So cross-references got missed, redundant content got shipped, and opportunities for creating a series or deepening a topic never surfaced.
Why an assistant
We’re no stranger to automation. In fact, we’ve built a few internal tools on that basis: an LLM assistant that drafts the article summaries for the FastRuby.io newsletter , Pecas , which flags problems in our time entries, and another one that handles our quarterly maintenance reports . We believe that humans should spend time on the things that need a human brain, and automation should take care of the boring bits.
This problem was no different. The accuracy issues were eating reviewer time and the style issues were slipping through, and both were landing on the same people who were already the bottleneck. What we needed to do was:
- Cut down the time our reviewers were spending on each post;
- Improve the quality of drafts before they ever got to review;
- Do it in a way that let our authors keep using AI wherever they find it helpful, because they’re going to either way, and because it does help.
None of that is a writing problem, so a tool that writes better wasn’t going to fix it. What we needed was a tool that knows things: what we’ve already published, what our house style actually is (rather than what we’d say it is if someone asked), and which sentences in a draft are making claims that somebody needs to check.
Deciding what to build
Knowing what we needed didn’t tell me what to build. There are a lot of different ways to solve the problem, and when Large Language Models (LLMs) are involved, there are a lot of fancy, complex ways that sound appealing (but ultimately aren’t worth it). I explored a few different possibilities:
A reviewer running in CI
We already have a tool like this that checks for grammar issues and typos. Plugging something into that would be a viable option.
This was quickly discarded though. It isn’t interactive enough, it’d need to focus on the review aspect and catch issues after they are there. Also, to make sure issues wouldn’t slip through, the goal was to make the AI reviewer very nitpicky. This would result in a lot of comments in the PR that nobody has the time to go through and hurt the conversation that can happen between two people in the PR itself. In other words, it makes things worse for both author and reviewer.
A well-crafted prompt
Write it once, share it with the team. Simple enough, cheap, and it’s where the whole thing starts, how you prompt the LLM.
However, the issue we have at hand is dynamic in nature, and the shared prompt would be static. It’d need to have categories, existing keywords, and references hard-coded into it. All that is stale the minute a new keyword is added, a category is added, or references shift with time.
It also has no concept of related posts or per-author style and expertise, so it doesn’t do much to help find a topic, flesh out an idea, or even review a post by a particular author. A lot of maintenance for a subpar result.
A custom agent
We hear this a lot. I have this problem, I think AI can help solve it, I need an agent. Agents are dynamic, can tackle complex tasks, can call tools and access external data, perfect for this. This would have, in fact, been a valid solution. But an agent needs a place to live, it needs maintenance, and it needs a significant amount of upfront work to work as intended.
Our workflows aren’t complex, the amount of data involved in this is small, and it really just needs to make the tool people are already using better. Anthropic built us a perfectly good agent, we just needed to make it a little bit more specialized. It needs data, not custom pipelines, workflows, and complex actions.
What we built
The last point settled the solution: let’s build something within Claude Code that extends its knowledge of our domain without relying on people telling it stuff. There are several ways to do that, and two of them fit what I needed: an MCP server for giving it access to our data, and a plugin for packaging up the workflows and shipping them to the team. So that’s what I built, a plugin and an MCP server.
Nothing in life is as easy as it sounds though. In order for the MCP to be effective, we needed the data it’d be exposing to be structured and available. As happens in most of these cases, it wasn’t.
So the first thing I built was a very simple data pipeline. It pulls the markdown files from both blogs’ GitHub repositories, reads the block of metadata at the top of each one, and loads the posts into a Postgres database along with their categories, content types, keywords and authors. It also creates an embedding for each post, a numeric summary of what that post is about (stored with pgvector , a Postgres extension built for this kind of data). Two posts that cover similar ground end up with similar numbers, which is what lets the assistant find related posts by meaning rather than by matching keywords.
On top of that database sits the MCP server, which exposes tools, meaning things the assistant can do, and resources, meaning documents it can read. The taxonomy resource is generated live from the database, so the list of valid categories, content types and keywords is whatever we are actually using today rather than something written down once and left to go stale. This makes it much more useful than just asking Claude to do a web search against our blogs. It allows it to see all available categories, top keywords, find the posts closest to a draft, pull stats on the content, and so on. It also exposes tools like style checks, looks for common antipatterns, and tools that validate the metadata at the top of a post.
The plugin complements it by holding the workflows. It determines the steps to follow to suggest a topic, plan a post, draft one, and then review it. It works the same for every author, it pulls from one source of truth, but it still has author-specific context available to it.
The split matters. Anything that is true about the blogs lives on the server, so when a style rule changes or a new pattern to look for needs to be added, the change applies to everyone at once. And when something in how we work changes, or we want to improve a workflow, the change applies to the plugin through a pull request like any other, and everyone gets it at the same time.
For an author, this means they can get better, more relevant topic suggestions, higher quality drafts, and less back and forth on reviews as issues get flagged early. Human reviewers are not replaced, we still need an expert to review the post and catch anything the tool can’t. It just helps reduce the number of things left for them to catch, and how much slips through.
Apart from the metadata validation, none of what the automated reviewer flags is a hard rule. Issues flagged in review can be ignored and the post will move forward all the same. The author still decides.
What it cost
The whole point here was simplicity. A quick but effective solution for a problem that’s been bugging us for months.
Those ten hours were a flight from Atlanta to São Paulo (so it’s not like I had anything better to do anyway), and this was enough because of everything I left out. There’s no custom interface, the interface is Anthropic’s problem. There’s no user management, because access to the repository is access to the plugin. There’s no orchestration layer, nothing coordinating a chain of steps, because the skills are markdown files that describe what to do and in what order (we’ve written about how to write a Claude Code skill before). Nearly every part of this that would have taken real time to build is a part I decided I didn’t need.
On the other side of the ledger, we expect this to cut the time spent reviewing a post, and the back and forth that comes with it, by something in the region of thirty to forty percent. The early results have been better than that, but we’re being careful with them: it’s a small number of posts so far, and those posts had already been through part of our usual process before the tooling saw them, so the comparison flatters the tool. We’re treating the early numbers as encouraging rather than settled. Even at the conservative end, the time being saved belongs to the people who are hardest to free up, and ten hours is not a lot to spend to get some of it back.
Conclusion
There’s nothing especially sophisticated about this assistant. It’s a data pipeline, a database, an MCP server that exposes what’s in it, and a handful of markdown files describing how we work. Ten hours and around $2,000 worth of time, against the weeks and the tens of thousands a custom agent would have cost to build and keep running. Most of the effort went into working out what those pieces needed to do, and that part had very little to do with AI.
One thing worth being explicit about though is that this worked because our writing process was already well-established. We knew what the steps were, who did them and where they got stuck. Automating a workflow you don’t understand very well tends to produce a tool nobody uses or, worse, one that makes the confusion happen faster. If you’re looking at your own process and wondering where AI fits into it, that’s the part to get right first. We go deeper into that in Finding the Right Problems to Solve with AI .
Got a workflow where AI would obviously help, but you’re not sure what to actually build? Let’s talk!