Contributing to the Documentation
Where a documentation page belongs, how to write it, and the checks a docs change has to pass.
On this page
A reader should be able to install the CMS, learn the six product ideas, finish a task, look up a contract, or change the engine — and each of those is a different section. This guide is where a new page is allowed to live, and how to write it.
Jump to your section:
- Where a page belongs — the map, and the rule that keeps it from rotting.
- For all contributors — tone, style, and writing approach.
- For developers and agents — rules, frontmatter, and the pull request.
For All Contributors
You don’t need to be a developer to improve SveltyCMS documentation. Typo fixes, clarity improvements, and outdated screenshots are just as valuable as new API references.
Where to Start
- Typos & Grammar: Every fix counts. If you spot it, fix it.
- Clarity: If a step confused you, it will confuse others. Rewrite it.
- Outdated Info: If the UI or API response differs from the docs, open an issue or a PR.
- Missing Examples: If you solved a problem not covered in the docs, add it.
- Broken Links: If a relative link leads to a 404, update it.
Quick Fixes: For small corrections, edit any page directly on GitHub by navigating to the file and clicking the pencil icon. No local setup required.
The “User-First” Writing Approach
Structure every section in this order:
- The Goal — What is the reader (Content Creator, Admin, or Developer) trying to achieve? State it in one sentence.
- The Solution — Clear, step-by-step instructions (screenshots, code snippets) to achieve that goal.
- The Mechanics — (Optional & Final) — Explain architecture, state machines, or DB-agnostic adapters after the goal is achieved. Never lead with mechanics for end-user guides.
Multi-Persona Balance: Major guides (like Getting Started) must provide distinct paths for Content Creators (layout, workflows), Administrators (settings, permissions), and Engineers (setup, mechanics).
1:1 Code Alignment: Before documenting any function, endpoint, or component, open the relevant file in src/. Document the actual parameter names and behavior — not what you expect them to be. If the code and the existing docs disagree, the code is correct.
🇪🇺 EU & German Comparative Advertising Compliance
All competitive comparisons in public-facing documentation must comply with EU Directive 2006/114/EC and German UWG §6 (Unfair Competition Act):
- Use Verifiable Sources: Every competitive claim must cite public, objective sources (competitor documentation, CVE databases, published benchmarks).
- Date-Stamp Performance Metrics: Include measurement date, hardware specs, and reproduction commands.
- Avoid Disparaging Language: Describe architectural differences neutrally (e.g., “React VDOM reconciliation” vs. “Svelte compile-time reactivity”). Never use terms like “fails to”, “broken”, or “suffers from”.
- Qualify Absolutes: Claims like “first”, “best”, or “only” must be qualified: “to our knowledge” or “based on public documentation as of [Date]“.
- Like-for-Like Comparisons: Only compare goods meeting the same needs. Note differences (SaaS vs. self-hosted, free vs. enterprise).
Writing Style
- Voice: Professional, direct, concise. Use American English.
- Active voice: “Click Save” not “The Save button should be clicked.”
- Short sentences: One idea per sentence.
- Real examples: Every concept should have a working code snippet or step-by-step scenario.
- Scannable structure: Use H2/H3 headings. End each section with a clear next step or summary.
- Headings: Use sentence case for headings (“Getting started with collections” not “Getting Started With Collections”).
When to Use a Mermaid Diagram
Use a diagram when the relationship between three or more components is not immediately obvious from prose alone. Do not add decoration-only diagrams.
Good candidates: Authentication flows, middleware pipelines, provisioning sequences, state machines, cache layers.
Skip the diagram: For a single API endpoint, a two-step process, or anything a one-sentence description handles clearly.
MDX Formatting Features
GitHub-Style Alerts
Use these callouts sparingly — if everything is important, nothing is.
> [!NOTE]
> General information that provides useful context.
> [!TIP]
> A helpful shortcut or best practice.
> [!IMPORTANT]
> An essential requirement the user must not miss.
> [!WARNING]
> A potential pitfall or side effect to be aware of.
> [!CAUTION]
> A high-risk action that may cause data loss or breakage.
Mermaid Diagrams
Use fenced code blocks with the mermaid language tag:
```mermaid
sequenceDiagram
participant Client
participant API
participant DB
Client->>API: Request + Token
API->>DB: Verify & Query
DB-->>API: Data
API-->>Client: JSON Response
```
The renderer supports these diagram types: graph (flowchart), sequenceDiagram, classDiagram, stateDiagram, erDiagram, gantt, pie, gitgraph, mindmap, timeline, quadrantChart, xychart-beta, journey.
Do not include inline HTML elements inside mermaid blocks — they will not render. Do not hardcode hex color values; let the theme engine handle coloring automatically.
Code Blocks
Always specify the language for syntax highlighting:
```typescript
// TypeScript example
const result = await cms.collections.find("posts", { tenantId });
```
```bash
# Shell example
bun run dev
```
For code blocks that contain triple backticks, use quadruple backticks as the fence:
````markdown
```mermaid
graph TD
A[Start] --> B[End]
```
````
Enterprise benchmark reports (auto-generated)
Per-database reports in docs/project/benchmarks/benchmark_<db>.mdx use a progressive-disclosure dashboard — not hand-written prose. The canonical pipeline reference is Database Performance Benchmarks.
| Zone | Purpose | MDX pattern |
|---|---|---|
| EXECUTIVE | Pass badge, dimension health, issues-only table, sparklines | [!NOTE] / [!WARNING], collapsed mermaid (xychart-beta, quadrantChart) |
| SUMMARY | Current-run overlay vs historical trends (Rule C — never mixed) | Separate SUMMARY_RUN_OVERLAY / SUMMARY_HISTORY slots |
| LEDGER | Four dimension groups → per-test collapsible truth tables | Nested <details> / <summary>, <!-- SECTION:TAG:START/END --> |
| METADATA | Host reproduction table | Markdown table |
Dimension groups (ledger + executive rollups): Core, API, Scale, Resilience — marked with <!-- LEDGER_DIMENSION:CORE|API|SCALE|RESILIENCE:START/END -->.
Record modes:
| Mode | Trigger | MDX writes |
|---|---|---|
none |
bun test (default) |
None — console only |
history |
BENCHMARK_HISTORY_ONLY=1 |
SQLite history only |
partial |
BENCHMARK_RECORD=1 bun test … |
Ledger + summary + partial executive |
full |
bun run scripts/benchmark-matrix/index.ts |
All zones + full executive |
Do not hand-edit zone interiors in benchmark_*.mdx. Writers in tests/benchmarks/modules/benchmark-mdx.ts replace content between markers surgically. Regenerate shells with bun run scripts/benchmark-matrix/generate-benchmark-reports.ts --force-all, or let the matrix / BENCHMARK_RECORD=1 populate results.
HTML <details> in benchmark reports: Nested collapsibles are required for enterprise ledger UX. This is intentional for auto-generated benchmark MDX only — avoid raw HTML collapsibles in hand-written guides unless necessary.
Validate report shape after benchmark runs:
bun run lint:benchmark-mdx
For Developers and AI Agents {#for-developers}
This section contains non-negotiable rules. All PRs are checked against these standards before review.
⚠️ The Golden Rules
These rules are enforced. A PR that violates them will not be merged.
MDX Only, Correct Locations: All documentation files must be
.mdx. No.mdfiles. Files must live in their designated canonical location (see the table below) — no exceptions.Exception: Benchmark reports in
docs/project/benchmarks/are auto-generated byscripts/benchmark-matrix/generate-benchmark-reports.tsusing an underscore naming convention (benchmark_sqlite.mdx,benchmark_postgresql_redis.mdx). This pipeline-driven naming is intentional and exempt from the kebab-case rule. Do not rename these files manually.Centralized API Docs: All API documentation must live in
docs/reference/api/. API content scattered elsewhere will be rejected.Current Functionality Only: Document only what exists in the current codebase on the
nextbranch. Do not document planned features, unmerged branches, or aspirational behavior.Comprehensive Indexing: Index pages (e.g.,
docs/reference/api/index.mdx) must serve as a complete map. They must link to every child document in their category. A partial index is broken navigation.Assets in
static/docs/: All non-MDX assets (images, SVGs, diagrams) must be placed instatic/docs/and referenced via absolute project-root paths. No assets indocs/itself.Widget API Sync Rule: Any change to
src/routes/api/[...path]/handlers/system.ts(the widgets section) orsrc/stores/widget-store.svelte.ts— adding, removing, or renaming a handler, or changing a response shape — must updatedocs/reference/api/system.mdxin the same PR. Refresh theupdateddate, update the endpoint table, and remove any obsolete entries.Thin API Handler Pattern: Handlers in
src/routes/api/[...path]/handlers/must only parse the request, delegate tolocals.cms(the Local SDK), and return a JSON response. All data access logic should live in the Local SDK (src/services/sdk/index.ts) or a dedicated service. Handlers that contain inline business logic will be rejected.// ✅ Correct — thin handler delegating to Local SDK export async function handleCollectionFind(event: RequestEvent) { const { locals, params } = event; const { id } = params; const entries = await locals.cms.collections.find(id, { tenantId: locals.tenantId }); return successResponse(entries); }Local SDK Performance Emphasis: When adding or modifying core CMS functionality, ensure it is exposed through the
LocalCMSclass (src/services/sdk/index.ts). Documentation for these features must highlight the performance advantage of using the Local SDK (zero HTTP overhead, direct DB adapter access) over external HTTP calls.“Next Steps” Footer Required: Every guide, tutorial, and architecture page must end with a
## Next Stepsor## Relatedsection linking to 2-3 relevant pages. This keeps readers flowing through the docs. A page that dead-ends at the last paragraph will be rejected.Frontmatter
updatedDate: Update theupdatedfield in frontmatter with every content change. Stale dates erode trust. The date must be inYYYY-MM-DDformat.One question, one page: A task is a guide. A contract is a reference page. An engine explanation is architecture. The product model stays in
docs/concepts.mdxand stays short. Do not copy the same explanation into a second folder.
Where a page belongs {#where-a-page-belongs}
The docs follow the reader’s question. One page answers one question. Do not add a second copy of the same explanation in another folder.
| Question | Put the page in | On the public sidebar |
|---|---|---|
| How do I learn this by doing it? | docs/onboarding/ or docs/getting-started.mdx |
Get started |
| What are the pieces of the product? | docs/concepts.mdx |
Concepts |
| How do I finish this task in the admin or in operations? | docs/guides/ |
Guides |
| How do I extend the CMS (widget, plugin, frontend)? | docs/development/ |
Build |
| What is the exact contract? | docs/reference/api/, security/, database/, or components/ |
Reference |
| Why is the engine built this way? | docs/reference/architecture/ |
Architecture, linked from reference — not the first page a new editor sees |
| How do I change this repository or these docs? | docs/contributing/ |
Contribute |
| What did a test or a benchmark show? | docs/tests/ or docs/project/benchmarks/ |
No. Link it from the page that needs the evidence |
| What is planned, or what already shipped? | docs/project/roadmap-2026.mdx, docs/project/achievements-2026.mdx |
No |
| How does this field widget behave? | src/widgets/.../{name}/{name}.mdx, next to the source |
Linked from Widget development |
Do not add a new top-level folder. Do not paste a full file tree into this guide. A pasted tree went stale while the files kept moving, and the index page of each folder is the map. That index must link every child document (golden rule 4).
Concepts stay short. A procedure belongs in a guide. A parameter table belongs in reference. A module layout belongs in architecture.
Architecture is not onboarding. Write those pages for someone changing that subsystem. Point a newcomer at Concepts.
Public URLs
docs.sveltycms.com serves this tree. The URL is /docs/ plus the path under docs/, without .mdx.
| File | URL |
|---|---|
docs/concepts.mdx |
/docs/concepts |
docs/getting-started.mdx |
/docs/getting-started |
docs/reference/api/collections.mdx |
/docs/reference/api/collections |
docs/development/widgets/index.mdx |
/docs/development/widgets |
The site homepage has to use those paths. /docs/architecture, /docs/api, and /docs/widgets are not files. The pages that exist are /docs/reference/architecture, /docs/reference/api, and /docs/development/widgets.
Folders
| Folder | Holds |
|---|---|
docs/concepts.mdx |
The product model. Keep it to a sitting’s worth of reading. |
docs/onboarding/ |
Tutorials that produce a running install. |
docs/guides/ |
Tasks: content/, configuration/, deployment/, legal/. |
docs/development/ |
Widgets, plugins, dashboard widgets, LocalCMS, the site starter, the native UI. |
docs/reference/api/ |
HTTP and API docs. Nowhere else. |
docs/reference/security/ |
Auth, CSP, field access, incident response. |
docs/reference/database/ |
The four adapters and the performance model. |
docs/reference/components/ |
Collection display (entry list, fields, smart table). The native kit is docs/development/ui/. |
docs/reference/architecture/ |
Why the engine is shaped this way. |
docs/contributing/ |
This guide, the admin style guide, accessibility, the validation pipeline. |
docs/tests/ |
How the suite is built. For contributors. |
docs/project/ |
Roadmap, achievements, comparison, and generated benchmarks. |
src/widgets/**/{name}.mdx |
That field’s page, beside its source. |
static/docs/ |
Images and diagrams. Mirror the docs/ path. No binaries inside docs/. |
Benchmark reports named docs/project/benchmarks/benchmark_*.mdx are generated. Do not rename them, and do not edit the marked zones by hand. The pipeline is Database performance benchmarks.
Frontmatter Specification
Every .mdx file must begin with a complete YAML frontmatter block. All fields are required.
| Field | Type | Purpose | Example |
|---|---|---|---|
path |
string | Full path from project root. Used for routing. Must match the file’s location. | "docs/reference/api/collections.mdx" |
title |
string | Main H1 heading. Shown in navigation, browser tab, and search results. | "Collections API" |
description |
string | One-sentence summary for SEO and link previews. | "CRUD operations for collection entries." |
order |
number | Position in sidebar navigation relative to siblings. Lower = higher. | 15 |
icon |
string | Material Design Icon with mdi: prefix. |
"mdi:database" |
author |
string | GitHub username of the original author. | "your-github-handle" |
created |
string | Creation date in YYYY-MM-DD format. Set once, never change. |
"2025-10-05" |
updated |
string | Date of last meaningful change. Update with every PR. | "2026-06-27" |
tags |
array | Lowercase kebab-case keywords for search and filtering. | ["api", "collections", "crud"] |
Correct frontmatter example:
---
path: "docs/reference/api/collections.mdx"
title: "Collections API"
description: "REST API for managing content entries with multi-tenant isolation."
order: 15
icon: "mdi:database"
author: "your-github-handle"
created: "2026-01-10"
updated: "2026-03-27"
tags:
- "api"
- "collections"
- "crud"
- "rest"
---
Asset Management
All non-MDX files (images, screenshots, SVGs) must follow these rules:
- Location:
static/docs/— mirror thedocs/directory structure beneath it.- Example: An image for
docs/reference/api/collections.mdxbelongs instatic/docs/reference/api/.
- Example: An image for
- Reference: Always use absolute paths. The
static/prefix is omitted because SvelteKit servesstatic/at the root:
File standards:
| Standard | Detail |
|---|---|
| Format | PNG for screenshots, SVG for diagrams and icons. |
| Size | Keep files under 500 KB. Compress screenshots before committing. |
| Naming | Descriptive kebab-case (e.g., saml-handshake-flow.svg). |
| Alt text | Always required. Describe what the image conveys, not what it looks like. |
Pull Request Workflow
Documentation is treated with the same rigor as code. Every contribution passes through the same gates before it reaches next.
-
Branch: Create a branch with a descriptive name:
git checkout -b docs/fix-collection-api-filter-params -
Verify source alignment: If documenting code behavior, open the relevant file in
src/and confirm every parameter name, return value, and sequence matches what you have written. -
Lint: Run the documentation linter and fix all errors before pushing:
bun run lint-docs bun run slop -
Audit & CI parity: Run the full check suite if code changed alongside docs:
# Pre-commit checks (staged files, ~2-3s) bun run gate:fast # Pre-push checks (type check + unit tests, ~15-45s) bun run gate # Full CI simulation locally bun run test:doctor # Performance audit (if applicable) bun run scripts/benchmark-matrix/index.ts --parallel=safe -
Update
updatedfield: Change the date in frontmatter to today’s date. -
Submit PR: Use a clear title following the convention:
docs: add filter operator reference to SCIM API docs: fix outdated widget sync steps in troubleshooting docs: overhaul getting-started for user-first structure -
AI agent commits: Commit messages authored or co-authored by AI agents must not include
Co-Authored-Byor AI-attribution tags. All commits should appear as the author’s own work for clean enterprise integration.
Pre-Submission Checklist
Before opening a PR, verify every item:
File & Frontmatter
- File is
.mdxformat — not.md - File is in its correct canonical location
-
pathfield in frontmatter matches the actual file location exactly - All required frontmatter fields are present and correctly typed
-
updatedfield reflects today’s date - Content documents only current, existing functionality (nothing aspirational)
Technical Accuracy
- Every parameter name, endpoint path, and return value verified against
src/ - Code examples are tested and functional
- Import paths in code examples are correct (use
@src/,@utils/,@services/aliases) - Permission names match actual code (
collections:read, notcollection:read)
Assets & Links
- Images are in
static/docs/with mirrored directory structure - All asset references use absolute paths from project root (
/docs/...) - Alt text provided for every image
- Internal links are correct and resolve to existing files
- “Next Steps” or “Related” section present at the bottom
Linting & CI
- Tags are lowercase and kebab-case
- Linter passes:
bun run lint-docsandbun run slop - Test suite passes: All unit tests are green (
bun run test:unit) - If
docs/project/benchmarks/benchmark_*.mdxchanged: changes came from the pipeline (not manual zone edits) andbun run lint:benchmark-mdxpasses - If
src/stores/widget-store.svelte.tsor widget handler changed:docs/reference/api/system.mdxupdated in this same PR - Rendered correctly in the CMS preview (no broken mermaid, no stray formatting)
Questions and Support
- Unclear guidelines: Ask in GitHub Discussions
- Documentation bugs: Open a GitHub Issue
- PR review help: Tag a maintainer in your pull request