RepoMind
Local-first code intelligence for Python repositories: deep static analysis, repository health and risk hotspots — with an optional LLM layer on top.
RepoMind answers one question: where should a team spend its refactoring budget?
It parses a Python repository, builds a module dependency graph, computes complexity metrics, finds dead code, and correlates everything with Git churn to rank the highest-risk parts of the codebase. The result is a health score, a ranked list of explainable findings, and shareable Markdown/JSON reports.
- Deterministic first — the entire analysis works offline, with no API keys and no LLM.
- Explainable — every finding carries the measured values and thresholds that produced it.
- Fast — pure AST analysis plus a linear-time dependency graph; no code is executed.
- Extensible — rules, parsers and reporters are separate layers with stable contracts.
- Local-first — your code never leaves your machine unless you explicitly opt into a cloud model.
Features
| Area | What RepoMind detects |
|---|---|
| Complexity | cyclomatic complexity, cognitive complexity, deep nesting |
| Maintainability | long functions, wide parameter lists, oversized files |
| Design | god objects (method count, class size, weighted methods per class) |
| Dead code | unused imports, unreferenced private functions and methods |
| Dependencies | import cycles (strongly connected components), external package usage, hub modules |
| Call graph | function-level call edges; caller counts attached to findings and fan-in leaders in reports |
| Cohesion & coupling | LCOM4 per class (stub and dunder methods excluded) and afferent/efferent coupling with instability per module |
| Trend | health score across sampled commits (repomind trend), in terminal, Markdown or JSON |
| Search | lexical (BM25) and semantic search over AST-aware chunks; local fastembed embeddings or any embedding API through litellm |
| Security | eval/exec, shell=True and os.system, unsafe pickle/YAML deserialization, weak hashes, tempfile.mktemp, hardcoded secrets (values never reported) |
| Documentation | missing docstrings on public modules, classes, functions and methods (private names, framework hooks and tests exempt) |
| History | churn per file and per function (git log -L), authors, recency, and complexity × churn hotspots (function-level when available) |
| Correctness | files that fail to parse |
| Configuration | path excludes, per-rule ignore entries, per-repo thresholds |
Reports: rich terminal output, Markdown for pull requests, a self-contained
HTML report, SARIF for GitHub code scanning, and JSON for automation
(--fail-under and --fail-on-new turn RepoMind into a CI quality gate).
Quick start
Requires Python 3.12+.
pipx install repomind-analyzer # provides the `repomind` command
The PyPI distribution is called repomind-analyzer because the plain
repomind name is taken by an unrelated project.
From source (for contributors):
# with uv (recommended)
uv venv
uv pip install -e ".[dev]"
# or with pip
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install -e ".[dev]"
Analyze a repository:
repomind analyze /path/to/repository
╭──────────────────────────────── RepoMind ─────────────────────────────────╮
│ Repository /home/dev/RepoMind │
│ Python code 88 files | 8,027 source lines │
│ Duration 3.93 s │
│ Git history analyzed │
╰───────────────────────────────────────────────────────────────────────────╯
██████████ 100/100 | grade A
No findings above the configured thresholds.
7 finding(s) suppressed by configuration (details in --format json).
Dependency graph
Metric Value
Internal modules 88
Internal imports 265
Import cycles 0
External packages 26
Call graph: 572 functions, 648 call edges
fan-in repomind.core.engine.analyze_repository (33 callers)
fan-in repomind.config.load_config (22 callers)
fan-in repomind.core.pyparser.parse_module (21 callers)
Most unstable modules: repomind.__main__ (1.00), repomind.agents (1.00), repomind.git (1.00)
Change hotspots (last 22 commits on master)
File Commits Churn Authors Last change Heat
src/repomind/core/engine.py 8 584 1 2026-09-22 100
src/repomind/core/pyparser.py 7 478 1 2026-09-22 78
src/repomind/cli/app.py 4 504 1 2026-09-22 63
Tip: use --format markdown --output report.md for a shareable report or --format json for machine-readable output.
Output above is trimmed and uncolored; borders and the score bar adapt to your terminal's encoding. The two suppressed entries are deliberate and explained in Dogfooding. A full HTML report generated from the deliberately flawed sample project is checked in at docs/example-report.html.
Generate shareable reports:
repomind analyze . --format markdown --output report.md
repomind analyze . --format json --output report.json
repomind analyze . --min-severity high --top 10
repomind analyze . --exclude migrations --exclude "*_pb2.py"
repomind analyze . --since main # review only files changed since main
repomind analyze . --fail-under 70 # exit code 1 when the score drops
repomind analyze . --format sarif --output repomind.sarif
repomind analyze . --format html --output report.html
repomind trend . # health score across sampled commits
repomind search "retry backoff" # lexical search over code chunks
repomind index . # build the local semantic index
repomind search "where is retry handled" --mode semantic
repomind rules # list every built-in rule
Adopting RepoMind in a legacy repository: accept today's findings once, then let CI fail only on new problems.
repomind baseline . # writes .repomind-baseline.json
repomind analyze . --fail-on-new # exit code 1 only for new findings
The baseline file is plain JSON with one reviewable entry per accepted finding (rule, path, symbol, severity). Fingerprints ignore line numbers and measured values, so a known issue stays known when it moves or grows.
Useful flags:
| Flag | Description |
|---|---|
-f, --format |
terminal (default), markdown, json, sarif or html |
-o, --output |
write markdown/JSON/SARIF/HTML to a file instead of stdout |
--min-severity |
hide findings below info, low, medium, high or critical |
--top |
number of findings shown in the report |
--history/--no-history |
force Git history analysis on/off (default: auto) |
-x, --exclude |
glob pattern to skip; repeatable, matches any path segment |
--config |
explicit configuration file |
--baseline / --no-baseline |
use or ignore a baseline file (auto-detected by default) |
--since |
only analyze Python files changed since a Git revision (committed + working tree) |
--fail-on-new |
CI gate: exit code 1 for findings not accepted by the baseline |
--fail-under |
CI gate: exit code 1 below the given health score |
Configuration
Drop a repomind.toml at the repository root, or use [tool.repomind] in
pyproject.toml:
[tool.repomind]
exclude = ["migrations", "*/generated/*"]
ignore = [
"maintainability/too-many-parameters@src/app/cli.py",
"dead-code/unused-import",
]
use_git_history = true
history_commits = 500
blame_files = 10 # hottest files tracked with git log -L (0 disables)
[tool.repomind.thresholds]
cyclomatic_warn = 10
cyclomatic_high = 15
cyclomatic_critical = 20
function_length_warn = 60
god_object_methods = 15
hotspot_min_commits = 5
Unknown keys are rejected loudly, so typos never silently change your analysis.
ignore entries silence known, accepted findings: rule-id suppresses a rule
everywhere, rule-id@glob only for matching paths. Suppressed findings never
disappear silently — every report shows how many were suppressed and
--format json lists them in full.
GitHub Action
RepoMind ships a composite action that analyzes the repository, writes a SARIF report and uploads it to GitHub code scanning, so findings appear as alerts on the pull request diff:
name: repomind
on: [push, pull_request]
permissions:
contents: read
security-events: write
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: PeterCode-cmd/RepoMind@master
with:
fail-on-new: "true" # optional: fail only on new findings
fail-under: "85" # optional: fail below this health score
Inputs: path, fail-under, fail-on-new, baseline, sarif-file,
upload-sarif. The action runs with --no-history so results stay
deterministic on shallow checkouts.
How the health score works
- Every finding adds penalty points:
critical 8,high 4,medium 1.5,low 0.5,info 0.1. - The penalty is normalised per 100 source lines:
density = penalty / (loc / 100). score = 100 - density × 10(clamped to 0–100), gradeA< 1.0,B< 2.0,C< 4.0,D< 7.0, elseF.
Size normalisation keeps large legacy repositories from being punished for their sheer size; the score measures density of problems, not their absolute count.
Architecture
repomind/
├── src/repomind/
│ ├── cli/ # Typer + Rich command line interface
│ ├── core/ # discovery, AST parser, complexity, graph, rules, engine
│ │ └── rules/ # one module per rule family, registered in default_rules()
│ ├── git/ # history analysis: churn, authors, hotspots
│ ├── models/ # shared dataclasses: findings, metrics, enums
│ ├── reporters/ # terminal, Markdown and JSON renderers
│ ├── semantic/ # (roadmap) embeddings + local vector search
│ ├── agents/ # (roadmap) LLM agents fed with prepared metrics
│ └── dashboard/ # (roadmap) Streamlit dashboard
├── tests/
│ └── fixtures/sample_project/ # deliberately flawed package used by tests
├── docs/
├── pyproject.toml
└── README.md
Pipeline: discover → parse → graph → history → rules → score → report.
Rules never read files: they consume prepared metrics, graphs and history, which
keeps them fast, deterministic and easy to test. See
docs/architecture.md for details and extension guides.
Dogfooding
RepoMind analyzes itself in CI:
repomind analyze . --no-history --fail-under 95
The repository ships a repomind.toml with two deliberate decisions:
exclude = ["tests/fixtures"]— the sample project is intentionally broken (that is its job), so it must not count towards RepoMind's own health.- two
ignoreglobs covering the Typer declaration surfaces insrc/repomind/cli/*.py— a command is one parameter per flag with rich help text and no logic, so parameter count and function length describe the CLI framework, not the code.
Everything else is clean: 100/100 (grade A), zero findings, zero import cycles. The score only became meaningful after the exclusions above; before them, RepoMind was grading its own test fixtures.
Benchmarks
First-run results on popular open-source projects (default thresholds, no configuration, 500-commit window):
| Project | Files | Source lines | Score | Findings | Wall time |
|---|---|---|---|---|---|
| psf/requests | 37 | 8,029 | 60/100 C | 159 | 21.9 s |
| pallets/flask | 83 | 10,740 | 68/100 C | 212 | 25.2 s |
| tqdm/tqdm | 65 | 5,901 | 30/100 D | 221 | 24.6 s |
| psf/black | 351 | 118,690 | 85/100 B | 886 | 25.3 s |
The full write-up — methodology, notable findings, and why excluding tests can lower the score — is in docs/benchmarks.md.
Trend
repomind trend samples commits, analyzes each one in a detached Git worktree
(same rules, thresholds and configuration every time) and reports how the
health score moved. RepoMind on itself:
Health trend (last 50 commits)
Date Commit Subject Score Grade Findings
2026-09-22 5f1eb37 Add semantic layer and comprehensive ... 87 B 22
2026-09-22 c81f016 Reduce complexity in the analysis core 97 A 5
2026-09-22 8db9318 Add baseline support and --fail-on-new 100 A 1
2026-09-22 eab2bf1 Track function-level churn with git log -L 100 A 0
2026-09-22 32aa381 Add LCOM4 cohesion and instability 100 A 0
Score 87 (5f1eb37) -> 100 (32aa381) (+13) best 100 (8db9318), worst 87 (5f1eb37)
History and blame stages are skipped per sample (they would be expensive and
biased by each snapshot's own commit window); use --samples and --commits
to trade detail for runtime.
Roadmap
- MVP: CLI, static analysis, dependency graph, terminal + Markdown reports
- Git history analysis with complexity × churn hotspots
- JSON output and
--fail-underCI gate - Configurable suppression (
ignore) and decorator-aware dead-code detection - Baseline +
--fail-on-newfor incremental adoption in legacy repositories - Diff mode (
--since) for pull-request reviews - SARIF output and a GitHub Action
- Self-contained HTML report
- Benchmarks against popular open-source projects (docs/benchmarks.md)
- Published on PyPI as
repomind-analyzer(v0.1.0) - Security, documentation, call-graph, cohesion and trend analyses
- Semantic layer: local embeddings + natural-language questions about the code
- Agent layer: Architect / Quality / Security / Maintainability / Documentation
- Streamlit dashboard
- GitHub URL input (clone + analyze) and PR comment bot
- Additional languages (tree-sitter based)
Development
uv pip install -e ".[dev]"
ruff format . # formatting
ruff check . # linting
mypy # strict type checking
pytest --cov # tests + coverage
pre-commit install # optional: run checks on every commit
The test suite includes a deliberately flawed sample project
(tests/fixtures/sample_project) that exercises every built-in rule, plus
temporary Git repositories for history analysis.
Contributing
Contributions are welcome — see CONTRIBUTING.md. Good first issues: new rules, new reporters, language support, and the roadmap items above.
License
MIT — see LICENSE.
Release files for repomind-analyzer 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| repomind_analyzer-0.2.0.tar.gz | 118.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| repomind_analyzer-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 236.8 kB
Release files / repomind_analyzer-0.2.0.tar.gz
| Download URL | repomind_analyzer-0.2.0.tar.gz |
|---|---|
| Size | 118.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e6c43041a853f59adbd139b765f16d2b61c9b2538a0eb47966120fe9487f382b
|
|
BLAKE2b-256 checksum How to use checksums |
5e757d088edcedbbdff6c20760a33f8d7247406e3ec16135b913f76e5a045761
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency logRelease files / repomind_analyzer-0.2.0-py3-none-any.whl
| Download URL | repomind_analyzer-0.2.0-py3-none-any.whl |
|---|---|
| Size | 118.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
02375b20dd5f8f7f9ffedfcd6cd0410556d864285c26b9a48a13bdecdfd523b0
|
|
BLAKE2b-256 checksum How to use checksums |
8a3acde0216429320f09300a3bcd62cea900f845189ce6b1a63c01718e7e2571
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency log