Graphora
Know what breaks before you change it.
Every function, method, and class in one code graph · What could break, split into certain and uncertain · Zero Docker · $0 LLM cost to build
pip install it as a library · run it as a CLI · plug it into any AI agent as an MCP server · or install the skill into 22 agents with one command
TL;DR: Graphora parses a repository with tree-sitter (no LLM) into a graph of every function, method, and class, and the calls between them. Ask it what could break if you change something, and it answers in three parts: callers that will break, callers that might break (with the alternatives spelled out: "this call is either X or Y"), and the tests that reach the change. It never guesses silently.
Why Graphora
AI coding agents and code review share the same blind spot: they see text, not structure. A one-line change to a shared function looks harmless in a diff; its callers live in other files. And when a tool does follow calls, it usually picks one target by name and presents the guess as fact.
| Problem | What Graphora does |
|---|---|
| Callers live outside the diff | Walks the call graph backwards (callers of callers, --depth N) from every changed function, method, or class. Edits inside a body count. |
| Name matching guesses wrong | Resolves each call the way the language does: self/this, same file, imports (incl. re-exports and src/ layouts), same Go package, declared types and return types. External library calls (os.path.join, fmt.Println) never link to your code. |
| Guesses look like facts | When a call could mean several definitions, it says so: "this save(...) call is either Db.save or FileStore.save, or a method outside this repository". |
| Missing definitions | Every function, method, and class: 100% of the definitions Python's own ast finds, on every repo we measured (see Benchmarks). |
| Repo dumps cost tokens | The answer is a few hundred tokens of facts, not the files. |
Quick start
pip install graphora-kg # or: pip install -e . inside this repo
graphora index /path/to/repo # build the graph (offline, $0)
cd /path/to/repo
graphora breaks charge_card # what could break if I change charge_card?
graphora breaks Db.save --depth 3
git diff | graphora breaks # ... for everything my diff touches
Without a FalkorDB server, Graphora uses its embedded backend (pure Python, JSON under
~/.graphora). For a shared, queryable graph, start FalkorDB and Graphora picks it up:
docker run -d --name graphora-falkordb -p 6379:6379 falkordb/falkordb:latest
# force a backend anytime with --backend embedded|falkordb|auto
What the answer looks like
Real output, from Graphora indexing its own repository:
$ graphora breaks EmbeddedGraphStore.find_symbols --depth 1
What could break if you change `EmbeddedGraphStore.find_symbols` (graphora/embedded.py:233)
Will break (1):
- `EmbeddedGraphStore.find_symbol` (graphora/embedded.py:277) calls `EmbeddedGraphStore.find_symbols` at line 280
Might break (3): the call could mean something else
- `blast_radius` (graphora/blast.py:82) may call `EmbeddedGraphStore.find_symbols` at line 87
this `find_symbols(...)` call is either `EmbeddedGraphStore.find_symbols` (graphora/embedded.py:233) <- the one you are changing
or `GraphStore.find_symbols` (graphora/store.py:267)
or a method outside this repository
... (2 more: what_could_break, changed_symbols)
Tests that reach it (0):
none found: consider adding one
With the default --depth 2 the same question also reaches the CLI commands, the MCP tools,
and 25 tests through those callers.
blast_radius receives a store typed as either backend, so the graph cannot know which
find_symbols runs; it shows both instead of picking one. Use --json for machine-readable
output.
How certain is each link?
Every CALLS edge carries a confidence tag and the rule that produced it:
| Tag | Meaning | Examples |
|---|---|---|
EXTRACTED |
The source names the target. | same-file call, self.method(), from pkg.mod import f; f(), db = FalkorDB(); db.query(), def f(g: Graph): g.query() |
INFERRED |
A bare call whose name matches exactly one definition. | compute() with one compute in the repo and no import |
AMBIGUOUS |
Several definitions match, or the receiver's type is unknown. All candidates are linked, and the answer lists them. | store.save() with Db.save and FileStore.save |
"Will break" uses only EXTRACTED/INFERRED paths. A single AMBIGUOUS call on the path
moves the caller to "might break".
Four ways to use it
1. CLI
graphora index PATH [--include-generated] Build the graph (no LLM; honours .gitignore, skips generated code)
graphora breaks NAME... [--depth N] What could break: will / might (X or Y) / tests
graphora breaks --diff F | --git-range R ... for every symbol a diff touches
graphora review [--diff F|--git-range R] Same facts as a review, plus missing-test warnings (LLM optional via --llm)
graphora blast NAME... Raw callers / callees / tests / importers
graphora stats Node and edge counts
graphora benchmark PATH Accuracy + context-size benchmark
graphora serve-mcp Serve the graph to AI agents over MCP
graphora install-skill [all|AGENT] Install the Graphora skill for 22 AI coding agents
graphora sessions ingest|connected Agent session-history graph (see below)
Every graph command accepts --project, --backend auto|falkordb|embedded, --host, --port.
2. Python library
from graphora import index_repository, open_store
from graphora.impact import what_could_break, what_could_break_for_diff
store = open_store("myrepo", backend="embedded")
index_repository("/path/to/repo", project="myrepo", store=store)
result = what_could_break(store, ["Db.save"], depth=2)
print(result.to_text()) # or result.to_dict()
# CI gate: fail when a PR changes code that certainly breaks callers and no test reaches it.
impact = what_could_break_for_diff(store, pr_diff)
assert impact.tests or not impact.will_break, impact.to_text()
3. MCP server (for AI agents)
graphora serve-mcp --project myrepo
Tools: what_could_break, what_could_break_for_diff, blast_radius, review_diff,
find_symbol, graph_stats. The server tells agents to call what_could_break before
editing a symbol and to report uncertain callers as uncertain. Works with mcp 1.x and 2.x.
4. One-command skill install (22 agents)
graphora install-skill all # every supported agent, into the current repo
graphora install-skill claude cursor copilot
graphora install-skill --list # see all supported agents
Writes the Graphora workflow (ask what could break before editing, check the diff before
committing) into each agent's project config: .claude/skills/, .cursor/rules/,
.github/instructions/, AGENTS.md, GEMINI.md, Windsurf, Cline, Roo, Continue, Amazon Q,
Zed, Goose, Aider, and more. Idempotent; existing files are preserved, shared files get a
marked block.
What gets indexed
Python, JavaScript/JSX, TypeScript/TSX, Go, Java, Rust, C, C++, Ruby, PHP (tree-sitter,
regex fallback). Per language this includes, for example: Python nested functions, lambdas,
decorated and async defs; JS/TS arrow functions, class fields, object-literal methods,
interfaces, enums; Go methods attached to their receiver type; Java constructors, records,
enums, interfaces; Rust impl methods; C++ out-of-class A::f definitions and destructors;
Ruby singleton methods; PHP traits and enums. Each symbol has a qualified name
(geo.Square.area), a parent, and a line range.
Indexing honours .gitignore inside a git work tree and skips generated files (ANTLR,
protobuf, @generated/DO NOT EDIT headers, minified JS) unless --include-generated.
Agent session memory: graph your work, not just your code
AI coding agents already record every session locally: GitHub Copilot CLI
(~/.copilot/session-store.db), Claude Code (~/.claude/projects/), Codex CLI
(~/.codex/sessions/). Graphora ingests them all into one graph, so sessions from
different terminals and different agents become connected the moment they touch the
same file, repo, or PR.
graphora sessions ingest --days 7 # all agents found (or --source copilot|claude|codex)
graphora sessions connected file build.yml # which windows/agents touched this file?
graphora sessions connected ref 275 # which sessions relate to PR 275?
graphora sessions connected repo org/proj # everything that happened in one repo
graphora install-skill all --skill sessions # let agents run these themselves
Read-only on the sources, no LLM, idempotent. See use case 6.
Benchmarks
Measured on local checkouts with graphora benchmark (embedded backend, deterministic, no
network). "Definitions found" compares the graph with Python's own ast parser; "certain"
is the share of call edges tagged EXTRACTED or INFERRED.
| Repository | Commit | Files | Definitions found (vs ast) |
Call edges | Certain | Context: repo → Graphora |
|---|---|---|---|---|---|---|
| Shiftory | f4e1a03630 |
61 | 498/498 (100%) | 1,479 | 97% | 134,155 → 1,243 tokens |
| falkordb-py | e4230e1ce7 |
42 | 390/390 (100%) | 1,143 | 57% | 61,931 → 1,708 tokens |
| GraphRAG-SDK | 93b760edd4 |
190 | 5,043/5,043 (100%) | 14,656 | 66% | 888,919 → 36,312 tokens |
The remaining ambiguous edges are mostly real polymorphism (several classes implement the
same method) and values whose type the source never states (e.g. pytest fixtures); those are
exactly the calls the answer lists as "X or Y". Indexing GraphRAG-SDK (190 files) takes 2.3 s
embedded and 2.5 s on FalkorDB. Methodology and the pinned public benchmark (scripts/public_benchmark.py)
are in BENCHMARKS.md.
Architecture
source files ──▶ tree-sitter parse: symbols (qualified names, ranges, return types),
call sites (callee + receiver), import bindings, local type facts
│
▼
resolver (graphora/resolve.py): self → same file → imports →
package → declared types → name; external imports dropped
│
▼
code graph (FalkorDB or embedded JSON)
File · Function · Class · Module / CALLS · DEFINED_IN · IMPORTS · IMPORTS_FILE
(every CALLS edge: confidence, candidates, reason)
│
┌──────────────┬──────────────┼───────────────┬─────────────┐
▼ ▼ ▼ ▼ ▼
what could break library API MCP server benchmark skill installer
(CLI, review) (CI gates) (AI agents) (accuracy) (22 agents)
Both stores keep each file's raw call sites and re-resolve the whole graph after every
write, so an incremental update (update_files) never drops callers in unchanged files.
Enterprise notes
- Privacy: indexing and queries are fully local. Nothing leaves the machine unless the
optional
review --llmis used, and then only the diff plus the graph facts go to your configured provider. - Determinism: identical input produces identical graphs and answers. No embeddings, no model drift in the core.
- Multi-project: one FalkorDB instance serves many project graphs (
graphora:{project}). Solo developers need no server at all (embedded backend). - Auditability: every claim in an answer traces to a tagged edge with the rule that
produced it (
same-file,import,self,returns,name,receiver-unknown, ...).
Testing
pip install -e ".[dev,mcp]"
python -m pytest tests -q # 200 tests
ruff check graphora tests scripts && mypy graphora
The suite covers every language's definitions (exact sets, including no false definitions), each resolution rule, what-could-break (certain vs uncertain, depth, diffs, X-or-Y text), both backends with a parity test, incremental updates, the CLI, the MCP server on mcp 1.x and 2.x, the skill installer, and the benchmarks. CI runs it against a live FalkorDB and fails on any skipped test.
Requirements
| Requirement | Version | Notes |
|---|---|---|
| Python | 3.10+ | |
| FalkorDB | optional | for the client-server backend; embedded backend needs nothing |
| git | any | .gitignore handling and --git-range |
| litellm | optional | only for review --llm |
| mcp | optional | only for serve-mcp (1.x or 2.x) |
License
MIT
Metadata
Release files for graphora-kg 0.3.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 | |
|---|---|---|---|
| graphora_kg-0.3.0.tar.gz | 68.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| graphora_kg-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 137.4 kB
Release files / graphora_kg-0.3.0.tar.gz
| Download URL | graphora_kg-0.3.0.tar.gz |
|---|---|
| Size | 68.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
811c10e0bd0cf5cd688c7adeb5eb04a648ae2469d43e0f20cd8808a8c5820762
|
|
BLAKE2b-256 checksum How to use checksums |
6faee6a11a26ec391b17f03b96d5bd2c10e8c514d4325c715ba4f233573c78f5
|
| 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 Oct 16, 2026.
Transparency logRelease files / graphora_kg-0.3.0-py3-none-any.whl
| Download URL | graphora_kg-0.3.0-py3-none-any.whl |
|---|---|
| Size | 69.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
38369b249ca1a786877ff3b30b5c49c3cf4a6842776f083d6f3b421c08871498
|
|
BLAKE2b-256 checksum How to use checksums |
0687849647146baa2185db42934f56d9d94713d7984c3327c7871cca6da29779
|
| 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 Oct 16, 2026.
Transparency log