I kept fixing the same problem in three different places.
Someone would land on the GitHub repo for my local AI gateway and need a fast answer: what is this thing, what does it support, and how do I start it?
Instead, they got the same thing a lot of open-source projects accidentally grow into: a README that wanted to be a landing page, onboarding guide, operator manual, architecture index, and release checklist at the same time.
That works for a while. Then every edit makes it worse.
The failure mode was boring but expensive
The project is CliGate, a local AI gateway that sits between tools like Claude Code, Codex CLI, Gemini CLI, OpenClaw, dashboard chat, channel workflows, and upstream model providers.
As the product surface expanded, the docs expanded with it:
- protocol translation details
- account pools and API keys
- app routing and model mapping
- dashboard pages
- runtime sessions
- Telegram and Feishu channels
- local manuals inside the product
The result was predictable:
- the GitHub README kept getting longer
- first-time users still needed a cleaner path
- the in-product assistant needed stable source material
- maintainers needed room for operational docs that should never be the first thing a new user reads
So the real problem was not "write more docs."
It was "stop making one document do five jobs."
I ended up with a three-layer docs model
The fix in this repo was to split the content by reader intent instead of by file history.
Now the project has three distinct layers:
- a repo-facing
README.md - a docs hub under
docs/README.md - a lightweight in-product manual served from
/manual/
Each one answers a different question.
Layer 1: README is for orientation, not full ownership of every detail
The current README now does the things a repo landing page is actually good at:
- explain what CliGate is
- show the supported surfaces
- give the shortest quick start
- point to the right deeper documents
That keeps the first screen useful instead of turning it into a scroll tax.
The structure is intentionally compact:
## Quick Start
### 1. Start CliGate
### 2. Add at least one working credential
### 3. Point your tool to CliGate
And it still gives concrete configuration examples, like Codex pointing at localhost:
chatgpt_base_url = "http://localhost:8081/backend-api/"
openai_base_url = "http://localhost:8081"
That is enough for a reader who wants to know whether the project is relevant before they commit to the rest.
Layer 2: the docs hub is the router for human readers
Once the README stops pretending to be everything, you need a clean next step.
That is what docs/README.md became.
Instead of a random directory listing, it routes by audience:
## By Audience
### New users
### Integrators and operators
### Contributors
This seems obvious, but it fixed a real repo problem for me.
When documentation grows organically, file names make sense to maintainers and almost nobody else. A docs hub changes the question from:
"Which markdown file sounds closest to my problem?"
to:
"What kind of reader am I, and where should I start?"
That is a much better first branch.
Layer 3: the product needed its own short manual
The part I did not want to keep faking was the in-product help path.
When users are already inside the dashboard, they usually do not want the full repository story. They want a short operational guide:
- what does this product do
- what is the default address
- what do I configure first
- where in the dashboard should I go next
So CliGate now serves a lightweight manual at /manual/, separate from the repo README and separate from the longer markdown manuals.
The HTML is deliberately focused on quick orientation:
<h2 id="page-title">Understand, configure, and verify CliGate quickly</h2>
<p id="page-subtle">This is the in-product quick manual. For full reference, use the complete product manuals.</p>
And the route layer exposes the source documents explicitly instead of scraping whatever happens to be on disk:
const DOC_FILE_MAP = Object.freeze({
'README.md': join(process.cwd(), 'docs', 'README.md'),
'API.md': join(process.cwd(), 'docs', 'API.md'),
'ARCHITECTURE.md': join(process.cwd(), 'docs', 'ARCHITECTURE.md'),
'product-manual.en.md': join(process.cwd(), 'docs', 'product-manual.en.md'),
'product-manual.zh-CN.md': join(process.cwd(), 'docs', 'product-manual.zh-CN.md')
});
That mattered for two reasons:
- the UI got a stable set of documents
- the product assistant got a cleaner source of truth
The manual files are now doing real product work
This was the architectural shift that made the cleanup worth it.
The docs are not only for GitHub readers anymore. They are also part of the product behavior.
The product manual now carries the user-facing explanation of:
- dashboard navigation
- routing concepts
- CLI configuration
- channel workflows
- troubleshooting paths
That means the manual has to be shaped for actual usage, not just for repository completeness.
One note in the docs hub says it pretty plainly:
- `product-manual.en.md` and `product-manual.zh-CN.md` are the primary user-facing manuals.
- The product assistant reads from those manual files directly.
Once that became true, letting the README keep absorbing everything stopped making sense.
I also had to accept that maintainers and users need different entry points
This is the trap I keep seeing in open-source docs.
Maintainers are comfortable with:
- roadmap files
- architecture notes
- release checklists
- migration plans
- incident writeups
New users are not.
If those documents sit beside the real onboarding path without any structure, the repo starts feeling harder than the product.
So the current split lets the project keep maintainers' documents in docs/ without making them the front door. The docs hub explicitly calls that out:
Planning, incident, and roadmap documents remain in this directory for maintainers, but they are not the best entry point for first-time users.
That one sentence removed a lot of ambiguity.
What changed for the actual product
The cleanup was not cosmetic. It changed how the project presents itself in three different contexts:
- GitHub readers now get a faster landing path
- dashboard users now get a short manual without leaving the product
- the product assistant now has clearer manual context to answer from
That last one is easy to underestimate.
If you build an assistant into the product, your documentation stops being passive. It becomes runtime input. Structure starts to matter much more than volume.
The pattern I would reuse
If your open-source project is growing past a single README, I think this split is a better default than endlessly reorganizing one giant file:
-
README.mdfor orientation and quick start -
docs/README.mdas a docs router by audience - an in-product quick manual for operational tasks
Not every project needs all three.
But the moment your docs are serving both repository readers and product users, pretending those are the same audience usually creates a worse experience for both.
If you want to inspect the implementation, the project is here:
I'm curious how other people are handling this boundary. When did your README stop being a README and start trying to become the whole product manual?
Top comments (0)