Skip to main content

Offline bug-risk prediction for code repositories. Static analysis + git intelligence + local ML. No cloud, no API keys required.

Project description

๐Ÿ” BugSeer

Offline bug-risk prediction for code repositories. Static analysis + git intelligence + a local ML model โ€” and an explanation for every number it shows you.

No cloud. No API keys. No telemetry. Your source code never leaves your machine.

Demo


๐Ÿ”ฅ  97  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  src/flask/app.py     Learned model predicts elevated defect risk ยท Mutable global state
๐Ÿ”ด  74  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘  src/payment.py       High bug-fix density ยท No error handling ยท Deeply nested control flow
๐ŸŸก  41  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  src/config.py        Frequently modified file
๐ŸŸข  12  โ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  src/utils.py         โ€”

Why this exists

Most "AI code review" tools give you a number and expect you to trust it. Developers don't, and they're right not to.

BugSeer's rule is simple: every point of risk traces back to named, inspectable evidence.

๐Ÿ”ฅ src/payment.py   96/100 (critical)
โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ
static 102  ยท  git 70  ยท  raw 172 pts

  โއ +40 High bug-fix density  [bugfix-density]
      9 of 10 commits (90%) look like bug fixes. Code that has needed
      repeated repair tends to need more.

  โ—† +27 No error handling around risky operations  [no-error-handling]
      4 I/O, network, parsing or subprocess call(s) and zero try/catch
      blocks. Failures here surface as unhandled exceptions in production.

  โ—† +25 Deeply nested control flow  [deep-nesting]
      Maximum loop nesting is 3 and maximum block depth is 7 (threshold 3).
      โ†ณ L12 (depth 7), L28 (depth 7), L11 (depth 6)

  โއ +14 Previously reverted  [revert-history]
      1 revert/rollback commit(s) touched this file. A revert is direct
      evidence that a change here broke something in production.

You can argue with that. That's the point.


Install

pip install -e ".[all]"     # everything
pip install -e .            # core only โ€” still fully functional
Extra Adds Without it
parsers tree-sitter for 19+ languages Python via stdlib ast, others via heuristics
server FastAPI dashboard Use the self-contained HTML report
ml XGBoost / LightGBM scikit-learn gradient boosting (built in)
env .env file loading Plain environment variables

Every extra is optional. Core BugSeer needs no network access at any point.


Quick start

bugseer scan .                        # rank files by risk
bugseer explain src/payment.py        # full reasoning for one file
bugseer heatmap .                     # colour-coded project tree
bugseer impact src/database.py        # "what if I change this?"
bugseer train .                       # learn from your own bug history
bugseer serve .                       # interactive dashboard
bugseer report . -o risk.html         # shareable offline HTML

The five phases

Phase 1 โ€” Rule-based static analysis (no AI, no API)

Parsed with the best available backend: stdlib ast for Python (exact), tree-sitter for 19+ other languages, and a heuristic analyzer that never fails so an unknown language still gets scored.

Rule Points Fires when
no-error-handling 20 Risky I/O with no try/catch
low-coverage 20 Measured coverage below threshold
deep-nesting 15 Nested loops deeper than 3
global-state 15 Mutable module-level state
high-complexity 12 Cyclomatic complexity > 20
long-function 10 Function longer than 100 lines
high-branching 10 More than 15 conditional branches
duplicate-code 10 Cloned blocks within or across files
swallowed-exception 8 except: / catch(e){} that hides failures
god-file 8 Over 600 lines
โ€ฆplus magic numbers, TODO debt, mutable defaults, long parameter lists

Phase 2 โ€” Git intelligence

Parses git log locally. No API, no network.

  • Change frequency โ€” the strongest empirical defect predictor
  • Bug-fix density โ€” how many commits here were repairs
  • Revert history โ€” direct evidence a change broke production
  • Fix-follow rate โ€” how often an edit here needed a follow-up fix within 7 days
  • Authorship spread and single-owner bus-factor risk
  • Co-change coupling โ€” files habitually committed together

Works on partial/blobless clones (--filter=blob:none), where git log --numstat would otherwise stall fetching blobs. BugSeer detects this, falls back to --name-only, and tells you churn is unavailable rather than silently reporting "no git history."

Phase 3 โ€” Learn from past bugs

bugseer train . --label-window 180

Trains locally on your repository. Labels come from bug-fix commits in a recent window; features come from history before that window โ€” a temporal split, so the model is genuinely predictive rather than circular.

โœ“ Model trained
  Estimator           sklearn.GradientBoostingClassifier
  Samples             80 files (17 bug-fixed)
  ROC AUC (5-fold)    0.7652
  Label window        1095 days

What the model learned to look at:
  largest parameter list      โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 24.5%
  comment ratio               โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 14.8%
  ownership concentration     โ–ˆโ–ˆโ–ˆโ–ˆ 10.0%

Honesty guarantees, because a prediction you can't trust is worse than none:

  • Reported metrics are out-of-fold (5-fold CV), never training-set scores.
  • Files in the training set get their cross-validated probability, not the memorised ~100% a fitted ensemble would return.
  • Probabilities are clamped to 2โ€“95%: a few dozen samples cannot justify certainty.
  • Too little signal? It says so and keeps using rules, rather than fitting noise.

Phase 4 โ€” Project heat map

bugseer heatmap in the terminal, or bugseer serve for the React dashboard. Click any file for its full evidence chain.

Phase 5 โ€” "What if?" simulator

$ bugseer impact src/flask/app.py

If you modify src/flask/app.py, 25 file(s) are most likely to be affected.

Impact              File                    Own risk  Why
    65  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘    src/flask/sessions.py         66  directly imports `app.py`;
                                                      changed together in 22% of commits
    52  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘    tests/test_basic.py           93  depends on `globals.py` transitively
                                                      (2 hops); is itself high-risk

Combines the import graph with historical co-change, weighted by each candidate's own fragility โ€” and explains every prediction.


Configuration

bugseer init          # writes a starter .bugseer.toml
[bugseer]
history_days = 730
exclude = ["docs/*", "examples/*"]
# coverage_file = "coverage.xml"

[bugseer.weights]
no_error_handling = 20
change_frequency = 15

[bugseer.thresholds]
long_function_lines = 100
band_critical = 85

Precedence: CLI flags โ†’ .bugseer.toml โ†’ environment/.env โ†’ defaults.

Test coverage

BugSeer auto-detects coverage.xml, lcov.info, coverage.json, and Clover. Without one it falls back to a filename heuristic โ€” and labels it as such, so a guess is never mistaken for a measurement.


CI usage

- run: pip install -e ".[parsers]"
- run: bugseer scan . --fail-over 85 --ignore-tests

Exits non-zero when any file exceeds the threshold. Add --json report.json to archive results.


The optional AI narrator

BugSeer needs no API key. All five phases above are deterministic and offline.

The only optional AI feature rewrites already-computed evidence as prose:

cp .env.example .env       # then set one key
bugseer explain src/payment.py --narrate

Supports OpenAI, Anthropic (Claude), Gemini, and Ollama (local).

Safety properties, enforced by tests:

  • It cannot change a score โ€” it receives finished evidence, and the score is computed before it runs.
  • It sends metrics and rule names only; source code requires explicit BUGSEER_AI_SEND_SOURCE=1.
  • BUGSEER_OFFLINE=1 blocks all outbound requests even if a key is set.
  • BUGSEER_AI_REDACT_PATHS=1 hashes file paths before transmission.
  • Any failure degrades gracefully to the deterministic explanation.

See .env.example โ€” every variable in it is optional.


Dashboard

bugseer serve .        # http://127.0.0.1:8420

React + TypeScript, bound to localhost. The build is committed, so it runs without a node toolchain. If the bundle is missing, the server falls back to the static HTML report.

To develop the frontend:

cd frontend && npm install && npm run dev    # proxies /api to :8420

Architecture

bugseer/
โ”œโ”€โ”€ analysis/
โ”‚   โ”œโ”€โ”€ static.py       Phase 1 โ€” ast | tree-sitter | heuristic backends
โ”‚   โ”œโ”€โ”€ langspec.py     Declarative grammar vocabularies (19+ languages)
โ”‚   โ””โ”€โ”€ duplication.py  Rolling-hash clone detection
โ”œโ”€โ”€ git_intel.py        Phase 2 โ€” git log parsing, coverage reports
โ”œโ”€โ”€ rules.py            Scoring engine โ€” every hit carries its evidence
โ”œโ”€โ”€ ml.py               Phase 3 โ€” local model, out-of-fold honesty
โ”œโ”€โ”€ graph.py            Phase 5 โ€” dependency graph + impact simulation
โ”œโ”€โ”€ scanner.py          Orchestration (parallel, with serial fallback)
โ”œโ”€โ”€ server.py           Phase 4 โ€” FastAPI dashboard
โ”œโ”€โ”€ report.py           Self-contained HTML output
โ”œโ”€โ”€ narrate.py          Optional AI narrator (stdlib urllib only)
โ””โ”€โ”€ cli.py              Typer CLI

Adding a language is a few lines of data in langspec.py. Adding a rule is one function in rules.py returning a RuleHit with its evidence.


Testing

pytest -q        # 104 tests

Covers the analyzers, rule scoring, git parsing, coverage formats, the graph, impact simulation, ML degradation paths, the CLI, and the narrator's privacy guarantees. Verified end-to-end against a real repository (Flask: 84 files, 5,539 commits) and a battery of pathological inputs โ€” binary files, invalid UTF-8, syntax errors, 800 KB files, broken symlinks, empty files.


Performance

Flask (84 files, 13k LOC, 3,812 commits analysed): ~1.0s full scan on 8 workers.


Design decisions worth knowing

  • Additive scores, saturating curve. Raw points are summed then squashed to 0โ€“100, so eight moderate problems and one catastrophic one both land sensibly.
  • Rules over ML by default. The model is opt-in and additive; it only moves a score when it genuinely disagrees with the repo baseline.
  • Naming heuristics are labelled. "No matching test file" never masquerades as measured coverage.
  • Trivial files score zero. Empty files and constants-only modules generate no findings โ€” noise is how a tool gets ignored.
  • Graceful degradation everywhere. No git, no tree-sitter, no model, no network: BugSeer still produces a useful report and tells you what it couldn't do.

License

MIT

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

bugseer-0.1.0.tar.gz (142.3 kB view details)

Uploaded Source

Built Distribution

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

bugseer-0.1.0-py3-none-any.whl (135.2 kB view details)

Uploaded Python 3

File details

Details for the file bugseer-0.1.0.tar.gz.

File metadata

  • Download URL: bugseer-0.1.0.tar.gz
  • Upload date:
  • Size: 142.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bugseer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9f02bbb36f9cc889ee3d57fb8619c52f8acf94f123884be397640c50a5baafd3
MD5 7602daf54bd03c21940058e9aeff47a6
BLAKE2b-256 3bd0c6b3ad663be4b2c8f8be6b2be64fde0bd35b55c42de469d49c7387eaa5f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for bugseer-0.1.0.tar.gz:

Publisher: publish-pypi.yml on rishibanota/Bugseer

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

File details

Details for the file bugseer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bugseer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 135.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bugseer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 901794122fe67d0af5136a5f009c037ce3bce5b1a243f2ae00108ddface698ac
MD5 276f2421d43b357d9c79ec801421eca5
BLAKE2b-256 9387d48a5768d62696de424ffa8429485bcfbe01bb0c8851deb3aa35a202159c

See more details on using hashes here.

Provenance

The following attestation bundles were made for bugseer-0.1.0-py3-none-any.whl:

Publisher: publish-pypi.yml on rishibanota/Bugseer

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