Skip to content

Documentation sync

Documentation that lives next to the code is the documentation that stays true. Documentation sync lets an entity’s documentation sections be sourced from Git: you point a section at a file — or a glob of files — in a repository, and Componecat keeps the section’s content current.

Synced sections behave like any other documentation section: they render Markdown with diagrams, they’re full-text searchable, and AI agents can read them over the MCP server. The difference is that the repository is the source of truth.

Documentation sync is a capability on a GitHub, GitLab, or Bitbucket integration; see Integrations for connecting one.

Open the integration and find the Documentation Syncing card. Its only setting is the schedule:

Setting Meaning
Schedule (cron) How often the sync runs. Default 0 */6 * * * — every six hours.

A run sweeps every Git-sourced section in your organization whose repository belongs to that provider — so a GitHub connection refreshes sections sourced from GitHub repositories, and never tries to read a GitLab URL. If your documentation spans several providers, enable the capability on each one.

The credential needs read access to repository contents for the repositories your sections point at. Sections in repositories the credential can’t see fail with a recorded error.

On an entity’s Documentation tab, choose Git Source and fill in:

Field Meaning
Repository URL Optional. Defaults to the entity’s own linked repository.
File Path Pattern The file to pull, or a glob. Required.
Branch Optional. Defaults to the repository’s default branch.

The path can be a single file (docs/architecture.md) or a glob: * matches within a path segment (docs/*.md), and ** matches across segments (docs/**/*.md).

When a glob matches several files, each file becomes its own page in the section. Selecting the section on the Documentation tab lists its pages beneath it in the contents sidebar, grouped by folder, and shows one page at a time with its file path and links to the previous and next page. Pages are ordered by folder, with a folder’s own files ahead of its subfolders and its README.md or index.md first. A page’s title is the file’s frontmatter title, otherwise its first # heading, otherwise the file name. A section keeps at most 500 pages; files past that, in page order, are left out.

Search still treats the section as one document, and the GraphQL content field keeps every page joined together, each preceded by a comment marking which file it came from; the pages field returns them one by one. The MCP server’s get_documentation tool lists each page under its own heading with its file path. A glob section synced before pages existed shows its joined content until its next sync.

Leading YAML frontmatter is stripped from each file as it’s pulled in, so documentation written for a static-site generator lands cleanly.

Sections can also be declared in a repository’s componecat.yaml, so the whole setup is version-controlled alongside the entity:

spec:
docs:
sections:
- title: Architecture
type: architecture
sourcePath: docs/architecture.md
- title: Runbooks
type: runbook
sourcePath: docs/runbooks/**/*.md

sourceRepository and sourceBranch are available too, and default to the entity’s repository and its default branch. See the descriptor file reference.

Each Git-sourced section shows its sync state — when it last synced, whether a sync is pending, or that the last attempt failed and when it last succeeded.

Refresh on the entity’s Documentation tab syncs that entity’s Git-sourced sections immediately, without waiting for the schedule, and the tab shows the new content as soon as the sync finishes. It’s available once the entity has at least one Git-sourced section and a Git integration exists to pull from. Run now on the integration’s Documentation Syncing card does the same for every section that provider covers.

While the capability is enabled, its card lists recent runs with the number of sections synced and failed, and one error entry per failed section naming the repository, the path, and the reason — a missing file, a branch that doesn’t exist, a permission problem.

The organization’s wiki can also live in a repository. It is read through the same capability, so the integration needs Documentation Syncing enabled. Organization admins connect it under Wiki → Settings:

Field Meaning
Integration A GitHub, GitLab, or Bitbucket integration with Documentation Syncing enabled.
Repository The repository as the provider names it, e.g. acme/handbook. A pasted web URL works too, including the URL of a folder or file in the repository (…/tree/main/docs), which is cut back to the repository.
Branch The branch the wiki is read from. Default main.
Root path The directory holding the Markdown files, e.g. docs/wiki. Leave it empty for the repository root.

Componecat checks that the integration can read that directory before it saves the source. Connecting then:

  • Moves the existing wiki pages to Trash. They stay there, outside the normal retention window, until the wiki is disconnected.
  • Makes the wiki read-only. Every page shows a banner naming the repository, the branch, and the last sync, with an Edit in GitHub (or GitLab, Bitbucket) link to the page’s file. Creating, editing, deleting, and restoring pages is refused with WIKI_EXTERNALLY_MANAGED, in the app and over the REST API and MCP server alike.

The wiki syncs on the integration’s Documentation Syncing schedule, right after it is connected, whenever an admin clicks Sync now on the settings page, and when a push changes it (see Sync on push). Each sync reads every .md file under the root path on the branch:

  • Page addresses follow the file paths. guides/onboarding.md becomes the page guides/onboarding. Folder and file names are lower-cased and anything other than letters and digits becomes -, so Conventions/Service Tiers.md becomes conventions/service-tiers. A README.md or index.md stands for its folder: guides/README.md is the page guides, and the one at the root is the wiki’s home page.

  • The title is the frontmatter title, otherwise the first # heading, otherwise the file name.

  • Tags come from the frontmatter tags list. Each tag must be exactly one reference; quote them, since @ and # have a meaning of their own in YAML:

    ---
    title: On-call guide
    tags: ["@platform", "#service://payments/api", "[[conventions/service-tiers]]"]
    ---

    A tag that isn’t a single reference is left out, with a warning in the sync history.

  • Links between files keep working. A relative link to another .md file in the wiki, such as [setup](../setup.md#install), opens that wiki page.

  • Unchanged files are skipped, so a sync with nothing new changes nothing. References are still re-checked, so a page that names a team created since the last sync links to it.

  • Deleting a file deletes its page. The repository history is how to get it back.

A file that can’t be imported keeps its last synced page and is listed in the sync history with the reason, while the rest of the wiki still syncs. Files larger than 500 KB, paths longer than 1,000 characters, a path with no letters or digits in a folder or file name, two files that make the same page address (such as Guides.md and guides/README.md), and pages under home/ are not imported. Only the first 2,000 files (by path) are imported. If the repository can’t be read at all, the sync fails, the error is shown on the settings page, and every page stays as it was.

Point the integration’s webhook at Componecat — the same webhook that repository scanning uses — and the wiki syncs within moments of a push instead of waiting for the schedule. A push starts a sync when it is to the wiki’s repository and branch and adds, changes or deletes a .md file under the root path; pushes to other branches, or that only touch other files, don’t. Bitbucket doesn’t say which files a push changed, so every Bitbucket push to the wiki’s branch starts a sync (unchanged files are still skipped). A push that arrives while a sync is running doesn’t start another one; if it came in after that sync read the repository, the next push, scheduled sync or Sync now picks it up. Each sync run records whether it came from the schedule, an admin, or a push (the trigger field of a sync run in the GraphQL API).

The settings page shows the sync status, the last error, and the history of sync runs, and follows a sync while it runs. Sync now is unavailable while a sync is running; sync again once it finishes to pick up newer changes. Turning Documentation Syncing off on the integration pauses the wiki’s sync (and Sync now) but keeps it read-only. The integration can’t be deleted while the wiki uses it; disconnect the wiki first.

Disconnect turns the wiki back into an app-authored one: the synced pages stay and become editable, and the pages that were moved to Trash can be restored again, with a fresh retention window.

  • A section never syncs. Check that an integration for that repository’s provider exists and has Documentation Syncing enabled. Componecat matches sections to providers by the repository URL.
  • The section is empty. The path pattern probably matched nothing. Confirm the path relative to the repository root and the branch.
  • Content disappeared after an edit in the app. A Git-sourced section is overwritten by its source on the next sync. Edit the file in the repository, or remove the Git source to make the section locally authored again.
  • Everything fails at once. Test the integration’s connection — an expired credential surfaces here first.