Skip to main content

Bubo — agentic AI code review for GitLab MRs and GitHub PRs, with the LLM of your choice.

Project description

Bubo 🦉

PyPI Python 3.14+ Docker: GHCR CI OpenSSF Scorecard Signed with cosign SLSA 3 Ruff Managed with uv Docs License: MIT

Agentic AI code review — with the LLM of your choice.

Self-hosted · bring-your-own-LLM · GitLab + GitHub · inline findings only · governance, provenance & audit · OpenTelemetry metrics

Bubo is the genus of the great horned and eagle owls — patient night hunters that sit silent, see in the dark, and strike only when sure. Code review, same idea: Bubo reviews your GitLab MRs and GitHub PRs with the LLM you choose (Codex, Claude, or any model your CLI drives) and posts only the findings worth acting on as inline threads — no chatbot noise, no praise, no summaries.

Features at a glance

🧠 Bring your own LLM Codex, Claude, or any model your CLI drives — no vendor lock-in.
🔒 Self-hosted Code, diffs, and review data stay on your infrastructure.
🔀 GitLab + GitHub MRs and PRs, one config, identical behavior on both.
🎯 Signal over noise Only actionable inline findings; one "all good" ack on a clean change.
🎭 Moods Pick the review voice — terse / collaborative / socratic / formal / casual.
📉 Learns your taste Suppresses finding-classes your team repeatedly disputes.
Verify before posting Optional "is this real?" passes drop findings that don't hold up.
🛡️ Governance-ready AI-code provenance, rigor modulation, auditable on-prem report.
🔌 MCP + CI Built-in bubo-mcp server + a GitHub Action to review PRs in CI.

📖 Documentation

Rendered docs live at → mountainowl.github.io/bubo — the canonical reference. The docs/*.md files below are its source; this README is a teaser.

👉 New here? The Recipes (docs/recipes.md) are copy-paste setups for GitLab and GitHub, using Codex (the bundled default) or Claude as the review agent.

What a review looks like

Findings are posted inline in a fixed shape — Issue / Impact / Evidence / Fix / Confidence:

Issue: HS256 JWT fallback is skipped when Cognito URL construction fails.
Impact: Valid local/shared-secret JWT requests return 500 instead of authenticating.
Evidence: The changed interceptor rethrows InvalidAwsUrlException before fallback runs.
Fix: Treat Cognito validation construction failures as failed Cognito auth when fallback is allowed.
Confidence: 0.94

Found nothing? Bubo posts one short change-level acknowledgement (Automated review ran — no issues found.) so a clean MR/PR reads differently from one the reviewer never touched. It's on by default, dedup'd by bot author + exact body, and configurable under [agents] (see the configuration reference).

🎭 Give it a mood

A finding only helps if someone reads it. The shape above is terse — the default, and the right call when you want pure signal. But a robotic comment gets skimmed; one that sounds like a teammate gets fixed. So Bubo lets you pick the voice. One knob:

[review]
tone = "collaborative"   # terse · collaborative · socratic · formal · casual

Below is one real finding — a cookie-deletion bug Bubo caught on a public PR — wearing four moods. Same bug, same evidence, same 0.99 confidence underneath. Only the words change:

🤝 collaborativefor teams who want a teammate, not a linter Heads up — this removes by name only, so if the jar has sid for a.example and b.example, one popitem() returns one pair but deletes both cookies. Probably worth clearing the specific cookie using its domain/path/name.

🤔 socraticfor mentoring and review-as-teaching What happens here when the jar has the same cookie name for two domains? del self[name] goes through remove_cookie_by_name without domain/path, so this removes every matching cookie while returning only one pair — should we clear the selected cookie by domain/path/name instead?

🏛️ formalfor regulated shops and a clean audit trail When multiple domains contain the same cookie name, this deletes by name only and removes every matching cookie while returning a single pair. Recommend clearing the specific cookie selected by popitem using its domain, path, and name.

😎 casualfor startups who keep it light Quick one — this deletes by name only, so same-name cookies on other domains/paths get cleared too. Grab the Cookie from the iterator and clear that exact domain/path/name.

The catch? There isn't one. Mood changes only the words a developer reads. Severity, evidence, confidence, the dedup fingerprint, and every row in your governance/audit dataset stay identical across tones — so you tune the voice for your humans without touching the data your compliance reports run on. Ships as terse; opt in when you're ready, set it once, leave it to the operator. → tone reference

More sanitized review examples are in docs/examples/README.md.

60-second quickstart

Install the prereqs (uv, Python 3.14+, Git, plus the CLI for your SCM and a Codex agent — see prerequisites), then:

uv tool install bubo     # from PyPI (or: pip install bubo)
# or track the main branch:
#   uv tool install git+https://github.com/mountainowl/bubo
bubo init                # idempotent; --dry-run to preview

# Edit ~/.local/share/bubo/config/env.toml:
#   [gitlab].token, [agents].llm_model, [agents].llm_api_key,
#   [agents].llm_api_key_env, and at least one [[projects]] entry.

bubo doctor              # verify before first poll
bubo-poller              # one poll cycle; exits at the end

The first cycle runs with [review].dry_run = true (the default) — findings are planned, no comments posted. Flip to false once a real review looks right. Full walkthrough in the Recipes and install and configure; poller flags and the bundled MCP server are in run.

Prefer a container? A multi-arch image is published to GHCR each release:

docker pull ghcr.io/mountainowl/bubo
docker run --rm ghcr.io/mountainowl/bubo bubo report   # or bubo init / bubo-poller

The image ships bubo + git; the review-agent CLI (Codex/Claude) is BYO — derive your own image (FROM ghcr.io/mountainowl/bubo) or mount it in.

Further reading

These render on the docs site and as plain Markdown in the repo:

Doc What's in it
Prerequisites macOS / Linux runtime, per-provider tools, credentials, install verification.
Install and configure uv tool install, bubo init, the minimum config/env.toml, GitLab and GitHub bot setup.
Run One-off review, the poller, the bundled bubo-mcp MCP server, and upstream wrappers.
Configuration reference Every [scm] / [gitlab] / [github] / [review] / [poller] / [agents] / [telemetry] / [[projects]] setting and its default.
Operate Remote deploy, scheduling under cron or systemd, --sync-outcomes grading, one-shot backfill.
Telemetry Emitted llm_review.* metrics, ready-made dashboard queries, cardinality discipline.

Status

  • GitLab & GitHub posting via polling — production path, at outcome-metric parity. Set [scm].provider = "github" (or BUBO_PROVIDER=github).
  • MCP server (bubo-mcp) — read-only metrics + triggered reviews; stdio or HTTP.
  • Codex or Claude — Bubo runs the review through a wrapper around your agent CLI. Codex ships pre-wired as the bundled default; Claude works the same way once you point the wrapper at it.
  • Webhook-driven triggering — not yet; polling is the only path.

Review execution sits outside CI/CD by design. Run it as a poller beside your existing pipelines.

Security

  • config/env.toml is gitignored and holds tokens. Do not print or commit real values from it.
  • Review-agent stdout is redacted (GITLAB_TOKEN=, OPENAI_API_KEY=, glpat-…, sk-…, and credentialed Git URLs) before it touches reports, logs, or the database error column.
  • The reviewer subprocess runs under a strict env allowlist — host secrets aren't passed wholesale into the LLM agent. Releases are cosign-signed with an SBOM. Report vulnerabilities per SECURITY.md.

Bot avatar

Upload assets/bubo.png as the GitLab (or future GitHub) bot avatar.

Bubo avatar preview

Community

Contributing · Security policy · Support · Code of conduct

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bubo-0.21.3.tar.gz (345.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bubo-0.21.3-py3-none-any.whl (160.4 kB view details)

Uploaded Python 3

File details

Details for the file bubo-0.21.3.tar.gz.

File metadata

  • Download URL: bubo-0.21.3.tar.gz
  • Upload date:
  • Size: 345.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for bubo-0.21.3.tar.gz
Algorithm Hash digest
SHA256 6f30bbc70bd7a20ea6bcf7f8f4ffb1e674b1c6f2828aefa4047593ed7e38e01c
MD5 dc42ec464f52a2bef2935d8f6e7aa72b
BLAKE2b-256 edf5679e1600d7d12e039e36efec29d260e6730ef5ce7ef3a3a5040931a293bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for bubo-0.21.3.tar.gz:

Publisher: publish-pypi.yml on mountainowl/bubo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bubo-0.21.3-py3-none-any.whl.

File metadata

  • Download URL: bubo-0.21.3-py3-none-any.whl
  • Upload date:
  • Size: 160.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for bubo-0.21.3-py3-none-any.whl
Algorithm Hash digest
SHA256 864bda3b5ac2af2cdf180c279fa6716c322be9738914650745d60b13b80f4207
MD5 eb93fe90185928bc36abcae51499657e
BLAKE2b-256 1c8e6e19edda99ec7f730933e8695f69f9017972eeacc0cbec2ca407a406ca70

See more details on using hashes here.

Provenance

The following attestation bundles were made for bubo-0.21.3-py3-none-any.whl:

Publisher: publish-pypi.yml on mountainowl/bubo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page