name: Review PR # /review triggers this workflow. The first word after the trigger picks a # model alias from .github/bonk-models.json. Currently registered aliases # (see that file for the source of truth): # # /review -> default model (currently opus) # /review opus -> Claude Opus 4.7 (default) # /review kimi -> Kimi K2.7 Code (cheap pass for tiny PRs) # # Add new aliases by editing .github/bonk-models.json. on: issue_comment: types: [created] pull_request_review_comment: types: [created] # Concurrency is at job level (below) rather than workflow level so it's only # evaluated when the `if:` filter passes. jobs: review: # mentions in this check must match the `mentions` input below. # For issue_comment events, require the comment to be on a PR (not an issue). if: >- github.event.sender.type != 'Bot' && contains(github.event.comment.body, '/review') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) && (github.event_name != 'issue_comment' || github.event.issue.pull_request != null) # Per-workflow group key so /review and /bonk have independent queues # per target. concurrency: group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.ref }} cancel-in-progress: false runs-on: ubuntu-latest timeout-minutes: 30 permissions: id-token: write contents: read issues: write pull-requests: write steps: - name: Get PR number id: pr-number env: # issue_comment on a PR exposes the number via github.event.issue.number; # pull_request_review_comment exposes it via github.event.pull_request.number. PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} run: | echo "number=${PR_NUMBER}" >> "$GITHUB_OUTPUT" - name: Verify PR exists id: verify-pr env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ steps.pr-number.outputs.number }} run: | if gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" > /dev/null 2>&1; then echo "exists=true" >> "$GITHUB_OUTPUT" else echo "exists=false" >> "$GITHUB_OUTPUT" echo "::warning::PR #${PR_NUMBER} not found, skipping review" fi - name: Checkout repository if: steps.verify-pr.outputs.exists == 'true' uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 1 persist-credentials: false - name: Resolve model from comment if: steps.verify-pr.outputs.exists == 'true' id: model env: BODY: ${{ github.event.comment.body }} run: node .github/scripts/resolve-bonk-model.mjs - name: Setup pnpm if: steps.verify-pr.outputs.exists == 'true' uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - name: Setup Node.js if: steps.verify-pr.outputs.exists == 'true' uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version-file: "package.json" cache: "pnpm" - name: Install dependencies if: steps.verify-pr.outputs.exists == 'true' run: pnpm install --frozen-lockfile - name: Get PR details if: steps.verify-pr.outputs.exists == 'true' id: pr-details run: | gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" > /tmp/pr_data.json # Use heredoc form for every field — PR titles and bodies can contain # newlines that would otherwise corrupt $GITHUB_OUTPUT and let a PR # author smuggle arbitrary step outputs via their title/body. { echo 'title<> "$GITHUB_OUTPUT" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ steps.pr-number.outputs.number }} - name: Run Review (${{ steps.model.outputs.alias }}) if: steps.verify-pr.outputs.exists == 'true' uses: ask-bonk/ask-bonk/github@bfd92f4d0abb62d98558b35432534f7b9992f3eb # main as of 2026-04-24 env: CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }} CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }} CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }} OPENCODE_CONFIG_CONTENT: ${{ steps.model.outputs.opencode_config }} with: model: ${{ steps.model.outputs.model }} mentions: "/review" opencode_version: "1.4.11" permissions: write # NO_PUSH scopes the installation token to contents:read so the # reviewer cannot push, even if it tries to commit. Write tools # remain enabled in the agent definition so it can scaffold fixes # locally to verify reasoning. token_permissions: NO_PUSH # Custom agent defined in .opencode/agents/auto-reviewer.md. # Holds the review philosophy, investigation protocol, and posting # protocol so workflows stay small. agent: auto-reviewer prompt: | Review pull request #${{ steps.pr-number.outputs.number }} ("${{ steps.pr-details.outputs.title }}"). Follow your agent instructions for investigation, severity calibration, and posting. Post a single review with line-anchored comments via the gh CLI; the summary will be posted as a separate workflow comment. ${{ steps.pr-number.outputs.number }} ${{ steps.pr-details.outputs.body }} If the PR looks good, respond with only "LGTM!" and skip posting a review.