Docs as Code
routebase docs pull downloads a documentation version into a folder of Markdown files, and
routebase docs push writes local changes back. Between those two your documentation lives in your
repository, where it is reviewed in pull requests, versioned with the code it describes and
editable in whatever editor you already use.
The Doc Hub in the app stays fully usable while you do this, because the two are views of the same pages rather than competing sources.
This guide assumes the CLI is installed and configured, which CLI Overview covers.
Pulling
routebase docs pull --project <project-id> --dir docs
| Option | Default | Effect |
|---|---|---|
--project |
required | The project id |
--doc |
the only one | The documentation id, optional when the project has exactly one |
--version-id |
highest version number | Which version to pull |
--dir |
docs |
Where to write the files |
What you get:
- Pages become
{slug}.mdwith YAML frontmatter. - Folders become directories with a
_folder.jsonsidecar holding their metadata. - API-reference nodes (spec snapshots) are skipped and listed at the end of the run. They are generated from your specs, so there is no Markdown to edit and you manage them in the app.
The frontmatter
---
id: 6f1b2c3d-4e5f-6789-abcd-ef0123456789
title: "Getting Started"
slug: "getting-started"
icon: "rocket"
pageType: "markdown"
position: 0
rowVersion: "AAAAAAAAB9E="
---
# Getting Started
Your content starts here.
Leave these fields alone unless you mean to change them. Two of them do real work:
slugis the page's address on the portal and howpushmatches a local file to a remote page. Renaming it moves the page and breaks any link pointing at the old address.rowVersionis the concurrency token from the moment you pulled. It is what letspushnotice that someone edited the page in the app since then, as described below.
Two optional fields carry the search metadata of a page. metaDescription holds the description
a search result shows, and metaKeywords holds the keywords the page is tagged with. pull writes
them when the page has them, and push sets them on the page like any other field.
position sets the order among siblings and is written back on push. icon is optional.
Pushing
routebase docs push --project <project-id> --dir docs --dry-run
routebase docs push --project <project-id> --dir docs
Run --dry-run first. It computes the whole diff and prints what would change without writing
anything, which is the cheapest way to catch a stray rename before it becomes a moved page.
push targets a mutable version (Draft or Review). By default it picks the newest one. A
version that is already published is immutable, and the command says so rather than cloning it
behind your back. Clone it in the app first, or point --version-id at a mutable one. See
Doc versioning.
What push does and does not do
It matches local files to remote pages by slug within each parent folder, then does four things:
- It creates pages and folders that exist locally but not remotely.
- It updates pages whose content differs, comparing with line endings normalised, so a Windows checkout does not show every page as changed.
- It skips unchanged pages entirely.
- It restores sibling order from
position.
It never deletes. A page that exists remotely with no local counterpart is reported as a warning
and left alone. Deleting is done in the app, deliberately, because a --dir pointed one level too
deep would otherwise wipe a documentation version in one command.
Conflicts
If someone edited a page in the app after your pull, its rowVersion no longer matches and the
server rejects that write with a conflict. The page is never overwritten. The conflict is
collected, the rest of the push continues, and the command exits with code 6.
To resolve, pull again and reapply your change on top of the newer content. There is no force flag, because the failure mode it would create, which is silently discarding a colleague's edit, is worse than the inconvenience.
After a successful create or update, the CLI writes id, slug and the fresh rowVersion back
into the local file. That is why a second push right after the first does not conflict with
itself, and why those write-backs belong in your commit.
Transient failures (5xx, 429, network timeouts) are retried with backoff, up to three attempts in total, before the command gives up.
A round trip in a pipeline
The natural shape is that docs live in the repo, and a merge to main pushes them.
name: Publish docs
on:
push:
branches: [main]
paths: ["docs/**"]
jobs:
push-docs:
runs-on: ubuntu-latest
env:
PROJECT_ID: 00000000-0000-0000-0000-000000000000 # <-- your project id
# US-hosted organizations only; EU needs nothing.
# ROUTEBASE_REGION: us
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Install the Routebase CLI
run: dotnet tool install --global Routebase.Cli
- name: Configure
run: routebase config set-api-key "$ROUTEBASE_API_KEY"
env:
ROUTEBASE_API_KEY: ${{ secrets.ROUTEBASE_API_KEY }}
# Exit 6 means a page changed in the app since the last pull — worth failing on,
# so nobody's edit gets quietly stranded.
- name: Push the docs
run: routebase docs push --project "$PROJECT_ID" --dir docs
The key needs docs:write (and docs:read for pull). Pushing writes into a Draft version rather
than publishing. Publishing stays a deliberate step in the app, so a merge never puts unreviewed
text in front of your readers. See Publishing.
When to use this
Docs-as-code pays off when the documentation changes with the code. That covers a client library, a set of guides that follows a release, and anything a reviewer should see in the same pull request as the change it describes.
It pays off less for pages that non-engineers maintain. Those people have a good editor in the app already, and routing their edits through Git adds a step without adding review value. Mixing both in one documentation version is fine, because the two only meet when the same page changes on both sides, and the conflict handling above is exactly for that case.
Related
- CLI Overview — install, configuration, exit codes
- CLI in CI/CD — the CLI's testing and scanning commands
- Doc versioning — mutable versions and why push needs one
- Publishing — turning a Draft into a live portal
- API Keys — creating and scoping the key