AI code review that actually reads your repo.
The name comes from the Stephen Chow movie gag "凌空瞪" — a disembodied eyeball floating in mid-air, staring you down.
English · 简体中文 · Русский · Français · Deutsch · Español
HoverStare is an AI code review bot for GitHub pull requests, written in Rust and shipped as a single static binary that runs as a GitHub Action. Instead of tossing a diff at a model in one shot, its reviewer reads your repository like a human reviewer would — opening context files, grepping call sites, comparing against the base branch — before it says anything. A multi-pass vote plus an independent verifier keeps false positives down, and every finding it reports is tracked across commits until it's fixed.
- 🔍 Repo-aware, not diff-only. The reviewing model gets a read-only tool
set (
read_file/grep/glob/show_base_file) and uses it to verify suspicions before reporting. It catches bugs that hide outside the diff — like a changed function whose callers break two files away. - 🗳️ Multi-pass voting + verifier. Three independent review passes (correctness / concurrency / security lenses) vote on findings; lone-vote findings must survive an independent verifier pass with tool access. High signal, low noise.
- 📌 Precise inline comments. Line numbers are validated against the real diff and snapped to the nearest valid anchor, so comments land exactly where the bug is — never on the wrong line.
- 🔁 Incremental reviews. Push a fix and HoverStare reviews only the delta, marks fixed findings as resolved (or leaves a "✅ confirmed fixed" note), and never repeats itself.
- 🛡️ Fail-open by design. Network trouble, rate limits, or a flaky model will never block your CI.
- 🔑 BYOK. Bring your own key: Anthropic, or any OpenAI-compatible endpoint (Kimi, DeepSeek, OpenRouter, …). Code goes straight to your provider.
flowchart LR
A[PR opened / synchronized] --> B{skip?}
B -->|draft / bot / empty diff| Z((exit 0))
B --> C[fetch diff]
C --> D{prior review?}
D -->|yes| E[delta diff]
D -->|no| F[full diff]
E --> G
F --> G["N parallel review passes<br/>(read-only repo tools)"]
G --> H[cluster & vote]
H --> I[verifier pass]
I --> J[validate & anchor lines]
J --> K["post review<br/>+ resolve fixed threads<br/>+ status checks"]
Every inline comment carries a hidden fingerprint (path + code line + title
hash). On the next push, HoverStare diffs against its previous review, asks the
model which open findings are fixed, and resolves those threads — immune to
line-number drift.
1. Add the workflow — .github/workflows/hoverstare.yml:
name: HoverStare
on:
pull_request:
types: [opened, reopened, synchronize]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
permissions:
contents: read
pull-requests: write
statuses: write
concurrency:
# 不含 @hoverstare 的评论事件给独立组名,避免无意义的 run 取消正在跑的审查
group: >-
hoverstare-${{
(github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
&& !contains(github.event.comment.body, '@hoverstare')
&& format('noop-{0}', github.event.comment.id)
|| (github.event.pull_request.number || github.event.issue.number)
}}
cancel-in-progress: true
jobs:
hoverstare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: liuchong/hoverstare@v0.1.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.HOVERSTARE_LLM_KEY }}
OPENAI_BASE_URL: ${{ vars.HOVERSTARE_LLM_BASE_URL }}
HOVERSTARE_MODEL: ${{ vars.HOVERSTARE_MODEL }} # e.g. kimi-for-coding2. Configure LLM credentials (pick one):
| Provider | Settings |
|---|---|
| Anthropic | secret ANTHROPIC_API_KEY (default model claude-sonnet-4-6) |
| OpenAI-compatible (Kimi, DeepSeek, OpenRouter…) | secret OPENAI_API_KEY, var OPENAI_BASE_URL (e.g. https://api.kimi.com/coding/v1), and a model name via var HOVERSTARE_MODEL or model in .github/hoverstare.toml |
⚠️ With an OpenAI-compatible endpoint you must set the model name — the defaultclaude-sonnet-4-6won't exist there.
3. (Optional) Repo config — .github/hoverstare.toml, every field optional:
model = "kimi-for-coding" # main review model
reformat_model = "kimi-for-coding-highspeed" # cheap model for output repair
passes = 3 # parallel review passes; 1 disables voting
verify = true # verifier pass for single-vote findings
severity_threshold = "medium" # below this → Nitpicks section only
ignore = ["*.lock", "**/dist/**", "**/*.min.js"]
max_diff_kb = 400 # diff budget (truncated by priority)
max_tool_calls = 20 # agentic loop tool budget
timeout_secs = 900
review_drafts = false
fail_closed = false # true → analysis failures fail CI
status_checks = false # write hoverstare / hoverstare-findings checks
language = "en" # output language: en/zh-CN/ru/fr/de/es
set_temperature = true # false for endpoints that only accept default temperature
thinking = "enabled"
reasoning_effort = "medium"
context_tokens = 1000000
compaction = true
compaction_threshold_ratio = 0.75
compaction_keep_ratio = 0.25
summary_max_chars = 4000
max_rounds = 0
max_output_tokens = 0 # per-call output cap; 0 = derived from the window (window/16, min 4096, max 65536); reasoning tokens count
commit_identity = "coauthor" # develop commit identity: author (the trigger) / bot (hoverstare[bot]) / coauthor (trigger + Co-authored-by trailer); default coauthor
commit_author = "" # optional "Name <email>" override; empty uses <login>@users.noreply.github.com
instructions = "" # team-specific review focus, injected into the system promptHoverStare reads repo-level rule files and applies them to reviews (they supplement but never override the built-in core rules). Precedence:
hoverstare.md/.hoverstare.md/.hoverstare/*.md/.github/hoverstare.mdAGENTS.md.github/copilot-instructions.md,CLAUDE.md,.cursorrules
Files are read from the base branch (a PR editing AGENTS.md cannot inject instructions). Core safety rules (read-only tools, targeted verification, defect-only scope, JSON contract) can never be overridden.
By default, reviews post as github-actions[bot] — that's a GITHUB_TOKEN
limitation, and it's the recommended mode for most users (zero extra setup).
Want a branded bot identity? Register your own GitHub App (5 minutes, no server needed — token exchange happens inside GitHub Actions) and pass its credentials to the action:
- Create a GitHub App at Settings → Developer settings → GitHub Apps (webhook off; permissions: contents read, pull-requests write, issues write, commit statuses write), install it on your repo
- Add its App ID and private key as secrets
APP_ID/APP_PRIVATE_KEY - Pass them:
- uses: liuchong/hoverstare@v0.1.1
with:
app_id: ${{ secrets.APP_ID }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}Reviews then post as your-app-name[bot], and resolveReviewThread works
without the GITHUB_TOKEN limitation (no GH_PAT needed).
Zero-config
hoverstare[bot]identity for everyone is on the roadmap as an optional self-hostablehoverstare servewebhook service.
Post in a PR (repo collaborators only):
| Command | What it does |
|---|---|
@hoverstare review |
Force a full re-review |
@hoverstare explain |
Reply in the thread with a plain-language explanation of the finding |
| Reply in a finding thread | Discuss the finding with HoverStare in-thread — no @mention needed |
@hoverstare help |
Command list |
HoverStare can also develop — issues and PRs become a conversation-driven development environment (spec 11/12). Not automation glue that reacts to events: a place where you actually build the feature, end to end, in the open.
Issue mainline — file an issue mentioning @hoverstare:
- It investigates the repo and replies with an analysis + plan (in comments).
- Discuss by simply replying; each round is answered in the thread.
@hoverstare go— it creates a branch, implements, pushes, and opens a PR (withCloses #N).
PR mainline — on any same-repo PR:
@hoverstare <instruction>— it checks out the PR branch, develops, commits (Conventional Commits, authored ashoverstare[bot]), pushes back to the branch, and reports in a comment. Rounds that exhaust their budget self-continue (max 10 rounds per PR).- Humans can adjust by committing to the branch directly — the next round always syncs to the remote head first and never overwrites your commits.
@hoverstare merge— once checks are green and there are no conflicts, it squash-merges and deletes the source branch.
- Workflow: add the
issuesandpull_request_reviewtriggers and grantcontents: write+issues: write..github/workflows/hoverstare.ymlin this repo is a complete working example. - Tokens (two duties, two tokens):
- Identity (comments, reviews, opening PRs): the default
GITHUB_TOKEN, or a GitHub App token for thehoverstare[bot]identity. - Write operations (git push, merge, branch deletion): a PAT via the
gh_patinput, or an App withcontents: write. Pushes made with the defaultGITHUB_TOKENdo not trigger CI, so required checks would never run on bot commits.
- Identity (comments, reviews, opening PRs): the default
- Permissions (optional): declare who can use what in
.github/hoverstare.toml— see spec 12. Defaults: auto-review for anyone,@review/developfor collaborators,mergefor users with write access.
- Only repo collaborators can issue commands; fork PRs are out of scope.
- PRs opened by the bot can show 1 workflow awaiting approval on
pull_requestchecks. That is GitHub's maintainer gate (below), not a missing LLM key. Approve the run, or prevent it as described in the FAQ. - Large tasks are sliced into budgeted rounds; the bot self-continues
(max 10 rounds per PR). It cannot run builds or tests. When Checks fail,
paste the job log into an
@hoverstarecomment — the agent does not fetch Actions logs. Browser-only loop, approval banner, and dogfood notes:docs/web-ide.md. - Commit identity and signing:
docs/web-ide.md.
Reviews/comments fail with permission errors?
Check workflow permissions (pull-requests: write required) and repo
Settings → Actions → General → Workflow permissions is "Read and write".
"model not found"?
You configured an OpenAI-compatible endpoint but no model name. Set
HOVERSTARE_MODEL (or model in hoverstare.toml).
400 / invalid temperature?
Your endpoint only accepts the default temperature. Set
set_temperature = false in hoverstare.toml.
Fixed findings aren't getting resolved?
A GitHub platform limitation: the default GITHUB_TOKEN cannot call
resolveReviewThread. HoverStare falls back to a "✅ confirmed fixed" reply in
the thread. For full resolution, store a classic PAT (repo scope) as secret
GH_PAT and pass it in the workflow env.
GitHub Enterprise?
Set GITHUB_API_URL=https://<your-ghe-host>/api/v3.
@hoverstare merge fails with 403?
The merge endpoint needs contents: write. Pass a PAT via gh_pat, or grant
the GitHub App Contents: Read and write (and accept the upgrade on the
installation).
Why do HoverStare's commits show as unverified?
Without a signing key the commits are unsigned. Configure
HOVERSTARE_GPG_PRIVATE_KEY (and the passphrase secret if the key has one) and
put the matching public key on the author's GitHub account. Note that GitHub
verifies against the commit's committer, and an app account cannot hold
signing keys — that is why an author override also makes the committer that same
person. Details: docs/web-ide.md.
Which HoverStare revision does a run use?
The one the event itself sits on, unless a pin applies. A flow (issue → go →
PR) records the default-branch revision it started from in the pull request
body, so every later round of that flow builds that same revision (and reuses
its cache). hoverstare-pin: master in a comment, or the version input of a
manual workflow_dispatch, overrides it; marker pins accept only master,
release tags, or commits reachable from the default branch. The round report
names the revision it built from.
Yellow banner "1 workflow awaiting approval" / checks stuck at action_required?
This is GitHub's maintainer-approval gate for pull_request workflows, not a
HoverStare bug and not a missing secret. How to drive develop mode from the
browser, including this banner: docs/web-ide.md.
GitHub checks both the pull-request author and the actor of the event that started the run. Those are different GitHub users:
- Opening the PR as
hoverstare[bot]uses the App identity. Once ahoverstare[bot]PR has been merged, later PRs opened by the same bot runpull_requestCI without this banner. - Using the GitHub App does not make those later CI runs look like the
App. Comments, the PR author, and
git logstayhoverstare[bot]. A commit pushed from Actions (even with the App installation token) is still recorded asgithub-actions[bot]for thepull_requestworkflow. That account has never had a PR merged, so the default policy asks a maintainer to approve on every such push. Approving one SHA does not trust the next.
That is why a repo can already have merged bot PRs and still stop on
continue rounds. Single-commit bot PRs only hit the first case (already
trusted). The App is the right unique identity for comments and commits; it
is not the actor GitHub uses for this gate.
Detect:
gh run list --repo OWNER/REPO --json databaseId,name,conclusion,event,headBranch \
--jq '.[] | select(.conclusion=="action_required")'Unblock this PR: click Approve workflows to run, or
gh api -X POST repos/OWNER/REPO/actions/runs/RUN_ID/approvePrevent:
- What actually skips the gate: pass a collaborator PAT as
gh_pat/ secretGH_PATforgit push. Keep the App token for comments and opening the PR (hoverstare[bot]stays the unique product identity). GitHub then treats thepull_requestactor as the collaborator. This is also how develop mode is specified: App = identity, PAT = write. - What does not: using only the App for push (the current fallback when
GH_PATis unset). That already happens in dogfood, and continue-round CI still showsgithub-actions[bot]. Relaxing Settings → Actions → General → Approval for running fork pull request workflows to Require approval for first-time contributors who are new to GitHub is fine for real fork PRs; it has not been observed to skip this same-repo Actions-push gate. - Do not add a
pull_request_targetworkflow whose only job is to approve other runs. That event runs with base-branch privileges and is a common injection path.
A go/dev round says "no changes, no PR created"?
Usually the task was too vague for one budgeted round. Reply with a sharper,
smaller instruction (files to touch, acceptance criteria) and run go again —
see the bot's comment for what it actually did.
# Dry-run a full review of a public PR (no publishing)
export OPENAI_API_KEY=... OPENAI_BASE_URL=... HOVERSTARE_MODEL=...
cargo run -- review --repo owner/repo --pr 123 --dry-run
# Review a local diff file (prints tool-call trace)
cargo run --example local_review -- path/to.diff [base_ref]
cargo test # unit + httpmock contract tests
cargo clippy --all-targets -- -D warnings
cargo fmtSpecs and the milestone plan live in specs/ — the single
source of truth for design decisions.
See CONTRIBUTING.md for the quality gate, commit-message convention, and PR review process.
Auto-updated daily by RepoScope —
committed to the orphan reposcope branch, never to master.