Skip to content
Thally
Log inGet started
Guide

Updated · 8 min read

How to set up CI to trigger documentation updates on code changes

Use GitHub Actions to regenerate references, remind authors, dispatch merged changes to a docs repository, draft docs pull requests, and gate docs quality.

By Published Updated

The short answer: the core pattern for CI-triggered documentation updates has three parts. First, use paths filters so only changes to public surfaces (API specs, SDK exports, CLI commands, config schemas) start a docs job. Second, on merge, send a repository_dispatch event from the product repository to the docs repository. Third, have a workflow in the docs repository turn that event into a docs pull request, drafted by a person or by a docs agent. Add a quality gate on the docs repository so a broken docs build fails before it ships. The GitHub Actions examples below cover each step, generic first and then with Thally.

What CI can and cannot do for docs

CI is good at noticing that something changed and running a job. It is not good at knowing what the change means for a reader. That splits the work into two kinds of jobs:

JobCI aloneNeeds judgment
Regenerate API reference from a specYesNo
Remind the author when docs are missingYesNo
Notify the docs repository of a mergeYesNo
Decide which guides a change made wrongNoYes
Draft the updated wordingNoYes

The examples start with the jobs CI handles on its own, then connect CI to something that can make the judgment call.

Step 1: regenerate what comes from a spec

If your docs site renders the API reference from openapi.yaml, the only thing CI has to do is rebuild the docs when the spec changes. With the spec in the docs repository, a normal deploy on push is enough. If the spec lives in the product repository, open a PR that copies it into the docs repository whenever it changes:

name: Sync OpenAPI spec to docs
on:
  push:
    branches: [main]
    paths: ["openapi.yaml"]

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Open a PR in the docs repo
        env:
          GH_TOKEN: ${{ secrets.DOCS_REPO_TOKEN }}
        run: |
          gh auth setup-git
          gh repo clone OWNER/DOCS-REPO docs
          cp openapi.yaml docs/openapi.yaml
          cd docs
          git checkout -b "spec-sync-${GITHUB_SHA::7}"
          git add openapi.yaml
          git -c user.name="docs-bot" -c user.email="docs-bot@users.noreply.github.com" \
            commit -m "Sync OpenAPI spec from ${GITHUB_SHA::7}"
          git push origin HEAD
          gh pr create --fill

DOCS_REPO_TOKEN is a fine-grained token with contents and pull request write access on the docs repository only.

Step 2: remind authors when a public surface changes without docs

This job runs on pull requests that touch public-surface paths and comments when nothing under docs/ changed. Keep it a reminder rather than a required check. Plenty of code changes need no docs, and a hard block teaches people to add empty edits.

name: Docs reminder
on:
  pull_request:
    paths:
      - "openapi.yaml"
      - "src/public-api/**"
      - "src/cli/**"

jobs:
  remind:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Comment if docs did not change
        env:
          GH_TOKEN: ${{ github.token }}
          BASE_REF: ${{ github.base_ref }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          if ! git diff --name-only "origin/$BASE_REF...HEAD" | grep -q '^docs/'; then
            gh pr comment "$PR_NUMBER" --body "This PR changes a public surface. Does it change anything users read about? If so, link the docs update."
          fi

Pass values through env instead of expanding ${{ }} inside the script. It keeps untrusted PR content out of the shell. This version comments on every push to the PR. If that gets noisy, add a label on the first run and skip when it is present.

Step 3: tell the docs repository a change merged

When docs live in their own repository, the product repository needs a way to say "this merged, take a look." repository_dispatch does that without either repository needing access to the other's code.

In the product repository:

name: Notify docs of merged changes
on:
  pull_request:
    types: [closed]
    branches: [main]
    paths:
      - "openapi.yaml"
      - "src/public-api/**"
      - "src/cli/**"

jobs:
  dispatch:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: Send a dispatch to the docs repo
        env:
          GH_TOKEN: ${{ secrets.DOCS_DISPATCH_TOKEN }}
          PR_URL: ${{ github.event.pull_request.html_url }}
        run: |
          gh api repos/OWNER/DOCS-REPO/dispatches \
            -f event_type=product-change \
            -f "client_payload[pr_url]=$PR_URL"

In the docs repository, a workflow listens for it:

name: Handle product changes
on:
  repository_dispatch:
    types: [product-change]

jobs:
  triage:
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - name: Open a docs triage issue
        env:
          GH_TOKEN: ${{ github.token }}
          PR_URL: ${{ github.event.client_payload.pr_url }}
        run: |
          gh issue create --repo "$GITHUB_REPOSITORY" \
            --title "Docs check for $PR_URL" \
            --body "A public-surface change merged: $PR_URL. Check which pages it affects."

This is where plain CI runs out. The issue tells someone to look. It does not say which of your pages are now wrong, and it does not write the fix.

Step 4: let a docs agent draft the pull request

To go from "someone should look" to "here is the proposed update," replace the triage issue with a job that reads the merged change, finds affected pages, and opens a docs PR for review.

This is the job Thally Track does. It replaces steps 3 and 4 with a GitHub App, so there are no dispatch tokens or workflow files to maintain:

  • It reads each merged pull request in the product repositories you connect, and works out what changed for users.
  • It finds the pages that now contradict the change across your connected docs, website, and support repositories.
  • It opens a pull request for each affected repository with the proposed edits and the evidence behind them. If a merge needs no docs change, nothing is opened.
  • It can draft before merge. Add a docs-preview label to an open pull request, and reviewers see the docs change alongside the code.

Every change arrives as a pull request that a person reviews and merges.

The quickest way to see whether this beats a triage issue is to run it on changes you have already shipped. The Track demo connects to GitHub, reads your last five merged pull requests, and shows which pages each one affected. No Thally account is needed, and it only reads the repositories you grant.

Step 5: gate the docs build

The last job runs on pull requests in the docs repository itself, so automated and human edits face the same bar:

name: Docs checks
on: pull_request

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx thally check --ci --agents --min 80

thally check validates content and links and posts GitHub annotations with --ci. --agents adds the agent-readiness score, and the job fails if the score falls below --min. Outside Thally, the equivalent is a link checker, a prose linter such as Vale, and a production build.

Putting it together

TriggerWhereJob
Spec changes on mainProduct repoPR the spec into the docs repo
PR touches public surfacesProduct repoRemind the author about docs
PR mergesProduct repoDispatch to the docs repo
Dispatch receivedDocs repoDraft a docs PR, or open a triage issue
Any docs PRDocs repoValidate content and gate on quality

Start with steps 1 and 2. They cost nothing and catch the obvious cases. Add steps 3 and 4 when changes land faster than the team can trace them by hand. For the reasoning behind each layer, read how to keep your docs site in sync when code changes.

Sources and verification

Workflow syntax follows the GitHub Actions documentation for repository_dispatch and path filters. Thally commands were checked against the current CLI source and CLI reference. Checked September 24, 2026.

Published under the Thally editorial policy. Technical conformance is defined in the agent-readiness methodology.

Frequently asked questions

How do I trigger a docs build when my API spec changes?
Add a paths filter for the spec file to a push workflow on your main branch. If the docs site renders the spec at build time, that workflow can deploy the docs directly; if the spec lives in another repository, have it open a pull request that copies the spec into the docs repository.
How does a product repository notify a separate docs repository?
Send a repository_dispatch event from a workflow that runs when a pull request merges. The docs repository listens for that event type and receives the pull request URL in the client payload, without either repository needing access to the other's code.
Should CI block merges when docs are missing?
Usually not. Many code changes need no documentation update, and a hard block teaches people to add empty edits. A comment or label when public-surface paths change without docs changes is a better default.

Build docs that stay close to your product.

Create a managed site, or use the open-source engine to run Thally yourself.