Claude Code Review workflow (ClickHouse/clickhouse-go)
The Claude Code Review workflow from ClickHouse/clickhouse-go, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Claude Code Review workflow from the ClickHouse/clickhouse-go repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Claude Code Review
on:
pull_request_target:
types: [labeled]
workflow_dispatch:
inputs:
pr_number:
description: "PR number to review"
required: true
type: string
jobs:
review:
# Only run when the exact trigger label is applied (skip for manual dispatch).
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.label.name == 'review:claude-agent'
runs-on: ubuntu-latest
permissions:
# resolving review threads needs contents:write, oddly enough:
# https://github.com/orgs/community/discussions/44650
# Safe here: we only check out the base branch, and only on a maintainer label.
contents: write
pull-requests: write # post review comments
issues: write # update labels / post issue comments
id-token: write # OIDC token for claude-code-action auth
steps:
- name: Checkout base branch
uses: actions/checkout@v4
# SECURITY: pull_request_target checks out the base branch by default.
# Do NOT add `ref: ${{ github.event.pull_request.head.sha }}` here -
# that would run untrusted fork code with access to repository secrets.
# that's why labeling check (usually by maintainer)
# Dump the bot's existing review threads (prior comments + author replies +
# resolved/outdated state) so the review step can decide, per open thread,
# whether to reply, resolve, or leave it alone. Empty on a first review.
- name: Fetch existing review threads
env:
GH_TOKEN: ${{ github.token }}
run: |
python3 .claude/skills/review-pr/post_review.py fetch \
--repo "${{ github.repository }}" \
--pr "${{ github.event.inputs.pr_number || github.event.pull_request.number }}" \
> existing-threads.json || echo '{"threads":[]}' > existing-threads.json
- name: Review PR with Claude (produce findings JSON)
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ github.token }}
claude_args:
--allowedTools "Read,Glob,Grep,Bash(grep:*),Bash(gh pr view:*),Bash(gh pr diff:*),Write"
prompt: |
Review pull request #${{ github.event.inputs.pr_number || github.event.pull_request.number }} by following `.claude/skills/review-pr/SKILL.md` exactly.
First Read `.claude/skills/review-pr/review-core.md` (the review criteria) and
`.claude/skills/review-pr/SKILL.md` (the workflow steps and findings JSON schema).
`existing-threads.json` is already present in the working directory. Write your findings
to `claude-review.json` in the repo root, matching the schema in SKILL.md. Do NOT post
any comments yourself - a separate workflow step posts the JSON.
# Deterministic posting: inline line-anchored comments, threaded replies,
# resolution of addressed/outdated threads, and one summary comment updated
# in place (idempotent, so re-runs do not duplicate). Runs even if the
# review step produced no JSON (the script is skipped in that case).
- name: Post review comments
if: always()
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ -f claude-review.json ]; then
python3 .claude/skills/review-pr/post_review.py post \
--repo "${{ github.repository }}" \
--pr "${{ github.event.inputs.pr_number || github.event.pull_request.number }}" \
--input claude-review.json
else
echo "No claude-review.json produced; nothing to post."
fi
- name: Remove trigger label
if: always() && github.event_name != 'workflow_dispatch'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
--method DELETE \
repos/${{ github.repository }}/issues/${{ github.event.inputs.pr_number || github.event.pull_request.number }}/labels/review%3Aclaude-agent \
|| true # ignore 404 if label was already removed
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Claude Code Review on: pull_request_target: types: [labeled] workflow_dispatch: inputs: pr_number: description: "PR number to review" required: true type: string jobs: review: timeout-minutes: 30 # Only run when the exact trigger label is applied (skip for manual dispatch). if: >- github.event_name == 'workflow_dispatch' || github.event.label.name == 'review:claude-agent' runs-on: latchkey-small permissions: # resolving review threads needs contents:write, oddly enough: # https://github.com/orgs/community/discussions/44650 # Safe here: we only check out the base branch, and only on a maintainer label. contents: write pull-requests: write # post review comments issues: write # update labels / post issue comments id-token: write # OIDC token for claude-code-action auth steps: - name: Checkout base branch uses: actions/checkout@v4 # SECURITY: pull_request_target checks out the base branch by default. # Do NOT add `ref: ${{ github.event.pull_request.head.sha }}` here - # that would run untrusted fork code with access to repository secrets. # that's why labeling check (usually by maintainer) # Dump the bot's existing review threads (prior comments + author replies + # resolved/outdated state) so the review step can decide, per open thread, # whether to reply, resolve, or leave it alone. Empty on a first review. - name: Fetch existing review threads env: GH_TOKEN: ${{ github.token }} run: | python3 .claude/skills/review-pr/post_review.py fetch \ --repo "${{ github.repository }}" \ --pr "${{ github.event.inputs.pr_number || github.event.pull_request.number }}" \ > existing-threads.json || echo '{"threads":[]}' > existing-threads.json - name: Review PR with Claude (produce findings JSON) uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} github_token: ${{ github.token }} claude_args: --allowedTools "Read,Glob,Grep,Bash(grep:*),Bash(gh pr view:*),Bash(gh pr diff:*),Write" prompt: | Review pull request #${{ github.event.inputs.pr_number || github.event.pull_request.number }} by following `.claude/skills/review-pr/SKILL.md` exactly. First Read `.claude/skills/review-pr/review-core.md` (the review criteria) and `.claude/skills/review-pr/SKILL.md` (the workflow steps and findings JSON schema). `existing-threads.json` is already present in the working directory. Write your findings to `claude-review.json` in the repo root, matching the schema in SKILL.md. Do NOT post any comments yourself - a separate workflow step posts the JSON. # Deterministic posting: inline line-anchored comments, threaded replies, # resolution of addressed/outdated threads, and one summary comment updated # in place (idempotent, so re-runs do not duplicate). Runs even if the # review step produced no JSON (the script is skipped in that case). - name: Post review comments if: always() env: GH_TOKEN: ${{ github.token }} run: | if [ -f claude-review.json ]; then python3 .claude/skills/review-pr/post_review.py post \ --repo "${{ github.repository }}" \ --pr "${{ github.event.inputs.pr_number || github.event.pull_request.number }}" \ --input claude-review.json else echo "No claude-review.json produced; nothing to post." fi - name: Remove trigger label if: always() && github.event_name != 'workflow_dispatch' env: GH_TOKEN: ${{ github.token }} run: | gh api \ --method DELETE \ repos/${{ github.repository }}/issues/${{ github.event.inputs.pr_number || github.event.pull_request.number }}/labels/review%3Aclaude-agent \ || true # ignore 404 if label was already removed
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
1 third-party action is referenced by a movable tag. Pin it to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.