DEV Community

N3MO
N3MO

Posted on

I indexed the entire Django codebase and traced 317 blast-radius references. Here's what I learned building the tool.

A few months ago I was mid-refactor on a Python codebase and grep -r gave me 12 results. I changed the function, ran the tests, and broke 4 things grep hadn't caught. Classic.

That afternoon I started building N3MO.

What N3MO does

N3MO answers one question: "what breaks if I change this?"

It parses your repository's ASTs using Tree-sitter, stores every symbol and call edge in PostgreSQL, then walks the call graph using recursive CTEs to return the full transitive blast radius of any function, method, or class.

pip install n3mo
n3mo index
n3mo impact "authenticate_user" --graph
Enter fullscreen mode Exit fullscreen mode

Output:

◈ IMPACT ANALYSIS
──────────────────────────────────────────────────
Target: authenticate_user

◉ Direct Callers (3 symbols)
 ▸ login_endpoint       api/auth.py:12
 ▸ refresh_token        api/token.py:23
 ▸ validate_session     middleware/auth.py:89

◎ Ripple Effects (5 symbols)
 ╰─▸ POST /login        routes.py:67
 ╰─▸ admin_login        admin/views.py:34
 ╰─▸ require_auth       decorators.py:12

──────────────────────────────────────────────────
Total impacted: 8 references │ depth ≤ 3
Enter fullscreen mode Exit fullscreen mode

Why Postgres as the graph store

The obvious question: why not Neo4j or a dedicated graph DB?

A few reasons:

  1. It's already in most stacks. Asking a team to spin up a new DB just for code intelligence is friction. Asking them to run n3mo setup (which starts a Docker container) is much less.
  2. Recursive CTEs are powerful enough. PostgreSQL's WITH RECURSIVE handles arbitrary-depth graph traversal cleanly. For the query volumes involved (this is a dev tool, not a production API), it's fast enough.
  3. The data is relational. Symbols have names, files, line numbers, types. Calls have callers and callees. This is a table, not a document or a property graph. The schema is roughly:
CREATE TABLE symbols (
  id SERIAL PRIMARY KEY,
  name TEXT,
  file TEXT,
  line INT,
  type TEXT  -- function, class, method
);

CREATE TABLE calls (
  caller_id INT REFERENCES symbols(id),
  callee_id INT REFERENCES symbols(id)
);
Enter fullscreen mode Exit fullscreen mode

The blast radius query uses a recursive CTE to walk calls from a given symbol outward to arbitrary depth.

The Django benchmark

I needed a real-world test case — not a toy repo. Django is public, large, and well-structured. Here's what indexing it looked like:

Metric Value
Files 3,021
Symbols ~43,000
Call edges ~181,000
Cold index time ~11 minutes
Impact query on dispatch 317 references, <2s

The biggest optimization came from fixing the call name matching query. Initial version used:

WHERE call_name LIKE '%' || s.name
Enter fullscreen mode Exit fullscreen mode

This was doing a full table scan on every symbol lookup. Replaced with:

WHERE SPLIT_PART(call_name, '.', -1) = s.name
Enter fullscreen mode Exit fullscreen mode

Cut indexing time from ~23 minutes to ~11 minutes on Django.

Other things N3MO does

Beyond the CLI, there are a few integrations I built:

GitHub App webhook — installs on a repo, runs on every PR, posts a markdown blast radius report as a PR comment. Useful for catching unintended impact before merge.

MCP server — N3MO exposes a Model Context Protocol server so AI coding tools (Cursor, Claude Desktop, Windsurf) can query the codebase structure before suggesting refactors. The idea is that if an agent knows dispatch has 317 downstream callers, it won't casually rename it.

Interactive graph UI--graph flag launches a vis.js visualizer in your browser with a depth slider and node highlighting. Click a node to deep-link into your local IDE.

What's next

The tool is technically complete. The current focus is on getting real teams using it and finding the rough edges.

If you work on a large Python codebase and want to try it:

pip install n3mo
n3mo setup   # starts Postgres in Docker
n3mo index   # parse and store
n3mo impact "your_function" --graph
Enter fullscreen mode Exit fullscreen mode

GitHub App and full source: github.com/RajX-dev/N3MO

AGPL-3.0. Free for open source and projects under 15k LOC.


Top comments (2)

Collapse
 
alexshev profile image
Alex Shev

Blast radius search is useful because it makes review contextual. Instead of asking an agent to understand the whole codebase, you ask it to follow the consequences of one change through real references.

That is also a better human workflow. A reviewer does not need every file; they need the few files where the abstraction leaks, the contract changes, or an assumption stops being true.

Collapse
 
n3mo-dev profile image
N3MO

The goal isn't to show everything it's to surface the few files where the contract actually changes.
That's what the recursive CTE traversal is built for: follow real references, stop at the boundary of the impact. No noise, just the files that matter.
The MCP integration works the same way instead of dumping the whole codebase into context, the agent queries blast radius on the specific symbol it's about to touch. Contextual, not exhaustive.