Writing Documentation
How to contribute to Sayr's documentation
Contributing to Sayr's documentation is one of the easiest ways to help the project. You can edit docs directly on GitHub without cloning the repository or setting up a local environment.
Quick Start: Edit on GitHub
Every documentation page has an Open menu below its title. Choose Open in GitHub to jump to the source file, then:
- Fork the repository (if you haven't already)
- Edit the file directly in GitHub's web editor
- Submit a pull request with your changes
That's it! No local setup required.
How the Docs Work
Sayr's documentation is built with Fumadocs and lives in the landing app (apps/landing), which runs on TanStack Start. It turns the Markdown files in apps/landing/content/docs/ into the docs site.
Key Features
- Markdown/MDX — Write in standard Markdown, with MDX for pages that need components such as callouts
- Navigation from the file tree — The sidebar is generated from the folders and each folder's
meta.json, which also controls page order - Code highlighting — Syntax highlighting built in, via Shiki
- Copy as Markdown — Every page can be copied or opened as raw Markdown, and
/docs/llms.txt//docs/llms-full.txtexpose the whole docs set to LLMs - Edit links — Open in GitHub on every page
- Generated API reference — The endpoint pages under
api/reference/are generated from Sayr's OpenAPI spec, so don't edit them by hand
File Structure
Documentation lives in the landing app:
apps/landing/
├── content/
│ └── docs/ # All documentation pages
│ ├── meta.json # Top-level sidebar order
│ ├── index.mdx # Homepage (/docs)
│ ├── quick-start.md
│ ├── cli/ # The sayr CLI: overview, feature pages, config reference
│ ├── tasks/ # Every folder has its own meta.json
│ │ ├── meta.json # (title, icon, page order)
│ │ ├── tasks.md
│ │ ├── subtasks.md
│ │ ├── task-relations.md
│ │ └── templates.mdx
│ ├── organize/ # labels, categories, views, releases
│ ├── visibility/ # overview, public-pages
│ ├── account/ # my-tasks, notifications, settings, security
│ ├── organizations/ # overview, preferences, members, billing
│ ├── ai/
│ ├── integrations/
│ ├── self-hosting/
│ ├── api/ # Separate "API" tab
│ │ ├── overview.md
│ │ ├── sdk.mdx
│ │ └── reference/ # Generated from OpenAPI — don't edit
│ ├── knowledge-base/ # Separate "Knowledge Base" tab
│ └── contributing/ # Separate "Contributing" tab
│ ├── local-development.mdx
│ ├── architecture.md
│ └── guidelines/
└── src/
└── lib/
├── source.ts # Docs loader + folder icon registry
└── layout.shared.tsx # Sidebar tabs (Documentation, API, ...)URL Mapping
Files map to URLs as follows (paths are relative to content/docs/):
| File Path | URL |
|---|---|
index.mdx | /docs |
quick-start.md | /docs/quick-start |
api/overview.md | /docs/api/overview |
visibility/overview.md | /docs/visibility/overview |
knowledge-base/index.md | /docs/knowledge-base |
URLs mirror folder and file names exactly, including case, so keep names lowercase with hyphens. Most folders have no index page, so a bare folder URL (one that stops at the folder name) doesn't resolve — link to a specific page instead.
Creating a New Page
1. Choose the Right Location
| Content Type | Location | Example |
|---|---|---|
| Task management | tasks/ | Tasks, subtasks, relations, templates |
| Organize & workflow | organize/ | Labels, categories, views, releases |
| Visibility & public pages | visibility/ | Visibility controls, public board |
| Account features | account/ | My tasks, notifications, settings, security |
| Organization settings | organizations/ | Members & teams, preferences, billing |
| Integrations | integrations/ | GitHub, and future integrations |
| API guides | api/ | Overview, SDK (endpoint pages are generated) |
| Self-hosting | self-hosting/ | Deployment guides |
| FAQ & troubleshooting | knowledge-base/ | Common questions |
| Contributing | contributing/ | Developer documentation |
Creating a New Section
If your content doesn't fit into an existing category, create a new folder under content/docs/ with a meta.json (see Ordering pages and folders), and add the folder to the root meta.json so it appears in the sidebar. Mention this in your PR and we'll help with the configuration if you're not sure how.
2. Create the File
Create a new .md or .mdx file with frontmatter:
---
title: Your Page Title
description: A brief description for SEO and previews
---
Your content here...3. Add It to the Sidebar Order
Add the file's name (without the extension) to the pages array in the folder's meta.json, at the position where it should appear. See the next section.
Frontmatter Reference
Every documentation page starts with YAML frontmatter:
---
title: Page Title # Required - shown in the sidebar and page header
description: Brief description # Required - shown under the title, used for SEO meta tags
---Page order and sidebar labels are not set in frontmatter. Starlight-style keys such as sidebar.order, sidebar.label, sidebar.badge and sidebar.hidden are silently ignored — use the folder's meta.json instead.
Ordering pages and folders
Each folder has a meta.json that names the folder and lists its pages in display order:
{
"title": "Organize",
"defaultOpen": false,
"icon": "IconFolders",
"pages": ["labels", "categories", "views", "releases", "..."]
}| Field | Purpose |
|---|---|
title | Folder label in the sidebar |
defaultOpen | Whether the folder starts expanded (false for most sections) |
icon | A Tabler icon name registered in src/lib/source.ts |
pages | Page order — file names without the extension, or sub-folder names |
root | true makes the folder its own sidebar tab (API, Knowledge Base, Contributing) |
Always end pages with "...". It stands in for every page you haven't listed, so a new page still appears (alphabetically, after the listed ones) instead of silently disappearing from the sidebar. A name in pages that doesn't match a file or folder is ignored, so double-check the spelling.
The root content/docs/meta.json controls the top-level order. A new top-level folder must be added there or it won't show up in the sidebar.
Generated API pages
content/docs/api/reference/ and its meta.json files are generated from the OpenAPI spec with pnpm -F landing openapi:generate. Don't edit them by hand.
Writing Style Guide
Tone and Voice
- Be direct — Get to the point quickly
- Be practical — Focus on what users need to do
- Be inclusive — Avoid jargon; explain technical terms
- Use "you" — Address the reader directly
Structure
- Start with the goal — What will readers accomplish?
- Show, don't just tell — Include code examples
- Use headings liberally — Make content scannable
- Keep paragraphs short — 2-4 sentences max
Formatting Conventions
| Element | Convention |
|---|---|
| File paths | Backticks, e.g. apps/landing/ |
| Commands | Code blocks with bash language |
| UI elements | Bold: Click Save |
| Keyboard shortcuts | Cmd/Ctrl + S |
| Variables/placeholders | {placeholder} or <placeholder> |
Code Blocks
Always specify the language for syntax highlighting:
```typescript
const example = "highlighted code";
```For terminal commands:
```bash
pnpm dev
```Callouts
Use the <Callout> component for important information. It needs no import, but the page must be an .mdx file:
<Callout type="info" title="Optional title">
Helpful additional information.
</Callout>
<Callout type="idea">
Suggestions for best practices.
</Callout>
<Callout type="warn">
Important warnings about potential issues.
</Callout>
<Callout type="error">
Critical warnings about destructive actions.
</Callout>Available types are info, warn, error, success and idea. They render as styled boxes:
This is an info callout.
This is an idea callout.
This is a warning callout.
This is an error callout.
Starlight's :::note / :::tip / :::caution / :::danger syntax is not supported here — use <Callout> instead.
Tables
Use tables for structured information:
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Data | Data | Data |These render as styled tables:
| Column 1 | Column 2 | Column 3 |
|---|---|---|
| Data | Data | Data |
Links
-
Internal links: Use absolute paths starting with
/docs/that point at a real pageSee the [Architecture Overview](/docs/contributing/architecture) -
External links: Use full URLs
Learn more at [Fumadocs](https://fumadocs.dev/)
Using MDX
Plain Markdown (.md) is simpler and preferred for most pages. Use the .mdx extension only when a page needs a component such as <Callout>: .md files are compiled as plain Markdown, so JSX in them renders as text.
---
title: Interactive Page
description: A page that uses a callout
---
Regular markdown content...
<Callout type="info" title="Heads up">
Components like this are available in every `.mdx` page without imports.
</Callout>
More markdown...Local Preview
To preview documentation changes locally:
# From repository root
pnpm -F landing dev
# Opens at http://localhost:3002Checklist Before Submitting
- Frontmatter includes
titleanddescription - The page is listed in its folder's
meta.jsonpages(and the list still ends with"...") - The page is added to the Browse by Topic table in
content/docs/index.mdx - Content follows the writing style guide
- Code blocks have language specified
- Links use correct paths (internal:
/docs/...pointing at a real page, external: full URL) - Images have alt text (if any)
- Page renders correctly in local preview (if testing locally)
Related Resources
- Fumadocs Documentation — Full Fumadocs reference
- Markdown Guide — Markdown syntax reference
- Pull Request Guidelines — How to submit your changes