Updated · 10 min read
Technical authoring software
Compare six technical authoring software options by who writes your docs and how content ships. Includes MadCap Flare, RoboHelp, Paligo, ClickHelp, GitBook, and HelpNDoc.
Updated · 13 min read
Set up CI documentation updates with a tested reference generator, a GitHub Actions check, scoped cross-repository handoffs, and human review before release.
A client timeout changes from ten seconds to twenty. The product tests pass, but the configuration reference still says ten. A continuous integration (CI) job can catch that mismatch before merge if the reference comes from the same maintained source. The quickstart that explains when to override the timeout needs a different check: someone has to understand what changed for the reader.
CI documentation updates work best when you separate generation, validation, and editorial review. This guide builds a small reference check you can reproduce locally, then explains how to extend that process to separate documentation repositories and reviewed proposals. It is for engineers maintaining Git-based product documentation. The runnable example uses synthetic configuration data, Node.js 24, and no external packages or credentials.
Choose the output you want before choosing the trigger.
| Job | Source | Useful output | What still needs review |
|---|---|---|---|
| Generate reference material | Maintained schema, types, or command definitions | Reproducible reference files | Whether the source describes the released product |
| Check documentation | Docs, examples, links, and build configuration | A failing check with a specific problem | Whether passing instructions solve the reader's task |
| Remind an author | Changed public-surface paths | One actionable reminder | Which pages the behavior affects |
| Propose prose updates | A product change and applicable docs | A reviewable diff with supporting evidence | Accuracy, missing pages, and release timing |
A successful build proves that the site can build. It does not establish that a tutorial teaches the right behavior. Keep both checks in the process. Our guide to keeping docs in sync with code covers the broader ownership and review work.

Start in a disposable directory or a branch in a test repository. Run the commands from that directory throughout this example. Create directories for a source file and generator:
mkdir -p config scripts
Save this synthetic configuration as config/defaults.json. In a real project, use the schema or definitions the product actually consumes. A second hand-maintained copy would create another place for drift.
{
"timeoutMs": 10000,
"maxRetries": 3
}
Save the following as scripts/generate-reference.mjs. It accepts nonnegative integer defaults with alphanumeric setting names and writes a sorted Markdown table. The --check mode compares the expected bytes with the saved file without changing it.
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
const defaults = JSON.parse(readFileSync("config/defaults.json", "utf8"))
const keys = Object.keys(defaults).sort()
for (const key of keys) {
if (!/^[A-Za-z][A-Za-z0-9]*$/.test(key) ||
!Number.isSafeInteger(defaults[key]) || defaults[key] < 0) {
throw new Error(`Invalid default: ${key}`)
}
}
const rows = keys.map(key => `| ${key} | ${defaults[key]} |`)
const output = [
"# Client defaults", "", "| Setting | Default |",
"| --- | --- |", ...rows, ""
].join("\n")
const destination = "docs/generated/defaults.md"
if (process.argv.includes("--check")) {
if (!existsSync(destination) || readFileSync(destination, "utf8") !== output) {
console.error("Reference is stale or missing. Run the generator.")
process.exitCode = 1
} else {
console.log("Reference is current.")
}
} else {
mkdirSync("docs/generated", { recursive: true })
writeFileSync(destination, output)
console.log(`Wrote ${destination}`)
}
Generate and check the reference:
node scripts/generate-reference.mjs
node scripts/generate-reference.mjs --check
The first command writes docs/generated/defaults.md. The second prints Reference is current. and exits successfully. Commit the source, script, and generated file together. Edit the source when a default changes, then regenerate. Manual edits to this generated page will fail the byte comparison.
For an OpenAPI reference, substitute your pinned generator and maintained API description. Include referenced files in its inputs. Keep generated output separate from authored explanation so the generator cannot overwrite a writer's guide.
Change timeoutMs to 20000 in the JSON file, leaving the generated Markdown untouched. Run the check again:
node scripts/generate-reference.mjs --check
It prints Reference is stale or missing. Run the generator. and exits with status 1. Regenerate, inspect the diff, and rerun the check. It now passes with a twenty-second default in the reference.
This is the boundary of the example. The script checks the generated file only. It will not find a sentence in a quickstart that promises a ten-second timeout, infer which product release uses the new value, or test the timeout implementation. Add those checks separately. Remove the disposable directory when you finish, or keep the files on your test branch.
In the test repository, save this workflow as .github/workflows/docs-reference.yml. It checks every pull request and pushes to main. Change that branch name if your default branch differs.
name: Docs reference
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
reference:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "24"
package-manager-cache: false
- name: Check generated reference
run: node scripts/generate-reference.mjs --check
The actions are pinned to full commit revisions verified on October 21, 2026. Review updates through your dependency process. Consult the checkout and setup-node documentation for runner requirements, particularly on self-hosted runners.
The local script and its failure cases were executed with Node.js 24.1.0. This workflow's configuration was checked against GitHub's documentation, but the sample was not executed on a hosted Actions runner. After adding it to your test repository, open a PR with a stale reference, observe the failure, then regenerate and push the fix. Confirm the check passes on the new revision before making it required.
There is deliberately no workflow-level path filter. GitHub documents that checks can remain pending when a workflow is skipped by branch or path filters. A required check that never starts can block an unrelated change. For this small generator, running on every PR keeps the result straightforward.
For a real docs site, add its production build, link checks, and executable example tests to this validation stage using the project's locked dependencies. If you use a merge queue, configure and verify the appropriate merge_group trigger too. The sample does not include merge-queue coverage.
Generation covers facts that have a maintained source. For the rest, ask the author what changed for users. A new timeout default might affect the quickstart, retry guidance, migration notes, and older supported versions differently.
A reminder can inspect API descriptions, exported SDK interfaces, CLI definitions, or configuration paths. Make it one updatable comment or a label with an owner, rather than a new comment on every commit. Give the author a way to explain why no docs change is needed. A path match is a signal to review, not proof that a page is wrong.
Keep the validation workflow read-only. Fork PRs normally lack repository secrets and have a read-only token. Put any privileged reminder or writing step behind a separately reviewed trust boundary. Do not switch to pull_request_target and execute the contributor's code to obtain write access. Follow GitHub's guidance on untrusted checkouts and script injection. When a script consumes PR text, pass it through an environment variable or structured input instead of interpolating it into shell code.
When product code and docs live separately, pass a specific revision to the documentation workflow. A notification does not grant the receiver permission to read a private source repository.
GitHub's repository_dispatch event is one option. The receiving workflow must exist on the docs repository's default branch. A fine-grained token used to create the dispatch needs Contents: write on that destination repository. The source repository's normal GITHUB_TOKEN does not automatically grant access to another private repository.
Design the handoff before adding a remote writing job:
A GitHub App can provide scoped installation tokens when the workflow needs permissions beyond its normal token. Review GitHub's authentication guidance. This section describes a handoff design, not a tested cross-repository dispatch implementation.
To move from a notification to proposed wording, an author or tool needs to inspect the product change and the affected passages. Include the old claim, the relevant source change, the applicable version, and the reason for each edit. A model-generated diff still needs the same build, link, example, and editorial checks as a human contribution.
Thally Track provides this workflow for connected GitHub sources and documentation destinations. You select repositories, branches, and optional watched paths. Its triggers include trusted same-repository, non-draft PR updates, merged changes, and scheduled branch comparisons. Each destination has its own run result. Track opens ready-for-review PRs and never merges them.
Track requires Cloud access, including trial access, and shared workspace AI Credits. It is separate from the MIT publishing engine and self-managed authoring tools. Connected Knowledge surfaces retain their own checks, previews, and publishing workflows. This does not imply a direct integration with every hosted help center.
Keep your existing CI gates when adding Track. It supplies proposals, while your repository's review and release process decides what reaches readers. For other approaches, see our documentation automation software comparison.

Before calling an update complete, inspect the run and the rendered page on the exact documentation revision under review.
| Situation | What to inspect | Next action |
|---|---|---|
| Generated reference is stale or missing | Source, generator version, and expected diff | Regenerate and commit the output, then rerun |
| A check stays pending | Trigger filters, approvals, and branch requirements | Confirm the intended workflow actually started |
| No docs proposal appears | Run status, accessible sources, watched paths, and destination | Separate completed no-change from failed or skipped work |
| An automated PR has no passing validation | Its latest revision and actual check runs | Resolve approval or trigger requirements, then verify the result |
| A product change is merged but unreleased | Release state and the docs version being edited | Hold current-version publication until the behavior is available |
| An older supported release keeps the old default | Version-specific guide and reference | Preserve the accurate older instructions |
For the timeout example, completion means the generated table says twenty seconds, the current quickstart gives correct override advice, older versions retain their own defaults, and the preview renders those instructions correctly. If publication introduces an error, restore the last accurate documentation revision, correct the source or proposed edit, and rerun the same checks before releasing again.
Start with one generated reference and one known stale case. Once those results are dependable, add the prose review and cross-repository handoff your team needs. If you are evaluating Thally, inspect the read-only Track preview, then follow the setup guide for approved sources and destinations. The preview does not open PRs.
Reviewed October 21, 2026. GitHub behavior follows the linked workflow syntax, event, security, authentication, and REST references. Thally claims follow its public Track and Knowledge surfaces guides. We build Thally. The local generation example uses synthetic data and is not a product benchmark. Hosted Actions execution, a cross-repository dispatch, and a private Track run were not performed. See our editorial policy.
Published under the Thally editorial policy. Technical conformance is defined in the agent-readiness methodology.
Create a managed site, or use the open-source engine to run Thally yourself.