📚 Series: Building Docs for the AI Era:
This post is the second of many in this series. You can find the outline for upcoming posts below:
- Part 1: Self-Healing Docs
- Part 2: The Multi-Agent Documentation Pipeline (you are here)
- Part 3: Redesigning the Documentation Experience
From a flagged pull request to an open docs PR in minutes
A few months ago, I told you about the “self-healing system” (Part 1 of this article series) and how it helps me automatically catch up with small code updates that previously were missed and left undocumented.
Now, let’s say I have an upcoming Strapi feature to document. One year ago, I would have had to dig into Linear issues, Notion pages, Strapi codebases, and try to figure out things by myself or ask the devs for some precious explanations. I can still do it if I want, and I actually sometimes still do. But it’s 2026, so I now have tools to help me with these tasks when necessary.
All I have to do now is open Claude Code in a terminal and type one command:
/inki:document "MCP builder helpers, strapi/strapi 26603"Twenty minutes later I have a branch, a drafted section, six review reports, and an open documentation pull request waiting for my judgment. I spend the next hour doing the part that is actually mine: deciding whether the page teaches the right thing in the right order.
I’m Pierre, Senior Knowledge Architect at Strapi, also known as piwi in the community, and in this article I’m going to walk you through what happened in those twenty minutes.
Self-healing handled the drift. This is about the writing.
Every code change at Strapi reaches the documentation along one of two paths.
The automation-driven path is what the self-healing system does: a nightly funnel of deterministic filters, a cheap model for triage, a cheap model for routing, an expensive model for drafting. It needs no label, it runs at 1:30 AM, and it is very good at one thing, catching small changes that would otherwise make the docs slowly go out of date.
The human-driven path is for bigger changes, such as features and breaking changes, that need a new page or a significant update to existing ones.
Either way, every merged PR in strapi/strapi gets handled on the docs side much faster than before with the help of custom, Strapi-tailored, AI-based tools.

The human-driven path now runs through a Claude Code plugin I built called Inki (from ink and Strapi, and also "In-key Knowledge Interface", because naming things is the hardest problem in documentation too 😅). It's open source, in the strapi/documentation repository, and it ships 22 skills, 6 review agents, 8 page templates, 9 authoring guides, and a catalog of documented mistakes. I built it for one reason: to move my own quality standards out of my head and into something anyone can run.
Three ideas hold it together, and they are the three things I want to explain in this post.
Idea 1: the chain mirrors the job, not the tool
The first instinct when you automate writing is to build a simple, single "write the docs" command. I tried that. It produces plausible pages that are wrong in ways that take longer to fix than writing from scratch.
The thing that worked was to stop modeling the tool and start modeling the job. A technical writer handling a feature basically does four things, in order, and each one answers a different question:
| Stage | Question it answers |
|---|---|
| Research | Where does this go, and why? |
| Write | How should it be structured, and what does it say? |
| Review | Is it good enough? |
| Submit | Does it follow our conventions? |
That’s why Inki has exactly four families of skills, with those four names. Each family has an orchestrator that runs the whole stage, and granular skills you can call on their own. One command chains all four families, by default stopping at a gate between each stage, so you approve the research before the writing starts and the draft before the PR opens:

If you're in a hurry, you can skip the gates. /inki:document "MCP builder helpers" --non-interactive goes from a topic to an open pull request without asking a single question. That's what a developer wants when they'd rather review a decent draft on GitHub than answer four prompts in a terminal.
The payoff of matching the job instead of the tool is that every stage is separable. Most of my real usage is not the full chain. It's /inki:review on a community contributor's PR. Or /inki:route on a code PR, to find out which pages it touches, and then writing them myself. Or /inki:exists "MCP server media library tools" before I start, to avoid writing a page that already exists two sections away.
A monolithic "write the docs" command would give me none of that. The decomposition is the feature.
Inside the writing stage
Writing is where the decomposition pays off most, because most of the work isn't writing at all. Three agents run in sequence, and only the last one produces prose.
Nobody opens an empty file and starts at the first sentence: you work out the structure first, which sections the page needs, in what order, and what each one is for, and only then do you fill them in. The three agents follow that same order, which means the structure becomes a real artifact, reviewable on its own, before a single sentence exists.
The Router answers "where?" and "why?". It doesn't write actual documentation. Given the source material, it searches the existing documentation map (llms.txt, the sidebars, the open PRs), finds the nearest neighbors, and emits a verdict per page, including the pages it rejected and why.
This is the decision people sometimes skip when they automate docs, and it's the one that matters most. A model asked to "document this PR" will write a page. A page is almost never the right answer. For instance, on the MCP builders PR, the Router's verdict was: the topic is partially covered, extend-mcp-server.md already documents the lower-level registerTool() / registerPrompt() / registerResource() API but not the builders, so do not create a page: update that one, and insert a section after the intro and before "Registering a custom tool".
Each target gets an action (create_page, add_section, update_section, add_link, add_mention, add_tip) and a priority (primary, required, optional, conditional). If the Router can't decide, it says so, sets an ask_user field with the actual question, and the chain stops. Uncertainty is a first-class output. The Router says it doesn't know instead of guessing in confident prose.
The Router's second job is quieter and, I'd argue, more valuable: it resolves the document type, and from that type, the two reference files the writer will need. Three lines of its output look like this:
doc_type: feature
template: claude-plugins/inki/references/templates/feature-template.md
guide: claude-plugins/inki/references/authoring/AGENTS.cms.features.mdFrom here on, the rest of the chain knows which skeleton to follow and which rules apply. More on why that matters in Idea 3.
The Outline Generator answers "how?". It only runs when a structure has to be invented. A new page needs one: nobody has decided yet which sections it will have, or in what order. An existing page already has one, so the Outline Generator is skipped and the Drafter works straight from the page itself.
It reads the template, reads the source material, and produces a tree. Not a bullet list, a tree, where every node carries three things the writer will need:
sections:
- heading: "## Using builder helpers"
level: 2
intent: "Explain why the builders exist before showing how to call them."
content_hints:
- "State that the helpers are identity functions at runtime."
- "Compare to factories: define, then pass to the registration methods."
- "Name the access variants: devModeOnly OR auth, never both."
source_refs:
- "JSDoc on makeMcpToolDefinition in the PR diff"intent is the why of the section in one sentence, and it's what stops an agent from writing a technically correct section that serves no reader. content_hints are the writing directives. source_refs point at the exact part of the source material that holds the facts, which is an anti-hallucination mechanism built into the structure: the Drafter isn't asked to be careful, it's told where to look.
The Drafter answers "what?", and only that. In fact, it's the only agent in the chain that writes prose, and deliberately the least autonomous. Its prompt says it plainly: your job is to write and edit content, not decide the structure. The Outline Generator and Router have already done that.
It walks the tree depth-first and, for each node, translates a block of topics into sentences: read the intent, address every content_hints, pull the facts from the source_refs, use the listed components, write the section. It has three modes, and the mode is chosen upstream, not by the Drafter:
- Compose when an outline is present,
- Patch when the page already exists (it refuses to run without the current content, because it cannot guess what the page says),
- and Micro-edit for a cross-link or a tip, where the instruction is self-contained down to the insertion point.
Every handoff is a document
Here's what I'd keep if I rebuilt this from scratch. Look at what travels between those three agents:

What travels between stages is not a conversation or hidden state: it's a document, with a stable format that both humans and AI can read.
And each one is written for more than one reader at a time. The Routing Report has three parts, in this order:
- a Summary for everyone (what changed, and a table of which page to touch and how),
- Details for documentation specialists (the map analysis, the rationale, a confidence level),
- and a Machine-readable summary (the YAML the next agent consumes).
The first section literally ends with the line "This summary should be enough to help you get started if you plan to manually update the Strapi documentation yourself." Humans can pick up the job at any time. AI is a tool, not necessarily a replacement.
The same file is a work order for a human, a rationale for a reviewer, and an input for an agent. Which means the pipeline degrades gracefully to a human at every stage. Stop after the Router and you have a usable work order. Stop after the Outline Generator and you have a usable plan. Nothing is trapped inside the machine. It also means I'm never debugging "the AI": when a page lands in the wrong section, the Routing Report shows me which inference was wrong, and I go fix the Router.
Idea 2: one agent, one job
Once there's a draft, the same decomposition principle applies to checking it. /inki:review doesn't ask one model to simply review a page. It dispatches six specialized agents in parallel:

Three design decisions make this work, and none of them are about prompting.
They are read-only by construction. Each agent's tool allowlist excludes every write, commit, and push tool. Not "the prompt says don't edit the file". The agent physically cannot. All edits happen one level up, in the orchestrator, after the findings come back. This matters more than it sounds: a reviewer that can also fix things will quietly fix things, and you lose the report.
Each agent gets the model its job deserves. Code verification, cross-page coherence and pedagogical UX need real reasoning across a lot of context, so they run on Claude Opus. Structural checks and pitfall matching are closer to pattern matching against a reference list, so they run on Sonnet. The style check runs a deterministic script first, and only then layers AI judgment that runs on Haiku. This is the same progressive cost gating from the self-healing system, applied inside a single command instead of across a nightly pipeline. Don't use AI for what a script can do, and don't use a frontier model for what a small one can do.
Each agent returns only its findings. The page content, the source files it grepped, the pull request diff it fetched: all of that stays in the subagent's context and never comes back. The orchestrator sees six short reports. This is what makes six parallel reviewers affordable at all, and it's the part people most often get wrong when they build multi-agent systems. Parallelism is cheap. Context pollution is what costs you.
What the reviewers actually catch
Back to the MCP builders. Here’s a real example of a table extracted from a review report:
| Check | Issues | Severity |
|---|---|---|
| Style | 1 | low |
| Outline structure | 0 | – |
| Pedagogical UX | 4 | medium |
| Code verification | 1 | high |
| Cross-page coherence | 3 | medium |
| Known pitfalls | 1 | medium |
The high-severity one is my favorite finding the system has ever produced.
Every code example used import { mcp } from '@strapi/strapi'. The code verifier checked that import against the actual PR diff and found it doesn't resolve: the PR exports ai at the top level, and mcp is nested underneath it. The correct import is ai.mcp.
The Drafter hadn't invented it. It had copied the import from the JSDoc examples in the pull request itself. The upstream source was wrong, the first docs draft faithfully reproduced the error, and the only thing that caught it was an agent whose entire job is to distrust code blocks and go check the source.
That is the argument for machine review, and it isn't that the machine is smarter. It's that it is indifferent, exhaustive, and consistent. I have never once checked every import on a page against the source without getting bored halfway.
Six findings were fixed automatically that round. The pitfalls finding was the same import bug, caught a second time by a different agent. Two UX findings were left for me as suggestions, flagged as judgment calls. That split is deliberate: a finding is only applied automatically when it has a single, unambiguous correction.
Idea 3: the real product is the conventions
Here is the part I did not expect when I started.
The skills are maybe a third of Inki. The rest is written-down knowledge that used to live in my head:
- 8 page templates, one per document type (feature, guide, API reference, configuration, plugin, breaking change…). The Outline Generator doesn't invent a structure. It fills the structure the docs already use.
- 9 authoring guides, one per docs area, each encoding the rules that apply there and nowhere else.
git-rules.md, which knows that a branch touchingdocs/cms/is prefixedcms/, that PR descriptions are flat text with no headings and no test plan, and that thellms.txtfiles must never be committed because they are generated when Vercel builds the website.- A known-pitfalls catalog, which is one of the most valuable files in the whole plugin.
This is why the Router resolving doc_type matters so much. The conventions are not in the prompts. They are files, and the prompts read them. When a convention changes, I edit one Markdown file, and every agent that touches a feature page changes behavior. I don't retrain anything, I don't rewrite six prompts, and a human contributor reading that same file gets exactly the same instructions the machine does.
It also means a rule can be overridden with a reason, the way rules work for human writers. On the MCP builders draft, the plugin authoring guide mandates JS/TS tabs on code examples. The Drafter wrote TypeScript only, because the entire value of these helpers is TypeScript inference, and recorded the deviation and its justification in the write report.
The pitfalls catalog deserves its own paragraph. It's a growing table of documented mistakes, each with the wrong pattern, the right pattern, and the source file that proves it.
Every entry in the file is a mistake that actually shipped, or nearly did. Every entry is now caught automatically, forever, on every page. There's a skill, /inki:pitfalls-add, whose entire job is to verify a newly discovered mistake against the Strapi source and add it to the catalog.
This is the thing I'd tell anyone building something similar.
The AI is the cheap part. The expensive part is writing down what your team knows.
Inki is valuable because the style guide, the templates, the naming conventions and the mistakes are all in files, not in the head of the person who has been writing the docs the longest. A new contributor installs the plugin in two commands and gets the same conventions I have. That was never true before, and it has nothing to do with machine learning.
Writing the standards down moved them from my reviews into the machine, which now applies them for anyone who touches the Strapi docs: a developer fixing something in passing, a PM documenting their own feature, a contributor opening their first PR.
How this got built, which is also the point
None of this was designed up front. It grew in four stages, and the order matters:

It started as a handful of Markdown prompt files that I pasted into a chat window by hand, in order, copying the output of one into the next. That sounds primitive, but it forced the thing that made everything else possible: because I was the transport layer, the artifacts had to be readable. The YAML handoff blocks exist because a human was moving them around first.
Then each prompt became a skill, callable with one command. Then the stages got orchestrators that chain their skills and gate between them. Then the whole thing became a Claude Code plugin anyone can install.
Four design principles survived all three migrations, and they're why the migrations were cheap: model-agnostic, tool-agnostic, composable, decoupled. The prompts are plain Markdown with no vendor syntax, so nothing had to be rewritten when the harness changed. Those original prompt files still live in references/prompts/, and they are still the specification. The skills are thin: they resolve inputs, dispatch, handle flags. The knowledge lives in documents. This also means that, even though Inki is designed as a Claude Code plugin, it can be used by any other AI-enhanced IDE exploring the content of the repository.
Where the human stays
Every orchestrator stops between stages by default and waits for human input. There's a --non-interactive flag that chains everything without pausing, and anybody can use it, but one guard holds even then: if the research stage finds the subject is already documented, the chain stops and points the writer at the existing page instead of creating a duplicate.
Then there's the list of things the chain simply cannot do, which has barely changed since my previous blog article:
- Prioritization. It can tell me nine pages need updating. It cannot tell me which three matter before the release.
- Product memory. Why a feature is designed that way, which decision this reverses, what we promised in a changelog eighteen months ago.
- Upstream feedback. When documenting a feature is painful, it usually means the feature is confusing. That signal goes back to the product team, and noticing it is a human act.
- Pedagogy. What a reader needs to understand first. Where to put the example. When to say less.
The chain gives me drafts and evidence. I still make every call that matters. What changed is the ratio: far less time on placement, structure, boilerplate and verification, far more on whether the page actually teaches anything.
Try it yourself
Inki is open source, in the same repository as the Strapi docs. If you run Claude Code in the terminal, Inki is only 2 commands away:
/plugin marketplace add strapi/documentation
/plugin install inki@strapi-documentationThe prompts, templates, authoring guides and pitfalls catalog are all readable Markdown in claude-plugins/inki/. The templates and rules are specific to Strapi, but the architecture is not:
- Decide where before you decide what, and make that a separate agent with a separate output.
- Keep your conventions in files the agents read, not in the prompts.
- Make every handoff a document with a human half and a machine half.
- Let the chain stop at any stage and still leave a human something useful.
Part 3 of this series will be about the other half of this work, and the part readers actually see: redesigning the documentation experience itself.





