October 20, 2026 · Jan Hoppe
A Content Repository Instead of a CMS: How an AI Agent Keeps Content, Tone of Voice, and SEO Together
A CMS manages pages. A content repository manages the knowledge about your content – tone of voice, audiences, keywords, facts – and an AI agent works with it. What that looks like at produktkraft.com: from changes across all pages to the podcast workflow, with two seed prompts to build your own.
At the end of the article on the website builder alternative, I claimed that the real reason not to want to go back to a website builder isn’t the technology at all. It’s that a change across all pages can be done in a single, reviewable commit. Now I’m making good on that claim.
Because the stack of static site, Cloudflare Pages, and AI agent is only one half. The other half is what lives inside it: the content – and everything you need to know about it to write it well. A CMS manages pages. What I describe here manages the knowledge about your content: how you sound, who you write for, which page targets which keyword, which statements about you are backed up and which aren’t. I simply call it a content repository. Content management without a CMS, if you like.
Content Management Without a CMS: What Goes into a Content Repository
The idea isn’t new. Technical writers have been calling it docs as code for years: documentation is written with the same tools as code – Git, text files, reviews, automated checks. What’s new is that an AI agent works inside it. And that suddenly makes the principle worthwhile not just for developer documentation, but for every website, every blog, every podcast.
I’ll show you what such a repository looks like using produktkraft.com as an example. It holds four things:
- The existing content. Every blog article, every page, every podcast episode as a Markdown file.
- The rulebook. A
context/folder with files on tone of voice, positioning, audience, SEO, keywords, glossary, linking rules. Everything that otherwise sits in a brand guidelines PDF nobody opens, or in the heads of two people who happen to be on vacation. - The skills. Recurring workflows as instructions for the agent – all the way up to a complete production line for the podcast, which would otherwise take half a dozen tools and a lot of copying back and forth. Plus checks for tone of voice and SEO.
- The templates. One template per content type, with all the fields the website needs.
On top of that comes an instruction file in the root folder that the agent reads at the start of every session. It doesn’t contain the rulebook itself, but what always applies – in my case, things like “Don’t make anything up” or “Checking and changing are separate” – and where the rest lives. As AGENTS.md, it has meanwhile become an open format that, according to its own site, is used by more than 60,000 open-source projects and stewarded by the Linux Foundation. Claude Code reads the same thing as CLAUDE.md.

The website itself lives in a second repository next door. The two are separate because content and code move at different speeds – a new podcast episode is a content change, not a reason to touch the website’s code. The second reason is content bleeding. An agent that builds components and writes texts in the same repository has both in its context at the same time: rules for code and rules for language, file names and tone of voice, build errors and audiences. I don’t have evals for this. But I’d be very surprised if that mix didn’t confuse the agents – and when they’re separate, each agent only works with the context it needs for its task. How the content still gets onto the website is covered further down.
One Change, Every Page
Here’s the point I promised. In a website builder, a change that affects many pages is a click marathon: open every page, find the spot, change it, save, hope you didn’t forget one.
I know firsthand what that feels like. In school and at university, I had several jobs as a content editor, and it’s grueling work: page after page the same change, hour after hour, and at the end you still miss that one spot. That’s exactly what drove me when I started with the content repository. I thought: surely it doesn’t have to be like this anymore, right?! So I tried out the concept with the two repositories – and it worked.
In a content repository, a change like that is one sentence to the agent – and the result is a commit you can review line by line before it goes live.
A few examples from my own repository:
A link moves. My appointment booking used to run through Google Calendar and now runs through Cal.com. The agent found and changed the three blog articles that offer the appointment in the body text, and the text snippet they come from, checked beforehand that the new link was reachable – and noted that the link in the navigation lives in the website repo and has to be set there. Four files, one commit, one note on where the rest lives – instead of endlessly poking around the website and still not being sure at the end whether you found every spot.

A mistake that’s everywhere. The chapter markers of my podcast episodes were, at the median, 43 seconds too early – in all 21 episodes, because the script that had set them searched in the wrong place. After the fix, 93 of 94 markers are accurate to within three seconds, cross-checked against the transcript of each MP3. In a website builder, I wouldn’t even have noticed.
Existing content that should match the rulebook. Once the rulebook was in place, the old blog was run against it in one pass: 32 instances of the informal “you” (Du/Ihr) written in lowercase, 31 missing alt texts, 19 headings formatted in bold as a leftover of the old website builder, four meta descriptions that were too long. Just as important as what was changed: the commit message states what was deliberately not touched – the mangled URLs, because a changed URL breaks every link.
A contradiction only a machine takes seriously. On my homepage, one spot said “10+ years” of experience, another “12+.” For a person, that’s a bit of fuzziness. For a language model reading the page, it’s a reason to trust neither number – and that very self-description flows into the structured markup and into the llms.txt. Now the valid number sits in one place in the rulebook, and every text that needs it pulls it from there. Why it matters so much to be read correctly by language models was the topic of my episode about AI-first startups with Henrik Roth.
The bigger example comes from ganzheit, the documentation platform for psychotherapists, whose website runs on the same principle. Imagine you launch a feature that answers questions asked all over your site. At ganzheit, that was the option to sign a data processing agreement – a topic that appears on the product pages, in the FAQ, and in the questions at the end of many blog articles. With the launch, the agent updated six pages and nine blog FAQs in one go – in five minutes. Afterward, another ten blog articles were added. And because the changes to the website went out there as a pull request, they could be timed to the feature’s release – not before, not forgotten.
If you’ve ever updated half a website after a feature launch, you know how often the old wording still turns up somewhere afterward.
Landing Pages from What’s Already There
The same logic also works in the other direction: not changing existing content, but building new content from it.
At ganzheit, a new audience came along in the fall: systemic coaches, for whom the app got its own coaching mode. They needed their own entry point on the website, but not a second positioning. So: a landing page – and most of the material for it was already in the repository. The data protection sentences came verbatim from the FAQ and the compliance rules, with the explicit instruction not to rephrase them. The homepage’s core message was translated for the new audience, and for that there was a new rule in the audience document: with coaches, people are called “coachees,” never “patients,” and therapeutic vocabulary stays out. The pricing line follows the homepage’s pattern, and the customer quote comes from the file of approved testimonials.
From the first text commit to the built, fine-tuned page took about three hours. Of that, at most 30 minutes were active work – the rest was waiting, reading, approving. And the same text now also produces the A4 handouts that coaches can give their coachees.

The same goes for a campaign. A campaign landing page is rarely a new idea, but a sharpening: one audience, one objection, one proof. Nobody needs to write the objection and the proof for you from scratch; they’re in your pages, your testimonials, your FAQs. What the agent needs is a short brief – for whom, against which objection, with which evidence – and access to everything that’s already there. What it doesn’t need is a blank page.
The Podcast Is the Content, the Rest Is Legwork
The difference is clearest with the podcast – and this is also where I like it most. Because the actual content of an episode is the conversation. I hold it, no agent can take that off my hands, and it shouldn’t. Everything around it is legwork: transcribing, setting chapters, picking out highlights for the teaser, writing the episode page, announcing the episode. Today, all of that is started by one command, /podcast-episode, which calls the sub-steps one after the other and records the status in one file per episode:
- Transcription. The rough cut is transcribed locally with Whisper, on my own computer, without the recording being uploaded anywhere – measured at just over eight minutes for 94 minutes of audio. Whisper understands fluent German speech very well, but reliably mangles English technical terms and names pronounced the German way. For that, there’s a glossary in the rulebook that pulls every known misspelling to the correct form.
- Cleanup. The agent assigns speakers, removes filler words and slips of the tongue, and adds chapter headings – following the structure of the conversation, not spread evenly over the running time. The rule for this sits at the very top: cleaned up, not cut. No content is dropped, none is added.
- Highlights for the cold open. Every episode begins with a montage of the guest’s statements before my intro starts. I used to search for these moments in the conversation by hand. Now the agent marks ten candidates with exact timestamps in the rough cut during transcription, I pick four to six of them, and audio post-production cuts the montage from them in parallel.
- Episode page. Title, teaser, text, SEO fields, links, chapter markers. Three title variants, and I make the choice. The chapter marker times are measured against the finished MP3, not taken from the raw transcript – the finished episode has the cold open at the front, and for episode 23 that pushed everything 70 seconds later.
- LinkedIn post. The announcement post with hook, technical terms, and the fixed blocks – on LinkedIn, even emojis are allowed, in fixed positions, which are banned on the website.
- Social clips, on request. One-minute clips that have to stand on their own without context. Because they come from the unedited recording, whose timeline doesn’t match the rough cut, the agent doesn’t deliver timestamps here, but the quote text I search for in the editing tool.
And then it goes into publishing, again without me copying anything back and forth: the agent writes the file the website reads, creates the episode in the website repo, brings the cover and banner into the right formats, and uploads the MP3 to R2 – with a check before and after that the file there is exactly the one whose size is in the feed. Two steps deliberately stay with me: the okay for the upload and the push, because the push is live.

What used to be a transcription service, editing notes, text editor, CMS, upload form, and LinkedIn draft is today essentially a “go ahead” – and I read, choose, and approve.
None of these steps is particularly hard on its own. But each is full of details you’ve forgotten by the third time – and those are now in the repository instead of in my head.
That’s worth more than it sounds. If, like me, you freelance for several clients and are founding a startup at the same time – which is a bit crazy, but works 🙃 – you know how closely you have to keep an eye on your own mental load. Every detail that no longer has to live in my head is room for another topic that is more important or more urgent right now.
The LinkedIn post shows how the repository learns. In the end, the post for episode 23 didn’t go out the way the agent had written it: the first line was missing the guest’s previous positions, and instead of a list of links, the platforms were written out as text. So the version that was actually published was written back into the repository. The next post therefore isn’t based on the draft, but on what really went out.
Mistakes find their way into the rules the same way. On the first run, the web research on the guest delivered a wrong job title, and companies that had been consulting clients rather than former employers – they nearly ended up in the title as “ex” positions. Since then, the skill says: every guest introduces themselves in the first few minutes, and that self-introduction takes precedence over any research. Every mistake the agent makes twice becomes a rule.
A Tone of Voice That Doesn’t Gather Dust in a PDF
Every company above a certain size has brand guidelines. Most of them sit as a PDF in a folder, were presented once, and since then only get sent out during onboarding. Hardly any text is actually checked against them, because nobody can manage that.
In the content repository, they live as a file, and the agent reads it for every text. Mine is called tone-of-voice.md, and it contains no adjectives like “approachable, competent, fresh,” but rules with evidence: which words I use and which never, how I build sentences, which openings work – each with real sentences from published texts. The most frequently broken rule sits at the very top: whether I write “Du” (the informal singular “you”), “Ihr” (the plural “you”), or “wir” (“we”) depends on who is addressed, not on the channel. Every text records in its header which form applies to it.

Two principles have turned out to matter more than any single rule.
The existing content is the benchmark, not the rule. When a check flags a published text that works well, the text isn’t wrong – the rule is miscalibrated. Rulebooks derived from wishful thinking instead of your own best material produce texts that sound like a rulebook.
Checking and changing are separate. The ton-check skill only reports – with the location and the rule violated – and never changes a file. Only text-redigieren (text editing) may make changes, and it asks first how deeply it should intervene: correction, tightening, or revision. Every correction remains a decision. An agent that silently “improves” things will grind your voice down to the average in a few weeks.
Here’s what that looks like in practice – the tone check over the draft of this article during editing. Among other things, it flags a list for which it finds no evidence in the repository. The list is right anyway, so it stays. The check reported; I decided.

And the tone of voice doesn’t stand still. The most important step for that is surprisingly simple: at the end of a long session, I ask the agent what we’ve learned that we should record in the context. Which wording did I reject three times? Which rule didn’t work? What did I decide that isn’t written down anywhere? That becomes a change to the rulebook – as a pull request, not as a meeting. I read the diff, accept what’s right, and discard the rest. That way, the tone of voice grows a little with every text instead of being renegotiated once a year in a workshop.
SEO and Audience as a Check, Not a Gut Feeling
The same goes for SEO. In a website builder, there’s a plugin that shows a traffic light. In the content repository, there’s a file with rules and a skill that checks against it: Is the primary keyword at the front of the title? Does the meta description have 140 to 160 characters – measured, not estimated? Is the slug descriptive? Does the text link to at least one related piece of your own content?
The real gain, though, lies in a file no plugin knows about: the keyword inventory. It records which primary keyword is assigned to which piece of content. Two pages targeting the same search term take each other’s position – and that happens faster than you’d think. In my own podcast archive, four episodes target “KI im Produktmanagement” (AI in product management). That can’t be fixed anymore without breaking URLs. But it won’t happen a fifth time, because every new text now gets its keyword from the inventory before the research begins.
It works the same way for the audience. In my positioning, it says who I write for and what may be said about my offering. At ganzheit, there’s a separate check that tests texts against the audiences – and for the coaching page, two of its passes were moot, because they’re written for psychotherapists. That’s a finding too: a new audience isn’t just a new page, but a new rule.
Content Sync: How the Content Gets onto the Website
That leaves the question of how the content gets from one repository into the other. At produktkraft.com, a command in the website repo does that: pnpm content:sync. It copies exactly what belongs on the site: blog articles, pages, and two files from each podcast episode. Working documents such as the title variants with their rationales deliberately stay out. On top of that, the sync writes a small file that records which commit of the content repository the copy comes from. That way, every build can be traced to a state of the content.

Sounds like a detail, but it isn’t one. At ganzheit, a sync once picked up a draft of the homepage that only existed in the content repository as local, not-yet-committed work. The website template no longer found the section it expected, and the build failed. Since then, one rule applies without exception: only what is on main in the content repository goes onto the website. A draft is work in progress, not a state.
At ganzheit, there’s also the return path. Fine-tuning on the website constantly creates a need for text changes – breaking a headline differently, shortening a button. Forbidding that would be impractical. So the text may be changed on the website, a check reports the discrepancy, and a second command writes the change back into the content repository without committing it there. The editorial team reviews and decides. The rule behind it carries over to almost any organization: discrepancies may arise; they just have to be visible and have a way back.
The Repository as a Brain
If I had to sum up everything so far in one sentence, it would be this: the content repository is the one place that knows the content context of every area.
It holds the positioning, the offering, the audiences, the keywords, the glossary, the tone of voice – and all the existing content. That’s why an episode page can point to the article that goes deeper into the topic, because the agent finds it in the same repository. That’s why a LinkedIn post matches the tone of the website. That’s why a landing page adopts the data protection sentence verbatim instead of phrasing it slightly differently for the third time.

At ganzheit, this now goes beyond the website and blog. Performance marketing also has its own repository, and it pulls prices, terminology, positioning, and the compliance rules from the content repository via sync. That way, an ad can no longer promise what the website stopped saying long ago. Maybe there’ll be a separate article on that soon – feel free to write to me if you’re interested.
And the brain has a memory. Every change is a commit, and every commit message can explain why a text is the way it is. Why does the homepage say “12+”? Why is this URL mangled, and why does it stay that way? Why doesn’t this one line appear in the LinkedIn post? The answer is in the history, not in the head of a person who left the company two years ago. And if a change was wrong, it’s reverted with one command instead of being reconstructed.
A Little Git Is Unavoidable – but Less Than You Think
Now the objection that every comparison of Git-based and classic CMSs raises: for non-technical editors, a Git workflow is a hurdle, and approval chains, roles, and previews are missing. That’s true, and I don’t want to downplay it. Anyone on a marketing team who is supposed to work with a content repository has to learn a bit of Git – what a commit is, what a branch is, why you don’t write directly to main.
But the barrier to entry is lower than it sounds. A Markdown file can be edited right in the browser, on GitHub as well as on GitLab: open the file, click the pencil icon, change the text, look at the preview, “Propose changes.” That turns into a pull request or merge request, and that’s exactly the approval chain that’s supposedly missing. Someone sees the change, comments, approves. The checks run automatically along with it. And as for the visual interface: that’s replaced by the agent, which you tell in plain language what you want. If you’d still rather click, Git-based editors like Decap CMS or TinaCMS offer a middle ground.
The best part, though, is something else: the file is also the briefing. The header of every file doesn’t just hold what the website needs – title, URL, meta description – but also how the content should be executed: for which audience, for which keyword, in which form of address, in which status, with which assignment. On ganzheit’s coaching page, there are even dedicated “Hinweise zur Umsetzung” (implementation notes) below the text, with rationales and the open points before the page may be finalized.

Marketers know this. It’s exactly what they’ve been writing for their agencies for years: a briefing with audience, tone of voice, key message, and dos and don’ts. Only now an agent reads it, one that responds in minutes instead of rounds of feedback – and briefing and result sit in the same file, versioned, visible to everyone. No briefing gets lost anymore because it was in an email.
A Seed to Build Your Own
How do you get started? As in the first article, there are two paths: the content repository on its own, even if the website stays in the website builder (for now), and content repository and website together. Both are kept general, not my real files.
Both share the instructions for the agent in the root folder of the content repository:
# Content Repository of Example Co.
All published content and the rulebook that goes with it.
## Folders
- `content/` pages, blog articles, landing pages – one Markdown file each
- `context/` tone-of-voice.md, positioning.md, audiences.md,
keyword-inventory.md, glossary.md
- `templates/` one template per content type
- `skills/` recurring workflows (landing page, announcement, checks)
## Rules
- Make nothing up. Claims about the company only if they are backed
up in positioning.md. Examples are allowed if they are
recognizable as examples.
- Existing content is the benchmark: if a rule contradicts a
published text that works, the rule gets adjusted.
- Every text has in its frontmatter: title, slug, seo_title,
meta_description, audience, keyword, voice, status, brief.
- The primary keyword comes from keyword-inventory.md and is
assigned there before anything is written.
- Slugs of published pages are never changed.
- Checks only report. Changes happen only after asking.
- Every mistake that happens twice becomes a rule in this file.
Content Repository Only
The path for everyone whose website stays in the website builder – for now or forever. Even then, the repository is worth it: the texts are written and checked there and then pasted into the website builder. That’s how it worked for me until the end of August. The first prompt could look like this:
We are setting up a content repository for <COMPANY>. The website is
at <https://www.your-domain.com> and stays on <WEBSITE BUILDER> for now.
If this prompt still contains placeholders in angle brackets, ask
before you start. Work in this order and stop after each step so I
can review:
1. Fetch existing content: Read the sitemap and bring over every page
and every article as Markdown into content/, with frontmatter.
Don't rephrase a single word.
2. Derive the rulebook from the existing content, don't invent it:
- tone-of-voice.md: recurring patterns with real sentences as
evidence, plus the words that never appear.
- positioning.md: what the site actually says about offering,
clients, and experience. Contradictions as a list for me.
- audiences.md: whom the pages address, with the source location.
- keyword-inventory.md: which page targets which search term.
Terms assigned twice as a list for me.
Here are our brand guidelines: <PATH OR LINK>. Where they contradict
the existing content, ask instead of picking a side.
3. Create skills: tone-check and seo-check, which only report – with
the source location, the rule violated, and measured character
counts. Plus a skill for landing pages that starts with a brief:
audience, objection, proof, keyword.
4. First pass: Run both checks across all existing content and give
me the findings as a list, grouped by rule.
Change nothing. I decide what we fix in one commit.
The fourth step is the most important. The first list of findings tells you more about your content than any content audit, and half of the findings will show that the rule is wrong, not the text.
Content Repository and Website
The path I took: two repositories side by side, one for the content, one for the website. For the website itself, the seed from the article on the website builder alternative applies. This prompt comes on top as soon as both are in place:
The website in <WEBSITE-REPO> reads its content from the
content repository in <../CONTENT-REPO>. Build a sync for that:
1. pnpm content:sync copies into src/content/ – but only what belongs
on the site: <content/pages, content/blog, …>. Working documents
stay out. The list lives in the script as an allowlist.
2. Proof of origin: On every sync, write src/content/.source.json
with the commit of the content repository and whether it was clean.
3. Only the committed state of main. If the content repository has
uncommitted work or is on another branch, abort and tell me
what you found.
4. Nothing is ever written directly in src/content/, only in the
content repository. Optional: pnpm content:push writes changes
made here during fine-tuning back there – without
committing. Show pnpm content:diff first.
5. A check in pnpm verify warns when copy and source drift
apart, with a file list in both directions.
6. The website's frontmatter schema checks all required fields.
If one is missing, the build fails, not the page.
After that, every content change is a commit in the content repository, a sync, and a build. And every page on the website can be traced back to exactly the state of the content it was built from.
Public Service Announcement: The Rulebook Doesn’t Write Itself
For all the enthusiasm, here too comes the uncomfortable part.
A content repository is only as good as the rulebook in it, and that doesn’t maintain itself. Every rule in my context/ folder came about because something went wrong or because I made a decision. The agent wrote them down, but I made them. If you fill a repository with rules nobody decided on, you get an agent that very consistently does the wrong thing.
The same applies to what I wrote about taste in the first article: the rulebook is no substitute for a mindset. A tone-of-voice file that consists of “professional but approachable” delivers texts that sound professional but approachable – in other words, like everyone else. A brand is the deviation from the average, and someone has to put it into words before an agent can maintain it.
I also want to be honest about why this works for me. I could only develop this setup the way I did because I’ve been active in this field since 1998 and know pretty precisely what I want. The jobs as a content editor, the websites I’ve built, the phpBB forums I’ve hosted, my time as CPO at Evernest, during which I also led performance marketing, the close collaboration with marketing at EventInc – more on that in my episode with Carsten Bohling on distribution and marketing – and the work for clients: all of that is in this rulebook, condensed into a few files. That doesn’t work if you just fire up the AI and say, “Just do something.” Then you get exactly that – something. For it to work, you need a common thread and a North Star: an idea of what your content is for and how you can tell that it’s good.
And some decisions don’t belong in a rulebook at all. The agent doesn’t invent quotes, numbers, or clients – that’s the first rule in the instruction file, and it’s no coincidence that it sits at the very top. The legal notice and the privacy policy aren’t editorial texts and aren’t tightened by any check. A content repository doesn’t do the work on your content for you. It makes sure that every decision you’ve made once still applies to the next text.
How to Get Started
If you’ve read this far, you don’t need both repositories right away. Start with the first tab: bring in the existing content, derive the rules from your own best material, run the checks over it once. The list of findings is the moment when you decide whether you want this.
Many teams are surprised at this point by how their brand actually comes across – because the rules derived from the existing content describe the brand you’ve published, not the one you have in your head. That leads to some of the most valuable discussions a team can have: does the brand need an update – or just the way it’s represented on your site?
And if you’re still looking for the common thread or the North Star: get in touch with me. I’m happy to help – with the setup, with the rulebook, and with the question of how this fits into your organization – so that your use of AI doesn’t end in slop. Book an intro call.
