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
52 changes: 38 additions & 14 deletions .github/workflows/claude-documentation-reviewer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,56 @@ on:
types: [opened, edited, reopened, synchronize]
paths:
- '**.md'
pull_request_review_comment:
issue_comment:
types: [created]
pull_request_review:
types: [submitted]

jobs:
claude-response:
runs-on: ubuntu-latest
# For issue_comment events, only run on PR comments that mention @claude
if: |
github.event_name == 'pull_request_target' ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@claude'))
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- name: Get PR branch for issue_comment events
id: pr-info
if: github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_DATA=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json headRefName,headRefOid)
echo "branch=$(echo "$PR_DATA" | jq -r '.headRefName')" >> "$GITHUB_OUTPUT"

- name: Checkout repository
uses: actions/checkout@v4
with:
# Use head SHA (not branch ref) to prevent TOCTOU attacks from forks
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 # Need full history to compare with base branch
# For fix mode, check out the branch by name so git push works.
# For review mode, check out by SHA to prevent TOCTOU attacks from forks.
ref: ${{ github.event_name == 'issue_comment' && steps.pr-info.outputs.branch || github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0

- name: Get changed markdown files
id: changed-files
if: github.event_name == 'pull_request_target'
run: |
# Get the base branch
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"

# Get only changed .md files
CHANGED_MD_FILES=$(git diff --name-only --diff-filter=ACMRT $BASE_SHA $HEAD_SHA | grep '\.md$' || true)

if [ -z "$CHANGED_MD_FILES" ]; then
echo "No markdown files changed"
echo "files=" >> "$GITHUB_OUTPUT"
echo "count=0" >> "$GITHUB_OUTPUT"
else
echo "Changed markdown files:"
echo "$CHANGED_MD_FILES"
# Create a comma-separated list for the prompt
FILES_LIST=$(echo "$CHANGED_MD_FILES" | tr '\n' ',' | sed 's/,$//')
echo "files=$FILES_LIST" >> "$GITHUB_OUTPUT"
echo "count=$(echo "$CHANGED_MD_FILES" | wc -l | tr -d ' ')" >> "$GITHUB_OUTPUT"
Expand All @@ -71,14 +81,15 @@ jobs:
echo "EOF"
} >> "$GITHUB_OUTPUT"

- uses: anthropics/claude-code-action@v1
if: steps.changed-files.outputs.count > 0
# Review mode: auto-triggered when markdown files change in a PR
- name: Run documentation review
uses: anthropics/claude-code-action@v1
if: github.event_name == 'pull_request_target' && steps.changed-files.outputs.count > 0
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
show_full_output: true
use_sticky_comment: true

prompt: |
Review ONLY the following markdown files that were changed in this PR: ${{ steps.changed-files.outputs.files }}

Expand All @@ -92,3 +103,16 @@ jobs:
--model claude-sonnet-4-5-20250929
--allowedTools "Bash(gh pr diff:*),Bash(gh pr view:*)"
--append-system-prompt "${{ steps.read-prompt.outputs.prompt }}"

# Fix mode: triggered when someone comments @claude on a PR
- name: Apply fixes on @claude request
uses: anthropics/claude-code-action@v1
if: github.event_name == 'issue_comment'
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
show_full_output: true
claude_args: |
--model claude-sonnet-4-5-20250929
--allowedTools "Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(git config:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*)"
--append-system-prompt "${{ steps.read-prompt.outputs.prompt }}"