---
name: write-docs
metadata:
version: "1.0"
description: "Write, author, edit, and format GitBook documentation pages in Git-synced repos, IDEs, or any text editor. Use whenever a task involves creating or editing a GitBook markdown page, writing or updating a README.md or SUMMARY.md, inserting a hint, tab, stepper, card, or other GitBook block, configuring page frontmatter or layout options, setting up variables or expressions, or formatting content for GitBook outside the GitBook UI."
---
### When to Use This Skill
Use this skill when working with GitBook documentation through:
* Git-synced repositories (GitHub, GitLab)
* Local markdown editors
* IDE integrations
* Any environment where you're editing GitBook content as files rather than through the GitBook UI
### Quick Reference
#### GitBook Content Structure
GitBook organizes content through pages, spaces, and collections:
* **Pages** are individual markdown files that make up your documentation
* **Spaces** are collections of pages organized into a documentation site
* **Collections** are groups of spaces
**File structure:**
```
/
.gitbook/
assets/ # GitBook-managed images and files
includes/ # Reusable content blocks
vars.yaml # Space-level variables
.gitbook.yaml # Configuration
README.md # Homepage
SUMMARY.md # Table of contents
getting-started/
installation.md
quickstart.md
api-reference/
authentication.md
endpoints.md
```
**Frontmatter fields (quick form):**
```markdown
---
description: "Page description for SEO"
icon: book-open
hidden: true
vars:
page_variable: value
layout:
width: default # or 'wide'
tableOfContents:
visible: true
pagination:
visible: true
---
```
**Variables and expressions:**
* Space variables: `/.gitbook/vars.yaml`
* Page variables: Frontmatter `vars:`
* Expression syntax: `space.vars.variableName`
**Most common custom blocks:**
* `{% tabs %}...{% endtabs %}` — for alternatives
* `{% hint style="..." %}...{% endhint %}` — callouts (info/warning/danger/success)
* `{% stepper %}...{% endstepper %}` — sequential steps
* `......
` — expandable content
**Links:**
* External: `[text](https://example.com)`
* Relative (same space): `[text](page.md)`, `[text](../folder/page.md)`
* Cross-space (different space): `[text](https://app.gitbook.com/s//)` — relative paths never cross space boundaries, and this is the only correct URL form (not `/spaces//pages/`). Get `` from `GET /orgs/{orgId}/spaces` and `` from a page's `path` field in `GET /spaces/{spaceId}/content/pages`. Scaffolding a new site where the target space doesn't exist yet? Use `XSPACE_` sentinels; `configure-site` resolves them after creation. Full examples: `references/markdown.md`.
* Moved/renamed pages keep working — GitBook auto-creates a redirect from the old path.
**Key reminders:**
* Read SUMMARY.md first when working with existing content
* Test in GitBook after editing locally
* Keep SUMMARY.md synchronized with your file structure
* OpenAPI specs must be uploaded via the UI, API, MCP, or CLI, not embedded in markdown
### When to Use Which Block
| Need | Use | Why |
|---|---|---|
| Sequential, ordered instructions | `{% stepper %}` | Clear step progression |
| Alternative options (languages, platforms) | `{% tabs %}` | User chooses without page clutter |
| Optional or detailed information | `` | Keeps page scannable |
| Important warnings or tips | `{% hint %}` | Colored callout (info/warning/danger/success) |
| Side-by-side comparisons | `{% columns %}` | Parallel layout (max 2 columns) |
| Timeline or changelog | `{% updates %}` | Dated entries with tag filtering |
| Visual navigation cards | `` | Clickable card grid |
| Downloadable files | `{% file %}` | File with caption |
| Call-to-action links | `` | Primary or secondary button |
| Reusable content across pages | `{% include %}` | Single source of truth |
| Dynamic content | `` | Renders variable values |
**Variable scope:**
| If variable is... | Define in... | Access with... |
|---|---|---|
| Used across multiple pages | `/.gitbook/vars.yaml` | `space.vars.variableName` |
| Specific to one page | Frontmatter `vars:` | `page.vars.variableName` |
### Working with Existing Content
1. **Read SUMMARY.md first** — complete table of contents and file hierarchy
2. **If no SUMMARY.md** — browse the directory structure directly
3. **Check .gitbook.yaml** — root path, custom README/SUMMARY locations, redirects
4. **Check .gitbook/assets/** — uploaded images and files
5. **Check .gitbook/vars.yaml** — space-level variables
### Common Pitfalls
**Cross-space links:**
* Don't use relative paths to link to a page in a different space — they won't resolve.
* Don't use `/spaces//pages/` — that's not a valid GitBook link form.
* Use `https://app.gitbook.com/s//` instead, where `` is the target page's `path` field (from `GET /spaces/{spaceId}/content/pages`), not its page ID.
* Use `XSPACE_` sentinels when space IDs aren't known yet (new space, not yet created).
**File organization:**
* Don't reference the same markdown file twice in SUMMARY.md
* Keep file paths consistent between SUMMARY.md and actual file locations
**Configuration:**
* When using Git Sync, manage README.md only through your repository
* Test redirects after moving or renaming files
**Custom blocks:**
* Always close blocks properly (`{% endtab %}`, `{% endhint %}`, etc.)
* Match opening and closing tags exactly
**Frontmatter:**
* Always quote `description:` values containing `:`, `#`, or other YAML-significant characters — unquoted special characters cause silent Git Sync failures with no error message
* Frontmatter must be at the very top of the file
### Working with Git Sync
When GitBook is synced with Git, changes flow in both directions — Git changes update GitBook, and GitBook UI changes commit back to Git. Merge conflicts are resolved in Git.
**Best practices:** make structural changes via SUMMARY.md in Git; use branch-based workflows for significant updates; review auto-generated commits from GitBook.
#### Previewing a pushed branch
The two-link rule below covers content pushed through a change request. When you push
through **Git** instead, the equivalent is the commit status: opening a pull/merge request —
or pushing to a branch that already has one — makes GitBook import that branch and post a
status linking a preview of the rendered site. **Give the user that link whenever you push
docs changes, without being asked.** Read it off the commit status rather than building a
URL: the revision id is minted at import time and can't be derived from the branch or the PR,
and every push mints a new one, so an earlier link goes stale. See
`references/git-sync-previews.md` for the GitHub and GitLab commands and what to do while the
import is still running.
#### Choosing Git Sync vs. a change-request content push
When a space has Git Sync configured and you have (or can get) a local checkout of the synced repo, **prefer editing the files directly and committing/pushing** — Git Sync propagates the change to GitBook. This holds even in an MCP session where a change-request content-push tool (e.g. `updateChangeRequestContent`) is available and connected: the tool being one call away isn't a reason to bypass Git as the source of truth. An agent that discovers it *can* push straight into a CR should still check whether Git Sync is set up and reachable before doing so.
Reach for the change-request content-push path instead (MCP's `updateChangeRequestContent` or similar, or the REST `POST .../change-requests//content` endpoint — see the `cr-create` skill) when:
- the space has no Git Sync configured yet (e.g. a brand-new space still mid-setup),
- there's no local Git checkout available in the current environment (no filesystem access to the synced repo), or
- the change is small and targeted (a typo, one paragraph, one field) — opening a CR is proportionate, and a full clone/commit/push cycle isn't worth it for that.
For anything larger — a new page tree, a multi-page rewrite, a migration — prefer Git Sync, even if that means pausing to confirm the repo is cloned locally first. Don't default to the change-request tool just because it's the first one that worked.
#### Two links are mandatory whenever a change request is involved
If any part of this edit went through a change request (`create_change_request` / `updateChangeRequestContent`, or the REST equivalents), **the edit is not done until both of the following have been reported back, every single time — this is a hard rule, not a reminder to skim past:**
1. **The CR diff/editor link** — `urls.app` on the change-request object, returned by `create_change_request`, `updateChangeRequestContent`, or `getChangeRequestById`.
2. **The site preview link** — the site URL from the **Site** object (`urls.published` when the site is public, else `urls.preview`) with **`/~/changes//` appended**. This is never part of the change-request response — it requires a separate lookup — which is exactly why it's the one that gets forgotten. Resolve it every time, not just when it comes to mind. **Without the `~/changes/` segment the link is not a preview of the change request** — it renders the site's current content, so it will look plausible and be wrong.
This applies no matter which skill pushed the content (this skill or `configure-site`) and no matter the transport (MCP or REST). See the `cr-create` skill's "Surfacing the preview link" for the full write-up and the REST resolution steps. **MCP equivalent** (GitBook MCP has no single ready-made "give me the preview link" call):
1. Resolve the space's organization — `invoke_operation("getSpaceById", {path:{spaceId}})` → `.organization` (skip if you already have the org ID).
2. Find which site the space belongs to — `list_sites` / `get_site_structure`, or check each site's site-spaces for a match on `.space.id`.
3. `invoke_operation("getSiteById", {path:{organizationId, siteId}})` → `.urls.published` (once the site is live), else `.urls.preview`. Append `/~/changes//`, stripping the trailing slash the API returns.
If the space isn't attached to any published site, say so plainly and give only the diff link — don't quietly drop the preview line without explanation.
This has already failed silently in practice: an edit was pushed and merged with only the diff link reported, and the preview link only surfaced when a person asked for it directly. Treat the two-link checklist above as literal.
### Reference files
Load these on demand when the task requires deeper detail:
- `references/blocks.md` — full syntax and worked examples for every GitBook block type: tabs, steppers, hints, expandable, columns, updates, cards, embeds, files, buttons, icons, reusable content, and OpenAPI blocks. **Load when authoring non-trivial pages or when the quick-reference above isn't enough.**
- `references/frontmatter.md` — all frontmatter fields with descriptions, YAML quoting rules, cover images, adaptive content (`if:`), and the variables/expressions deep-dive. **Load when configuring page layout, covers, conditional visibility, or variables.**
- `references/markdown.md` — standard markdown, code blocks with titles, math/TeX, Mermaid diagram types and examples, and SVG handling quirks. **Load when working with diagrams, math, or SVG assets.**
- `references/configuration.md` — `.gitbook.yaml` options, the `.gitbook/` directory structure (assets, includes, vars, tags), and SUMMARY.md grammar rules in full. **Load when setting up a space, adding redirects, or authoring/editing SUMMARY.md.**
- `references/git-sync-previews.md` — getting a preview link for a branch pushed through Git Sync: reading the GitBook commit status on GitHub and GitLab, telling the site preview from the editor diff, and handling an import that's still running. **Load whenever you push docs changes to a branch with a pull/merge request open.**