opencode-code-review.yml
Read-only OpenCode PR code review, run through the opencode CLI headless. The agent receives the PR diff as an attachment and may read the checked-out repository for context; it runs with file edits, shell commands, and web fetches denied, so the workflow itself posts whatever review the model produces.
The default caller stub is workflow_dispatch-triggered. Add a pull_request trigger in the caller if you want automatic reviews on PR updates. There is no opencode.yml mention bot yet, so unlike gemini-code-review.yml there is no comment-triggered re-dispatch path to keep names in sync with.
Requires an OPENCODE_API_KEY secret (OpenCode Zen; free-tier models are available). Without it, each run posts a skip notice on the PR instead of a review.
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
pr-number |
string | '' |
Pull request number to review. Required on workflow_dispatch; taken from the event on pull_request. |
prompt-addendum |
string | '' |
Extra prompt instructions appended to the review prompt. |
checkout-submodules |
boolean | false |
Check out git submodules. |
opencode-model |
string | 'opencode/big-pickle' |
Model passed to opencode run -m. |
opencode-version |
string | '1.18.21' |
opencode CLI release installed at run time. |
opencode-attempts |
string | '3' |
Total run attempts per review (1-5). A failed attempt is retried only when its output carries the transient Zen stream-drop signature (finish_reason: network_error, gha#600); auth, quota, and other failures are never retried. |
Secrets
| Secret | Required | Description |
|---|---|---|
OPENCODE_API_KEY |
no | OpenCode Zen API key. Without it the workflow skips gracefully with a warning comment on the PR. |
SUBMODULES_TOKEN |
no | Token used to check out private submodules. |
Permissions
Grant contents: read, pull-requests: write, and issues: write. No id-token: write is needed: the agent is invoked directly rather than through an action that exchanges an OIDC token.
What it refuses to review
The automatic pull_request path skips draft PRs, PRs from forks, and PRs opened by a bot, using the event payload.
A workflow_dispatch run carries none of that payload, only pr-number, so it re-checks the same two conditions over the API and skips a fork or Dependabot PR. A lookup that fails outright (rate limit, a bad pr-number) also skips, and fails the run rather than reviewing a PR whose provenance it could not establish.
Only one review runs per PR at a time: a newer run cancels an older one, so a verdict on a superseded commit cannot land after the current one.
Untrusted-repository hardening
A pull request’s tree is attacker-controlled input, so before the CLI starts the workflow deletes any project-level opencode configuration files from the checkout (opencode.json, opencode.jsonc, .opencode/config.json, .opencode/opencode.json). Without that, a PR could carry its own config overriding the deny rules this workflow relies on and re-enabling shell or edit permissions for the reviewer.
The remaining surface is instruction-file injection (a PR editing AGENTS.md), which every AI reviewer here shares: the agent reads repo files, so a malicious diff can try to steer its prose. Reviews are read-only and the verdict contract is stated after any repository-controlled content, which bounds what such an attempt can achieve.
Failure reporting
The workflow classifies each run’s outcome into two kinds:
- review — the agent exited 0 with non-empty output, posted as a comment.
- failed — anything else (non-zero exit, empty output). The failure comment always begins
OpenCode review failed:and includes the raw CLI stderr for triage.
A missing API key skips with an OpenCode review skipped notice instead.
Concurrency
Do not declare a top-level concurrency: block in your caller workflow. opencode-code-review.yml manages per-PR concurrency internally on its review job (group: opencode-review-<PR>). Adding a top-level concurrency: block in the caller with a PR-scoped group name causes GitHub Actions to detect a deadlock between the top-level workflow and the nested job, cancelling the run immediately (gha#437).
Example
# Copy to .github/workflows/opencode-code-review.yml in your repo.
name: OpenCode Review
on:
# Optional: automatic review on PR activity.
# pull_request:
# types: [opened, synchronize, ready_for_review, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'Pull request number to review'
required: true
type: string
jobs:
review:
permissions:
contents: read
pull-requests: write
issues: write
uses: Morrison-Lab/gha/.github/workflows/opencode-code-review.yml@v2
secrets:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
with:
pr-number: ${{ inputs.pr_number }}
# with:
# checkout-submodules: true
# opencode-model: opencode/big-pickle
# opencode-attempts: '3'
# prompt-addendum: |
# Repo-specific review guidance.See the examples/ directory for the full caller stub (opencode-code-review.yml).