Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/claude-doc-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Sync docs on merged PRs

# 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
# 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]
branches: [master]

permissions:
contents: write
pull-requests: write

jobs:
doc-sync:
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:-<empty>}"
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: |
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:*)'"
Loading