中文文档 | English
An AI-powered automatic code review tool for Gitea / Forgejo / GitHub PRs, built on the OpenCode plugin system. Supports two runtime modes:
suggestion code blocksapprove, request_changes, or comment based on severity[BUG:HIGH], [SECURITY:CRITICAL], etc.sha256= prefixmarkdown_v2 formatted review summaries to WeCom group bots*.go,src/**/*.ts).opencode-review/ directory, no conflict with existing .opencode/ setupslinux/amd64 + linux/arm64), ready to use┌─────────────────────────────────────────────────────────────────────┐ │ Trigger Methods │ │ ┌──────────────────┐ ┌──────────────────────────────────────┐ │ │ │ Gitea Actions │ │ Gitea / GitHub Webhook POST │ │ │ │ (bundled) │ │ (pull_request / issue_comment / │ │ │ │ │ │ pull_request_review_comment) │ │ │ └────────┬─────────┘ └──────────────┬───────────────────────┘ │ └───────────┼─────────────────────────────┼──────────────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌────────────────────────┐ │ entrypoint.sh │ │ Go Webhook Server │ │ review command │ │ ┌──────────────────┐ │ │ │ │ │ Signature verify │ │ │ 1. TLS config │ │ │ + Dedup │ │ │ 2. Provider det.│ │ └───────┬──────────┘ │ │ 3. Build prompt │ │ ┌───────▼──────────┐ │ │ 4. opencode run │ │ │ Worker Pool │ │ └────────┬─────────┘ │ │ (queue+concurrency)│ │ │ │ └───────┬──────────┘ │ │ └──────────┼──────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────┐ │ OpenCode CLI + Plugin System │ │ ┌────────────┐ ┌───────────────────────────┐ │ │ │code-review │ │ Tools │ │ │ │Agent │ │ • gitea-pr-diff │ │ │ │ │ │ • gitea-incremental-diff │ │ │ │ (AI review │ │ • gitea-pr-files │ │ │ │ strategy │ │ • gitea-review │ │ │ │ + decision│ │ • gitea-comment │ │ │ │ logic) │ │ • provider (API adapter) │ │ │ └─────┬──────┘ │ • diff-utils │ │ │ │ └───────────┬───────────────┘ │ └────────┼─────────────────────┼───────────────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌──────────────────────┐ │ Provider API │ │ WeCom Group Bot │ │ Gitea / GitHub │ │ (markdown_v2 notify) │ │ Submit Review │ └──────────────────────┘ │ Line Comments │ └─────────────────┘
Run in your project root:
curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash
The script guides you through choosing an installation method and auto-installs the review workflow to .gitea/workflows/ for Gitea Actions.
# Docker-based — adds only 1 workflow file
curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --docker
# Source-based — adds full .opencode-review/ directory + workflow
curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --source
# Both methods
curl -fsSL https://cnb.cool/zishuo/opencode-review-gitea/-/git/raw/main/install.sh | bash -s -- --both
| Aspect | Docker | Source |
|---|---|---|
| Files added | 1 workflow file | .opencode-review/ + workflow |
| CI speed | Fast (pre-built cached image) | Slower (installs deps each run) |
| Customization | Environment variables only | Full control over Agents, Tools, Skills |
| Updates | Pull :latest image | Manual sync of .opencode-review/ |
| Best for | Quick setup, standard use | Custom review strategies, power users |
Configure in repository Secrets (Actions mode) or container environment variables (Webhook/Local mode):
| Variable | Description | Example |
|---|---|---|
API_ENDPOINT | OpenAI-compatible model gateway base URL | https://your-gateway.example.com/v1 |
API_TOKEN | Model gateway API token | sk-xxxxx |
GITEA_TOKEN | Gitea / Forgejo API token (with repo scope) | gitea_xxxxx |
GITHUB_TOKEN | GitHub / GHES Personal Access Token | ghp_xxxxx |
OPENCODE_GIT_TOKEN | Token for actions/checkout in Gitea Actions runtime | — |
Webhook mode additionally requires
WEBHOOK_SECRET. See Webhook Server Configuration.
Specify the model via the MODEL environment variable in provider/model-id format:
env:
MODEL: openai/glm-5.0 # default
# MODEL: openai/gpt-5.4
# MODEL: openai/claude-4.5
# MODEL: openai/deepseek-v3.1
# MODEL: openai/gemini-2.5-pro
The opencode.json pre-defines 20+ models (GPT-5.x, Claude 4.5/4.6, Gemini, DeepSeek, GLM, MiniMax, Kimi, Hunyuan, etc.) with cost set to 0 (billing via custom gateway). You can add new model definitions in opencode.json.
| Variable | Default | Description |
|---|---|---|
REVIEW_LANGUAGE | auto | Review response language: auto (detect from code) / en / zh-CN |
REVIEW_STYLE | balanced | Review depth: concise / balanced / thorough / security |
FILE_PATTERNS | (empty) | File filter (glob patterns, comma-separated), e.g., *.go,src/**/*.ts |
File filtering examples:
# Only review TypeScript files
FILE_PATTERNS: "*.ts,*.tsx"
# Only review Go files under src/
FILE_PATTERNS: "src/**/*.go"
# Mixed patterns
FILE_PATTERNS: "*.py,*.js"
Note: Only positive matching is supported. Negation patterns with
!are not available.
| Variable | Default | Description |
|---|---|---|
WEBHOOK_LISTEN_ADDR | :8080 | HTTP listen address |
WEBHOOK_PATH | /webhook | Webhook endpoint path |
WEBHOOK_QUEUE_SIZE | 64 | Async queue buffer size |
WEBHOOK_MAX_CONCURRENT | 2 | Maximum concurrent review workers |
WEBHOOK_REVIEW_TIMEOUT | 30m | Per-review timeout (Go duration format) |
WEBHOOK_MAX_BODY_BYTES | 2MB | Maximum request body size |
WEBHOOK_ENTRYPOINT | /entrypoint.sh | Review execution entrypoint script path |
WEBHOOK_WORK_ROOT | /tmp/opencode-review/jobs | Temporary working directory for clones |
WEBHOOK_COMMENT_COMMANDS | /oc,/opencode | Comment commands that trigger review (comma-separated) |
WEBHOOK_PULL_REQUEST_ACTIONS | opened,reopened,synchronize,ready_for_review | PR action whitelist for auto-trigger |
WEBHOOK_POST_FAILURE_COMMENT | true | Post a PR comment when review fails |
WEBHOOK_CLEANUP_WORKTREE | true | Clean up temporary worktrees after review |
WEBHOOK_ALLOW_INSECURE | false | Allow webhook requests without signature (dev only) |
Webhook Secret (by priority):
| Variable | Description |
|---|---|
GITEA_WEBHOOK_SECRET | Gitea-specific secret (overrides shared) |
GITHUB_WEBHOOK_SECRET | GitHub-specific secret (overrides shared) |
WEBHOOK_SECRET | Shared secret for both providers |
TLS certificate verification is skipped by default for self-signed certificates in internal networks. Set any of the following to false to enforce strict validation:
SKIP_TLS_VERIFYWEBHOOK_SKIP_TLS_VERIFYREVIEW_SKIP_TLS_VERIFYGIT_SSL_NO_VERIFY| Variable | Description |
|---|---|
WECOM_BOT_WEBHOOK_URL | WeCom group bot webhook URL |
WECOM_WEBHOOK_URL | Alias (equivalent, lower priority) |
Notification content includes: repository name, submitter, PR link, review verdict with a short hint, optional PR summary, feedback overview (comment count / suggestion count), model used, duration, and result link.
| Scenario | Recommended Mode | Notes |
|---|---|---|
| Gitea / Forgejo, quickest setup inside the repo | Actions Mode | The bundled installer writes .gitea/workflows/opencode-review.yaml automatically |
| Gitea / Forgejo, centralized service across multiple repos | Webhook Mode | Better if you want one long-running service and unified notifications |
| GitHub / GHES, automated reviews with the shipped setup | Webhook Mode | This is the documented default for GitHub because the server natively handles GitHub webhook headers, API base URLs, and PR review submission |
| GitHub / GHES, Actions-based execution | Manual adaptation required | The shipped workflow templates are Gitea-oriented and must be adjusted before use in GitHub Actions |
After installation, creating or updating a PR automatically triggers review (if the workflow is configured for those events). You can also manually trigger via comment:
/oc
Or with custom instructions:
/opencode please focus on concurrency safety issues
Custom instructions after the command are extracted and passed to the AI review agent.
The bundled installer currently provisions a Gitea Actions workflow. For GitHub / GHES, prefer Webhook Mode unless you plan to adapt the workflow templates manually, because the shipped templates reference Gitea runtime variables.
Webhook Mode is the recommended automation path for GitHub / GHES today, and it also works well for Gitea / Forgejo when you want a centralized review service instead of per-repo workflows.
Start the webhook server:
docker run --rm -p 8080:8080 \
-e GITEA_TOKEN="your-gitea-token" \
-e GITHUB_TOKEN="your-github-token" \
-e WEBHOOK_SECRET="your-webhook-secret" \
-e API_ENDPOINT="https://your-llm-gateway.example.com/v1" \
-e API_TOKEN="your-api-token" \
-e MODEL="openai/glm-5.0" \
-e WECOM_BOT_WEBHOOK_URL="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx" \
-e WEBHOOK_PATH="/webhook" \
docker.cnb.cool/zishuo/opencode-review-gitea:latest webhook
Then configure in your Gitea / GitHub repository webhook settings:
http://your-server:8080/webhookapplication/jsonWEBHOOK_SECRETBy default,
pull_requestevents with actionsopened/reopened/synchronize/ready_for_reviewauto-trigger reviews. You can also trigger via PR comments/ocor/opencode.
Docker single review:
docker run --rm \
-v $(pwd):/workspace \
-e GITEA_TOKEN="your-token" \
-e GITEA_SERVER_URL="https://your-gitea.example.com" \
-e API_ENDPOINT="https://your-llm-gateway.example.com/v1" \
-e API_TOKEN="your-api-token" \
-e MODEL="openai/glm-5.0" \
-e PR_NUMBER=123 \
-e REPO_OWNER="your-org" \
-e REPO_NAME="your-repo" \
docker.cnb.cool/zishuo/opencode-review-gitea:latest
REPO_NAMEaccepts bothrepoandowner/repoformats — the entrypoint normalizes it automatically.
Docker Compose:
# Single review
docker compose run review
# Webhook server
docker compose up webhook
# Interactive shell
docker compose run dev
Source-based:
export GITEA_TOKEN="your-token"
export GITEA_SERVER_URL="https://your-gitea.example.com"
export API_ENDPOINT="https://your-llm-gateway.example.com/v1"
export API_TOKEN="your-api-token"
export MODEL="openai/glm-5.0"
export OPENCODE_CONFIG_DIR="$(pwd)/.opencode-review"
opencode run --agent code-review \
"Please review PR #123 in owner/repo"
For GitHub / GHES, replace GITEA_TOKEN with GITHUB_TOKEN and optionally set GITHUB_SERVER_URL (defaults to https://github.com).
| Method | Path | Description |
|---|---|---|
GET | / | HTML guide page (runtime status + configuration) |
GET | /healthz | Health check (returns {"status":"ok","queue":N}) |
GET | ${WEBHOOK_PATH} | HTML guide page (same as /) |
POST | ${WEBHOOK_PATH} | Webhook event receiver |
The webhook server only processes the following events:
| Event Type | Trigger Condition |
|---|---|
pull_request | Action is in the whitelist (default: opened,reopened,synchronize,ready_for_review) |
issue_comment | Comment body matches a trigger command (default: /oc or /opencode) |
pull_request_review_comment | Comment body matches a trigger command |
Non-matching events return 202 Accepted + {"status":"ignored"}.
| Provider | Event Header | Delivery Header | Signature Header |
|---|---|---|---|
| Gitea / Forgejo | X-Gitea-Event | X-Gitea-Delivery | X-Gitea-Signature |
| GitHub / GHES | X-GitHub-Event | X-GitHub-Delivery | X-Hub-Signature-256 |
Signature verification uses HMAC-SHA256 and is compatible with the sha256= prefix. To skip verification (development only), set WEBHOOK_ALLOW_INSECURE=true.
Successfully queued (202 Accepted):
{
"status": "queued",
"delivery": "uuid-delivery-id",
"provider": "gitea",
"repository": "owner/repo",
"pull": 42,
"trigger": "pull_request/opened"
}
Duplicate delivery (202 Accepted):
{
"status": "ignored",
"reason": "duplicate delivery",
"delivery": "uuid-delivery-id"
}
Signature error — 401 Unauthorized
Queue full — 503 Service Unavailable
code-review agentThe review agent's tool selection strategy:
FILE_PATTERNS filter → uses gitea-pr-diff (filtered diff retrieval)gitea-incremental-diff (incremental review, new changes only)gitea-pr-filesDecision matrix:
CRITICAL or HIGH severity issues found → request_changescommentapproveEdit .opencode-review/agents/code-review.md — the main review agent definition (413 lines of detailed prompt covering review discipline, priority rules, tool strategy, decision matrix, and 6 few-shot examples).
Key configuration is in the frontmatter:
---
description: AI code reviewer for Gitea/Forgejo PRs
tools:
"*": false
"gitea-review": true
"gitea-pr-diff": true
"gitea-incremental-diff": true
"gitea-pr-files": true
"gitea-comment": true
---
You can modify the review focus, language style, severity thresholds, and more.
Create a TypeScript file in .opencode-review/tools/:
import { tool } from "@opencode-ai/plugin";
export default tool({
description: "Tool description",
args: {
param: tool.schema.string().describe("Parameter description"),
},
async execute(args, context) {
return "Result";
},
});
Create a matching .txt file for the tool description (helps the agent understand the tool's purpose), then enable it in the agent's frontmatter:
tools:
"your-tool-name": true
Tools can use getProviderConfig() from provider.ts to auto-detect the current provider and call providerFetch() / providerFetchJson() for unified API interactions with Gitea/GitHub.
. ├── Dockerfile # Two-stage build: Go compile + Bun runtime ├── docker-compose.yaml # Local testing (review / webhook / dev) ├── entrypoint.sh # Container entrypoint (review / webhook / shell commands) ├── install.sh # Interactive installation script ├── .cnb.yml # CNB CI config for the primary docker.cnb.cool image pipeline ├── .github/ │ └── workflows/ │ └── docker-publish.yaml # GitHub Actions: publish the same image to docker.cnb.cool using CNB credentials ├── .gitea/ │ └── workflows/ │ └── opencode-review.yaml # Gitea Actions: source-based review workflow ├── templates/ │ ├── workflow-docker.yaml # Docker-based workflow template │ └── workflow-source.yaml # Source-based workflow template ├── backend/ # Go backend (Webhook Server) │ ├── go.mod # Module: cnb.cool/zishuo/opencode-review-gitea │ ├── cmd/webhook-server/ │ │ └── main.go # HTTP server entry + Worker Pool + deduplication │ └── internal/ │ ├── config/ │ │ └── config.go # Env var loading (all config definitions) │ ├── webhook/ │ │ ├── model.go # Provider / ReviewRequest types │ │ ├── verify.go # Provider detection + HMAC-SHA256 signature verification │ │ └── parse.go # Event parsing + filtering + comment command matching │ ├── review/ │ │ ├── runner.go # Review executor (clone + opencode + notification) │ │ └── notifier.go # WeCom markdown_v2 notification sender │ └── webui/ │ ├── guide.go # Go embed guide page renderer │ └── guide.html # Embedded HTML guide page ├── docs/ # Reference documentation │ ├── webhook-review-service.md # Webhook deployment deep-dive │ ├── gitea-webhooks-reference.md # Gitea Webhook API reference │ ├── github-webhooks-reference.md # GitHub Webhook API reference │ ├── wecom-group-bot-webhook.md # WeCom group bot API reference │ ├── opencode-sdk-reference.md # OpenCode SDK reference │ └── gitea-plugin-redoc-2.yaml # Gitea API 1.25.5 OpenAPI spec └── .opencode-review/ # OpenCode plugin (isolated config directory) ├── opencode.json # Model definitions / Provider / permissions config ├── package.json # Dependency: @opencode-ai/plugin ├── agents/ │ ├── code-review.md # Main review agent (prompt + strategy + few-shots) │ └── gitea-assistant.md # General assistant agent ├── tools/ │ ├── provider.ts # Provider abstraction (API adapter / line mapping) │ ├── diff-utils.ts # Diff parsing / formatting / file filtering │ ├── gitea-review.ts # Submit review (line comments + suggestions) │ ├── gitea-pr-diff.ts # Fetch full PR diff │ ├── gitea-incremental-diff.ts # Fetch incremental diff (new change detection) │ ├── gitea-pr-files.ts # List changed files │ ├── gitea-comment.ts # Post issue/PR comments │ └── *.txt # Tool description files ├── skills/ │ └── pr-review/SKILL.md # Reusable PR review skill └── tests/ # Bun unit tests ├── gitea-incremental-diff.test.ts ├── gitea-pr-diff.test.ts ├── gitea-review-stats.test.ts └── gitea-review-tags.test.ts
| Component | Technology |
|---|---|
| Runtime image | oven/bun:1-alpine |
| Go backend | Go 1.26, go-git/v5 (only direct dependency) |
| Plugin system | OpenCode Plugin SDK (@opencode-ai/plugin) |
| Test frameworks | Bun Test (plugin), Go testing (backend) |
| CI/CD | CNB Build (primary multi-arch publish path for docker.cnb.cool), GitHub Actions (alternate CNB publish path for GitHub-hosted automation) |
The published image referenced throughout this README is docker.cnb.cool/zishuo/opencode-review-gitea. Both the CNB pipeline and the GitHub Actions publish workflow now target the same CNB registry image; the GitHub workflow requires CNB_TOKEN_USER_NAME and CNB_TOKEN secrets.
# Start interactive dev environment
docker compose run dev
# Run Go backend tests
cd backend && go test ./...
# Run plugin tests
cd .opencode-review && bun test
docker build -t opencode-review-gitea:latest .
MIT License - See LICENSE