Skip to main content

culprit

CI PyPI Python versions License: MIT

Root-cause analysis for a pull request or branch. Read-only — never modifies your repo or PR.

Given a PR or branch, culprit classifies it as a bugfix or feature:

  • Bugfix — blames the lines the fix removed at base revision to rank introducing commits (the suspect set), surfaces the author's original intent (introducing PR + linked issue), determines which releases shipped the bug, flags hotspot files, and checks fix completeness (untouched call sites, missing test, revert).
  • Feature — maps the blast radius: reverse-import dependents, covering tests, high-risk shared modules.

Example

rca --html report.html on a bugfix — a one-line formula silently broken by a perf commit, shipped across three releases. QA risk score, introducing commit intent, line-evolution timeline (created → broke (red) → fix (green)), test impact, co-change gaps, reviewer suggestions.

culprit RCA report

Single self-contained HTML file. No server, no CDN. Opens offline, attaches to CI.

Architecture

The deterministic git work (diff parsing, git blame/git log -L, suspect set, reverse-import map) emits structured JSON. The LLM narrative is isolated behind a ReasoningAdapterHarnessAdapter for Claude Code (no key needed), ClaudeAPIAdapter for standalone use (claude-opus-4-8 default, --fast for claude-sonnet-4-6).

  PR / branch ---.
  stack trace ---+--> pr_context --> ctx  (diff, changed files, commits, host links)
                          |
                          v
                    classify   (bugfix vs feature, with evidence)
                   /                                  \
          bugfix  v                                    v  feature
   suspect   (blame the lines the fix removed)     blast_radius
     -> evolution  (how the line evolved)           (importers, covering tests,
     -> intent / lifecycle / completeness            high-risk modules)
     -> test_gap
                   \                                  /
                    v                                v
                  report.build --> QA risk score
                          |
            + test_impact . coupling . owners . coverage
                          |
                          v
   reasoning (optional LLM "why") --> output:
      JSON | HTML report | markdown | --select-tests | --fail-on (CI exit code)

Full module map and data shapes: docs/ARCHITECTURE.md.

Install

uvx culprit                          # runs from PyPI on demand, no install step
uvx --from "culprit[api]" rca        # include the Claude API reasoning layer

pip install culprit                  # permanent install
pip install "culprit[api]"           # + anthropic SDK
pipx install culprit                 # isolated CLI
pip install -e ".[dev]" && pytest    # from source

PR metadata uses the GitHub CLI when available (brew install gh && gh auth login). For public repos, rca --pr N falls back to the unauthenticated REST API (GitHub and GitLab) — set GITHUB_TOKEN / GITLAB_TOKEN to raise rate limits. Without either, culprit uses local git only (no PR title/labels).

Hosts: deep links work for GitHub, GitLab, Bitbucket, and Gitea. For self-hosted forges set host = "gitlab" in .culprit.toml or CULPRIT_HOST.

Languages: suspect/timeline are language-agnostic (git blame/log -L). Blast radius detects imports across JS/TS, Python, Go, Java/Kotlin, Ruby, C/C++, C#, PHP, Rust, Scala, Swift.

Usage

rca                          # current branch vs configured base (or HEAD~1)
rca --last                   # latest commit only
rca --pr 16786               # specific PR (uses the PR's own base)
rca --repo /path --base main
rca --mode api --fast        # Claude API reasoning, sonnet model
rca --json                   # structured JSON output only
rca --html report.html --open
rca --trace crash.txt        # RCA from a stack trace, no fix/PR needed
rca --verify-fix patch.diff  # check a diff for completeness before committing
rca --select-tests           # print tests to run for this change (CI-pipeable)
rca --pr 16889 --bisect "pytest tests/test_x.py::test_y"
rca --pr 16889 --fail-on high   # exit non-zero when QA risk >= high
rca serve --repo /path          # local web UI with base picker (http://127.0.0.1:8722)

CI

culprit signals risk via exit code only — no PR comments, no writes. Copy examples/github-actions/culprit-pr.yml into .github/workflows/:

- uses: actions/checkout@v4
  with: { fetch-depth: 0 }
- uses: actions/setup-python@v5
  with: { python-version: "3.12" }
- run: pip install "culprit>=0.3.0"
- env: { GH_TOKEN: "${{ github.token }}" }
  run: rca --pr ${{ github.event.pull_request.number }} --html culprit-report.html --no-save --fail-on high
- if: always()
  uses: actions/upload-artifact@v4
  with: { name: culprit-report, path: culprit-report.html }

MCP server

culprit ships an MCP server that works with any MCP-compatible client over stdio: Claude Code, Cursor, Windsurf, VS Code, Codex CLI, Zed, Continue.dev, Cline, Amazon Q, Goose, or any agent built on the MCP SDK. Requires Python 3.10+ and uv (brew install uv).

Claude Code:

claude mcp add culprit -- uvx --from "culprit[mcp]" culprit-mcp

Other clients — add to your client's MCP config (mcpServers key; file location varies by client):

{
  "mcpServers": {
    "culprit": {
      "command": "uvx",
      "args": ["--from", "culprit[mcp]", "culprit-mcp"]
    }
  }
}

Tools (11):

Tool Description
analyze Full RCA in one call — classify + suspects/blast-radius + risk + test impact
find_suspects Rank commits by likelihood of introducing the bug
get_evolution Per-commit line history via git log -L for the buggy range
get_intent Introducing commit: message body, linked PR, referenced issues
check_completeness Call sites the fix didn't touch
verify_fix Check a proposed diff before committing — complete/partial/risky
get_risk_score QA gate score (0–100, low/medium/high) with contributing factors
get_blast_radius Feature change impact: dependents, covering tests, high-risk files
get_test_impact Minimal test set to run for this change
classify_change Bugfix vs feature with evidence
from_trace RCA from a stack trace — no diff or PR required

For a skill-based alternative (agent runs the CLI and writes the narrative), copy examples/claude-code-skill/SKILL.md into .claude/skills/rca/ and fill in <REPO_PATH> / <BASE_BRANCH>.

vs git bisect

git bisect culprit
Input A reliable failing test The fix diff (or a stack trace)
Method Checks out commits and runs the test Blames the fix's lines + git log -L
Speed Minutes (~log₂N test runs) Instant
Output First bad commit Suspect set, line evolution, intent, lifecycle, completeness, risk score
Confidence Proof Strong heuristic

--bisect "<cmd>" runs a real bisect as an optional confirmation layer — in a throwaway git worktree so your checkout is never touched. When the first failing commit matches the blamed suspect, the HTML report stamps it confirmed by git bisect. --good / --bad override the search bounds.

HTML report

--html PATH produces a single self-contained file (no CDN, opens offline). For a bugfix it renders a line-evolution timeline: for each line the fix touched, every commit that ever changed those lines from creation through the breaking commit (red) to the fix (green), each node expandable to its diff. Also includes: TL;DR banner, lifecycle strip (releases that shipped the bug), introducing PR intent card, fix-completeness callout, deep links on every commit/PR/file, weight bars on suspects, per-file filter, and a copy-as-markdown button.

rca --pr 16889 --html rca.html --open
rca --pr 16889 --html rca.html --narrative-file why.md   # embed a pre-written narrative

Configuration

Base branch resolution order: --base flag → CULPRIT_BASE env → .culprit.tomlHEAD~1.

# .culprit.toml
base = "origin/main"

--last forces the latest-commit view regardless of config.

Tests

pip install -e ".[dev]" && pytest

Download files

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

Source Distribution

culprit-0.3.1.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

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

culprit-0.3.1-py3-none-any.whl (76.9 kB view details)

Uploaded Python 3

File details

Details for the file culprit-0.3.1.tar.gz.

File metadata

  • Download URL: culprit-0.3.1.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for culprit-0.3.1.tar.gz
Algorithm Hash digest
SHA256 2325d7f86d6fee1fd15737be3bee60870a847f8b727d03641bc366d38d0a2398
MD5 65facd00f55a0f4a2706118f58fac20a
BLAKE2b-256 235805861c0e8f2988c4ef88795564df0edad891a34b28031b3fcaef3400d0ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for culprit-0.3.1.tar.gz:

Publisher: publish.yml on noordeen123/culprit

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

File details

Details for the file culprit-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: culprit-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 76.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for culprit-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4a2e1b4dca4ecd81fa82408e1cba7807f2d642b590c3ef4ad7b6ac86e2042f98
MD5 2bfb44c264508f1c3d9218ee6242c8bd
BLAKE2b-256 734793c029f7a3f2743a2b5522d84bd99a964483ee91a82965a43eacc9663089

See more details on using hashes here.

Provenance

The following attestation bundles were made for culprit-0.3.1-py3-none-any.whl:

Publisher: publish.yml on noordeen123/culprit

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

Release history Release notifications | RSS feed

0.4.1

2 files

0.4.0

2 files

This release

0.3.1 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page