Attach the HTML preview to every pull request

Write the HTML preview in CI on each pull request, and link it from the run, so anyone can read the change without a checkout.

For AI agents: the documentation index is at llms.txt, and this page is available as Markdown.

ascribe diff --format html writes one HTML file showing every changed page rendered, with the same marks as the previews and Copy prompt for an agent that reviews the page. It shows the changes, not the pull request’s comments. The file holds everything it shows and makes no network requests, so a reviewer opens it with no checkout, no build, and no account, and nothing in it runs but its own script, so a preview from a pull request you don’t trust yet is safe to open. The HTML preview is its reference.

ascribe diff --format html > review.html

Add the preview to CI

This GitHub Actions job writes the preview on each pull request, uploads it, and links it from the run’s summary, so a reviewer opens it from the pull request’s checks. Change --config docs to your project’s folder (the one with ascribe.toml), or drop it when that’s the repository’s root, and install ascribe however your other jobs do.

name: Review

on:
  pull_request:

permissions:
  contents: read

jobs:
  preview:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          # The whole history, so `ascribe diff` finds where the branch left
          # its base. The default, one commit, isn't enough.
          fetch-depth: 0
      - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
        with:
          node-version: 24
      - run: npm install --global @ascribed/cli
      - name: Write the preview
        run: >
          ascribe diff --config docs
          --base "origin/$GITHUB_BASE_REF" --format html > review.html
      - id: upload
        uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
        with:
          name: review.html
          path: review.html
          # One file, not zipped, so it opens in the browser.
          archive: false
      - name: Link the preview from the summary
        env:
          URL: ${{ steps.upload.outputs.artifact-url }}
        run: |
          {
            echo "### HTML preview"
            echo
            ascribe diff --config docs --base "origin/$GITHUB_BASE_REF" | sed 's/^/    /'
            echo
            echo "[Open the HTML preview]($URL)"
          } >> "$GITHUB_STEP_SUMMARY"
  • History. ascribe diff compares with the merge base of the pull request’s base branch and its head, as the pull request itself does, so the checkout needs enough history to find it: fetch-depth: 0. With less, ascribe diff stops and says so; --base-exact compares with the base branch’s tip instead, which also lists changes made on the base branch since the pull request branched.
  • The base. --base "origin/$GITHUB_BASE_REF" names the pull request’s base branch. Without it, ascribe diff uses the repository’s default branch.
  • Opening it. archive: false uploads the file as it is instead of in a zip, so the summary’s link opens it in the browser. The link needs read access to the repository, like the rest of the run.

This repository runs this job on these docs, when a pull request changes them or the code their examples come from, and the same job on examples/quill, in .github/workflows/review.yml: the job above is taken from that file. It also installs @ascribed/cli@next, the nightly build of main, since these docs follow main.

See also

  • The HTML preview: what the preview shows, and its limits on a large change.
  • How review works: what review compares, and what its marks mean.
  • Review: reviewing the same change in the previews, with comments.