From f23f5680d416dd3f699a1261828e3d74256a54e2 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Tue, 25 Aug 2026 15:00:56 -0500 Subject: [PATCH 1/2] ci: sync docs via Claude after merged PRs Adds a workflow that runs after every merged PR and asks Claude to check whether root/package READMEs or /docs need updating to reflect the change, opening a follow-up PR only when it finds something to update. Uses pull_request_target rather than pull_request so the workflow gets write access even for merges of fork-authored PRs (common in this repo). This is safe because the job only ever checks out base.ref (the already-merged, already-reviewed default branch) - it never builds or executes the contributor's own head ref. Requires an ANTHROPIC_API_KEY repo secret and the Claude GitHub App (https://github.com/apps/claude) installed on this repo; neither is included here. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/claude-doc-sync.yml | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/claude-doc-sync.yml diff --git a/.github/workflows/claude-doc-sync.yml b/.github/workflows/claude-doc-sync.yml new file mode 100644 index 000000000..cbd9a857e --- /dev/null +++ b/.github/workflows/claude-doc-sync.yml @@ -0,0 +1,46 @@ +name: Sync docs on merged PRs + +# Runs after every merged PR and asks Claude to check whether any +# documentation (root README, package READMEs, /docs) needs updating to +# reflect the change, opening a follow-up PR only if it finds something to +# update. +# +# Uses pull_request_target (not pull_request) so the workflow runs with this +# repo's own permissions even when the merged PR came from a fork - this repo +# takes plenty of external contributions and a plain `pull_request` trigger +# gets a read-only token for fork-authored PRs, which would make `gh pr +# create` fail below. This is safe here because we only ever check out +# base.ref (the already-reviewed, already-merged default branch), never the +# PR's own head ref - we never build or execute the contributor's code. +on: + pull_request_target: + types: [closed] + +permissions: + contents: write + pull-requests: write + +jobs: + doc-sync: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Checkout base branch + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + ref: ${{ github.event.pull_request.base.ref }} + fetch-depth: 0 + + - name: Sync docs with Claude + uses: anthropics/claude-code-action@16b3b310c3d7b5279df73130324d5205aeea8eac # v1 + with: + prompt: | + Pull request #${{ github.event.pull_request.number }} ("${{ github.event.pull_request.title }}") was just merged into ${{ github.event.pull_request.base.ref }}. + + 1. Run `gh pr diff ${{ github.event.pull_request.number }}` to see exactly what changed. + 2. Search this repository's documentation (root README.md, each package's README.md, and any /docs content) for anything describing the behavior, API, configuration, or usage that this PR changed. + 3. If you find documentation that's now inaccurate, incomplete, or missing details because of this change, update it to match. Do not treat CHANGELOG.md files as documentation - they're generated by release tooling, leave them alone. + 4. If no documentation needs updating, stop here: do not create a branch, commit, or pull request. + 5. If you did update documentation, create a new branch off ${{ github.event.pull_request.base.ref }} named `docs/sync-pr-${{ github.event.pull_request.number }}`, commit the changes, push it, and open a pull request against ${{ github.event.pull_request.base.ref }} with `gh pr create`. Title it "docs: sync with #${{ github.event.pull_request.number }}" and explain in the body which doc(s) you updated, why, and link back to #${{ github.event.pull_request.number }}. + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,Bash(git:*),Bash(gh:*)'" From 5190faf585608d0bcb76fd184f59449b25b2f535 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Tue, 25 Aug 2026 15:09:42 -0500 Subject: [PATCH 2/2] ci: gate doc-sync on master merges with an approving review Restricts the trigger to PRs merged into master (branches: [master]), and adds a gate step that only lets the Claude step run when gh pr view reports reviewDecision == APPROVED. master requires 1 approval via branch protection, but enforce_admins is off, so an admin can still merge without one - this closes that gap instead of assuming protection alone guarantees a review happened. Cuts run volume/cost by skipping merges to other branches (e.g. beta) and admin-bypassed merges with no approval on record. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/claude-doc-sync.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude-doc-sync.yml b/.github/workflows/claude-doc-sync.yml index cbd9a857e..99100f1a0 100644 --- a/.github/workflows/claude-doc-sync.yml +++ b/.github/workflows/claude-doc-sync.yml @@ -1,10 +1,17 @@ name: Sync docs on merged PRs -# Runs after every merged PR and asks Claude to check whether any +# Runs after a PR merges into master and asks Claude to check whether any # documentation (root README, package READMEs, /docs) needs updating to # reflect the change, opening a follow-up PR only if it finds something to # update. # +# Gated to keep run volume (and cost) down: only master-targeted merges +# (branches: [master] below) that also carry an approving review +# (reviewDecision == APPROVED, checked in the gate step) trigger a Claude run. +# master requires 1 approval by branch protection, but enforce_admins is off, +# so an admin can still merge without one - this gate closes that gap rather +# than assuming protection alone guarantees a review happened. +# # Uses pull_request_target (not pull_request) so the workflow runs with this # repo's own permissions even when the merged PR came from a fork - this repo # takes plenty of external contributions and a plain `pull_request` trigger @@ -15,6 +22,7 @@ name: Sync docs on merged PRs on: pull_request_target: types: [closed] + branches: [master] permissions: contents: write @@ -25,13 +33,29 @@ jobs: if: github.event.pull_request.merged == true runs-on: ubuntu-latest steps: + - name: Require an approved review + id: gate + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + decision=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json reviewDecision -q .reviewDecision) + echo "review decision for #$PR_NUMBER: ${decision:-}" + if [ "$decision" = "APPROVED" ]; then + echo "approved=true" >> "$GITHUB_OUTPUT" + else + echo "approved=false" >> "$GITHUB_OUTPUT" + fi + - name: Checkout base branch + if: steps.gate.outputs.approved == 'true' uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ github.event.pull_request.base.ref }} fetch-depth: 0 - name: Sync docs with Claude + if: steps.gate.outputs.approved == 'true' uses: anthropics/claude-code-action@16b3b310c3d7b5279df73130324d5205aeea8eac # v1 with: prompt: |