AI Code Review (scripts/ai-review)
Automated PR review that posts a single consolidated comment on every pull request. Driven by
.github/workflows/ai-code-review.yml → run-review.mjs, using DeepSeek-V4-Pro via opencode.
The posted comment is branded OpenObserve Code Reviewer. Branding is cosmetic + identity only — it does not change what the reviewer finds or decides.
How it works (one paragraph)
On each PR the workflow fetches the diff, filters noise, picks a risk tier (trivial / lite /
full), runs the tier's read-only specialist agents (security, code-quality, performance,
documentation, release) in parallel — plus any conditional agent whose domain the diff touches —
and a coordinator consolidates their findings into one comment with an approve/needs-work
decision. The comment PATCHes itself in place on re-review. Full engine details live in the code;
the rest of this README covers setup, activation, and rollback of the branded identity.
The Frontend UI Reviewer
frontend is the one conditional agent: it is appended to whatever the tier selected whenever
the diff touches web/src (excluding specs), so a 6-line UI change still gets reviewed even at the
trivial tier. requiresFocus: true is the other half of that contract — the generic focus filter
falls back to the full diff when an agent matches no files, which would otherwise have the
frontend reviewer opining on Rust; with the flag set it skips the PR entirely instead.
Its remit is deliberately narrow: only the half of .claude/skills/ui-architect/ that no lint
rule or check script can see — structure (OPageHeader/OPageLayout/OTable vs hand-rolled
markup), cross-file consistency (a sortable column vs the Rust handler's sort keys; route ↔ nav
entry ↔ rail gate agreement; a token in :root but not dark.css), values that are well-formed
but wrong (text-[0.8125rem], a parseInt-read px converted to rem), and i18n semantics
(raw() on real copy, a catalogue key for Kafka). Everything local/no-hardcoded-px,
lint:design:strict, stylelint or type-check:app already fails the build on is explicitly
out of scope — see the "What NOT to Flag" table in agents/frontend.md.
Adding another conditional agent: define it in AGENTS (with requiresFocus if it is
domain-scoped), add a { agent, matches } entry to CONDITIONAL_AGENTS, register
ai-review-<key> in opencode.jsonc with the same read-only tool policy, and add its glyph to
CATEGORY_GLYPH and to agents/coordinator.md.
Identity: how the comment gets its author
The comment is posted with whatever token run-review.mjs sees as GH_TOKEN:
- Branded — a GitHub App installation token (comment authored by OpenObserve Code Reviewer with its avatar).
- Fallback —
github.token(comment authored bygithub-actions[bot]).
The workflow mints the App token via actions/create-github-app-token, gated on the
OO_REVIEWER_APP_ID repo/org variable:
- id: app_token
if: ${{ steps.skip.outputs.skip_review == 'false' && vars.OO_REVIEWER_APP_ID != '' }}
continue-on-error: true # never breaks CI if minting fails
uses: actions/create-github-app-token@<pinned-sha> # v2.2.2
with:
app-id: ${{ vars.OO_REVIEWER_APP_ID }}
private-key: ${{ secrets.OO_REVIEWER_APP_PRIVATE_KEY }}
# ...
env:
GH_TOKEN: ${{ steps.app_token.outputs.token || github.token }}
This is fail-safe at every stage:
| Situation | What happens |
|---|---|
| Variable unset | Token step skipped → posts as github-actions[bot] |
| Variable set, App not installed / key wrong | Mint fails, continue-on-error → empty token → || github.token → posts as github-actions[bot] |
| Variable set, App installed | Mint succeeds → posts as OpenObserve Code Reviewer |
Provisioning the GitHub App (one-time)
- Create a GitHub App (org-owned preferred; personal works but must be set to
Any account to install on org repos). Name:
OpenObserve Code Reviewer; upload the brand logo as the avatar; uncheck Webhook → Active (no server, no events). - Permissions (minimum): Pull requests Read & write, Contents Read-only, Metadata Read-only. Do NOT grant Contents write — the review agents are read-only by design and the token must not be write-capable.
- Install the App on
openobserveando2-enterprise. - Generate a private key (
.pem) and note the numeric App ID. - Set on both repos (or at org level), under Settings → Secrets and variables → Actions:
- Variable
OO_REVIEWER_APP_ID= the App ID (this is the on/off gate). - Secret
OO_REVIEWER_APP_PRIVATE_KEY= full contents of the.pem.
- Variable
Via CLI:
gh variable set OO_REVIEWER_APP_ID --body "<APP_ID>" --repo openobserve/openobserve
gh secret set OO_REVIEWER_APP_PRIVATE_KEY < <key.pem> --repo openobserve/openobserve
gh variable set OO_REVIEWER_APP_ID --body "<APP_ID>" --repo openobserve/o2-enterprise
gh secret set OO_REVIEWER_APP_PRIVATE_KEY < <key.pem> --repo openobserve/o2-enterprise
Rollback
Delete the OO_REVIEWER_APP_ID variable on the repo(s). The next review instantly reverts to
github-actions[bot]. No code change, no revert needed.
Skipping a review
Put any of these in the PR body or a comment: [skip ai review], [skip review], [skip ci],
or break glass.
Notes
actions/create-github-app-tokenis pinned to a full commit SHA (it receives the App's private key). Bump the pin deliberately after review — same discipline as theOPENCODE_VERSIONpin.- The App installation's granted permissions bound the token; keep the install at the minimum above so a mis-scoped install can't hand the reviewer a write-capable credential.
- OSS (
openobserve) and ENT (o2-enterprise) run identical engine files — keep them in sync.