How to write docs
Guide for humans and agents editing Bondery documentation
How to write docs
This guide applies to everyone who writes or edits documentation in docs/ — contributors, maintainers, and AI agents.
Language
Write in clear, concise, accurate prose. No fluff.
| Do | Don't |
|---|---|
| State what something is and what it does | Pad with marketing language or filler |
| Use plain words; define terms once | Assume jargon without context |
| Prefer short sentences and active voice | Repeat the same idea in different words |
| Be precise about behavior and limits | Hand-wave with "simply", "just", or "easily" |
Docs are reference material, not blog posts. Every sentence should earn its place.
Know your audience
Before you write, decide who will read the page:
| Audience | Typical goal | Where it lives |
|---|---|---|
| Users | Use Bondery day to day | getting-started.mdx, apps/, bondery/, concepts/ |
| Developers | Integrate, self-host, or contribute | api/, deploy/, contributing/ |
| Agents | Answer questions or implement against the product | All of the above |
Lead with the reader's goal. A user page explains what to do; a contributor page explains how the system works.
Structure
Every page
- Title — frontmatter
title(rendered by the docs site) plus matching#heading in the body when useful for readers on GitHub - Lead — one or two sentences: what this is and why it matters
- Body — sections with
##headings; tables and lists where they reduce ambiguity - Related links — point to the next doc a reader likely needs
Core concept pages (docs/concepts/)
- One concept per file
- Set
iconin frontmatter to a Lucide PascalCase name (e.g.User,Bell) — see Icons below - Cross-link related concepts at the bottom
- Do not duplicate full explanations — link instead
Contributing pages
- Describe the current architecture and setup, not historical plans
- Link to source files or env examples when steps are non-obvious
- Keep commands copy-pasteable and tested
Changelog partials (docs/changelog/)
- In-flight entries — edit
docs/changelog/unreleased.mdx(title: "Release notes for next version update",hidden: true; unpublished; not inmeta.json). - Shipped releases — one file per version under
docs/changelog/releases/X.Y.Z.mdx(title: "X.Y.Z"), listed newest-first indocs/changelog/releases/meta.json. - Hub page —
docs/changelog/index.mdxat/docs/changelogcomposes Unreleased plus all releases viaChangelogFeed; do not add manual imports per release.
Architecture decision records (docs/adr/)
- Do not link to ADRs from user-facing or operator docs (
deploy/,getting-started,bondery/,concepts/, etc.). ADRs are internal, hidden records (hidden: true); readers should not need them. - When a decision matters for operators or integrators, restate the relevant facts in the appropriate guide (e.g. storage and
pre_startbootstrap belong in Configuration and Dokploy). - New ADRs may still be added under
docs/adr/for maintainers and agents; keep them out ofmeta.jsonand avoid cross-links from published doc pages.
API docs
- Do not hand-write endpoint docs. The contract is compiled from Zod schemas on Fastify routes.
- Zod wire schemas live in
@bondery/schemasand@bondery/schemas/http; routes compose them inschema.body,schema.params, andschema.response. - When you change API routes or
@bondery/schemas, the pre-commit hook regeneratespackages/openapi-spec/openapi.yamlautomatically. - Run
pnpm run check:openapibefore release or to validate Redocly rules locally. - The docs site renders the OpenAPI reference from
packages/openapi-spec/openapi.yamlvia build-timegenerate:api-docs(Fumadocs OpenAPI). - Prose in
api/should explain auth, base URL, and integration patterns — not duplicate every field. - See API routes for the route schema checklist.
Formatting conventions
- File format — use MDX only (
.mdx). Plain.mdis not compiled by the docs site. MDX gives us Callouts, Cards, Steps, Files, and other Fumadocs components without a parallel format. - Frontmatter —
title(required), optionalicon,description,docId/docSectionsfor in-app links,hidden: trueonly for pages that should not appear in the sidebar - File names — lowercase, hyphenated (
getting-started.mdx,local-setup.mdx) - Navigation — sidebar order and grouping come from the nearest
meta.jsononly (add, move, or rename pages there) - Code blocks — include the language tag; show real commands and env var names from the repo
- Callouts — use
<Callout type="info">/warn/errorsparingly for warnings or non-obvious caveats - Cards — use
<Cards>/<Card>for navigation hubs (e.g. welcome page modes), not for every link list - Steps — use
<Steps>/<Step>for ordered setup flows (e.g. getting started, local setup) instead of manual## 1.headings - Files — use
<Files>/<Folder>/<File>for repository or directory trees instead of ASCII art - Accordions — use
<Accordions>/<Accordion>for FAQ-style Q&A sections - BonderyRepo — use
<BonderyRepo />for monorepo mentions (wrapsGithubInfowithusebondery/bondery) - Code tabs — use
<CodeBlockTabs>when showing the same snippet in multiple languages or runtimes
Icons
Sidebar icons help readers scan the tree. Use Lucide names in PascalCase (User, not user).
| Where | Rule | Example |
|---|---|---|
Top-level folders (meta.json) | One icon per section | Guides → BookOpen, API → Webhook |
Core concepts (docs/concepts/) | icon on every page — maps to a product entity | people.mdx → User |
Product guides (docs/bondery/, docs/apps/) | icon on user-facing task pages | Extension → Puzzle, Mobile → Smartphone |
| Welcome & changelog | icon on index pages | Welcome → House, Changelog → History |
Self-hosting (docs/deploy/) | icon on every page | Requirements → Server, Installation → Download |
| Contributing | Folder or page icon where it helps scan | Environment → Settings, Local setup → Terminal |
| API reference | Folder + overview pages only; OpenAPI operation pages inherit tag grouping | Auth → Key |
| Authoring guide | No icon | how-to-write-docs |
Do not use emojis in navigation (sidebar, tabs, or meta.json). Emojis are fine in page body content where they already carry meaning (e.g. changelog category headings).
Pick icons that match the reader's mental model, not decoration. If two pages would share the same icon, differentiate them (Calendar vs Bell for interactions vs reminders).
Writing for agents
Agents read the same docs as humans. Optimize for retrieval, not cleverness:
- Use descriptive headings that match how people ask questions ("How to access it", "Prerequisites")
- Prefer tables for field lists, env vars, and comparisons
- Put canonical terms in bold on first use (
Myself,merge recommendation) - Link to the definitive page instead of copying long passages into multiple files
Good external examples: Resend docs, AgentMail docs.
When you change the product
Update docs in the same change when behavior, architecture, or setup steps change. If you move a feature (e.g. Myself from user guides to core concepts), update:
- The page content and location
- Nearby
meta.jsonfiles - In-app help links — add or update
docId(anddocSectionsfor section anchors) in the page frontmatter, then runpnpm run generate:doc-links. UsehelpDoc="your.docId"ordoc="your.docId"in the webapp; never hardcodeHELP_DOCS_URLpaths. - Cross-links from related concept pages
- Changelog for user-visible release notes
In-app doc link frontmatter
Pages linked from the app need stable identifiers in YAML frontmatter:
---
title: People
docId: concepts.people
docSections: # optional; maps section docId suffix → anchor id
enriching-contact: enriching-contact
---docIdis permanent once shipped — app code references it, not file paths.docPathis auto-derived from the file location; override only when the public slug differs.- Section anchors: place
<a id="anchor-id" />under the heading (MDX cannot use{#anchor}syntax). - Run
pnpm run generate:doc-linksafter changing frontmatter; CI validates files and anchors.
Checklist before opening a PR
- Audience and goal are obvious from the first paragraph
- No outdated stack names, ports, or data-flow claims
-
meta.jsonreflects new or moved pages - Related pages link to each other where useful
- Prose is concise — remove anything that does not inform or instruct