Constrictor
An agent-first dependency and blast-radius explorer for Python codebases. Generates structured, machine-readable dependency graphs that AI coding agents can query to understand code relationships, assess refactoring impact, and navigate complex projects autonomously.
Install / Use
/learn @ameya1995/ConstrictorREADME
Constrictor
Static dependency and blast-radius analyzer for Python codebases. Answers "what breaks if I change X?" before you touch a line of code.
Agent Integration
Constrictor is designed first for AI agents. Two integration paths are available.
MCP server (Claude Code, Cursor, Copilot, Codex)
# 1. Install
pip install -e .
# 2. Scan the project once
constrictor scan . -o graph.json
# 3. Start the MCP server
constrictor mcp serve --graph graph.json
Add to your agent config (e.g. .claude/mcp.json, ~/.cursor/mcp.json):
{
"mcpServers": {
"constrictor": {
"command": "constrictor",
"args": ["mcp", "serve", "--graph", "graph.json"]
}
}
}
Available MCP tools:
| Tool | Description |
|---|---|
| constrictor_scan | Scan a project and build the graph |
| constrictor_impact | Blast-radius analysis (downstream / upstream) |
| constrictor_paths | Enumerate dependency paths between two nodes |
| constrictor_search | Search nodes by name, type, or file pattern |
| constrictor_file_context | All entities defined in a single file |
| constrictor_diff_impact | Blast radius from a git diff or line ranges |
| constrictor_batch_impact | Merged impact analysis for multiple nodes |
| constrictor_unused | Find dead code candidates (no incoming edges) |
| constrictor_cycles | Detect circular import dependencies |
| constrictor_dependents | Find all dependents of a file |
| constrictor_audit | List ambiguous / unresolved edges |
| constrictor_rescan_graph | Rebuild graph.json in place after editing code |
| constrictor_check_staleness | Check if graph is stale relative to source files |
| constrictor_summary | Human-readable graph summary + statistics |
Graph Staleness Detection
The dependency graph goes stale when source files change after the last scan. Running impact analysis on a stale graph produces inaccurate results.
Before any impact analysis, agents should check staleness:
// 1. Check if graph is stale
constrictor_check_staleness({ "graph_path": "graph.json" })
// Response:
{
"is_stale": true,
"changed_file_count": 3,
"recommendation": "Graph is stale: 3 file(s) modified since last scan. Call `constrictor_rescan_graph` to update."
}
// 2. If stale, rescan before proceeding
constrictor_rescan_graph({ "graph_path": "graph.json" })
// 3. Now run impact analysis with accurate data
constrictor_impact({ "node": "process_order", "graph_path": "graph.json" })
Why this matters:
- A stale graph won't reflect new imports, function calls, or class hierarchies
- Impact analysis on stale data will miss downstream dependents
- Agents may give incorrect refactoring advice based on outdated topology
SSE transport (for HTTP-based agent runtimes):
constrictor mcp serve --transport sse --port 9000
SKILL.md (skill-file agents)
For agent runtimes that discover tools via skill files:
constrictor agent skill -o SKILL.md
Common agent workflows
Staleness-aware impact analysis (recommended):
# 1. Check if graph is stale
constrictor_check_staleness --graph graph.json
# 2. If stale, rescan first
constrictor_rescan_graph --graph graph.json
# 3. Then run impact analysis
constrictor impact --node "app.services::process_order" --graph graph.json
Before refactoring:
constrictor scan . -o graph.json
constrictor impact --node "app.services::process_order" --graph graph.json
Before reviewing a PR:
git diff HEAD~1 | constrictor diff-impact --graph graph.json
Trace data flow to a database table:
constrictor paths --from "POST /api/orders" --to "orders" --graph graph.json
Find dead code:
constrictor unused --graph graph.json --exclude "tests/*"
Detect circular imports:
constrictor cycles --graph graph.json
After an agent edits files:
# Ask the MCP server to rebuild graph.json in place
constrictor mcp serve --graph graph.json
Then call constrictor_rescan_graph from the agent before running impact or path analysis again.
What it does
Constrictor parses every .py file into an AST and builds a rich dependency graph capturing:
- Import relationships — which modules depend on which
- Call graphs — which functions call which functions
- Class hierarchies — inheritance, ABC/Protocol implementations
- Framework endpoints — FastAPI, Flask, and Django routes
- Database models — SQLAlchemy and Django ORM with foreign-key relationships
- HTTP calls — outbound
requests/httpxcalls - Type annotations — parameter and return type relationships
- Service topology — multi-service projects via
docker-compose.yml,Procfile, multiplepyproject.tomlfiles
Every edge has a certainty level (EXACT, INFERRED, AMBIGUOUS, UNRESOLVED).
Installation
Constrictor is not yet published to PyPI. Install from source.
git clone https://github.com/ameya1995/Constrictor.git
cd Constrictor
pip install -e .
# Optional: pip install -e ".[dev]" # pytest, ruff, mypy
# Optional: pip install -e ".[js]" # JS/TS support via tree-sitter
Requirements: Python ≥ 3.10
CLI Reference
constrictor scan
constrictor scan <path> -o graph.json [-v] [-i] [--include-js] [-e <glob>]
Scans <path> and writes the dependency graph. -i enables incremental re-scanning (uses .constrictor_cache/).
constrictor impact
constrictor impact --node "app.utils::greet" --graph graph.json [--direction upstream|downstream] [--depth 6] [--format full|compact|files]
Blast-radius analysis for a single node.
constrictor diff-impact
git diff HEAD~1 | constrictor diff-impact --graph graph.json [--format compact]
Maps every changed line in a unified diff to graph nodes; produces a tiered impact report.
constrictor paths
constrictor paths --from "app.routes::create_order" --to "orders" --graph graph.json [--depth 8]
All dependency paths between two nodes (up to 20, capped to avoid combinatorial explosion).
constrictor search
constrictor search "create_order" --graph graph.json [--type FUNCTION] [--limit 10]
Ranked by match quality: exact → prefix → substring → regex.
constrictor context
constrictor context app/routes/users.py --graph graph.json
All entities (imports, functions, classes, endpoints, callers) defined in one file.
constrictor unused
constrictor unused --graph graph.json [--exclude "tests/*"] [--entry-point "main"]
constrictor cycles
constrictor cycles --graph graph.json [--edge-type CALLS]
constrictor watch
constrictor watch /path/to/project -o graph.json [--debounce-ms 1500]
Re-scans incrementally on every file change.
constrictor audit / constrictor summary
constrictor audit --graph graph.json # list AMBIGUOUS/UNRESOLVED edges
constrictor summary --graph graph.json # human-readable stats
constrictor export
constrictor export neo4j /path/to/project -o ./neo4j/ # produces nodes.csv, edges.csv
constrictor serve
constrictor serve --graph graph.json --port 8080
Interactive force-directed D3.js graph visualization in the browser.
Web UI quick start
# 1. Build or refresh the graph
constrictor scan . -o graph.json
# 2. Start the browser UI
constrictor serve --graph graph.json --port 8080
# 3. Open the app
open http://127.0.0.1:8080
How to use the UI
The web UI is organized as a three-column workspace:
- Left panel: view selection, focus controls, filters, and path inspector
- Center panel: interactive dependency graph or unresolved-audit list
- Right panel: metadata and blast-radius details for the currently selected node
Recommended workflow:
- Start in Workspace topology for a full-project view.
- Use Node type filters to remove noise before inspecting a subgraph.
- Type in Focus to visually narrow the graph to matching nodes.
- Click a node in the graph to open its metadata and impact analysis in the right panel.
- Switch Downstream / Upstream to answer either "what does this affect?" or "what depends on this?".
- Increase Depth when you want a broader blast radius.
- Use Path Inspector when you need concrete paths between two nodes.
Views:
- Workspace topology: the full graph, useful for general exploration
- Service/API dependencies: emphasizes service, component, endpoint, and external-service nodes
- Data/table impact: emphasizes SQLAlchemy models, tables, modules, and packages
- Unresolved audit: shows ambiguous and unresolved edges in a readable review list
Controls:
- Node type filter: show or hide classes of nodes without rebuilding the graph on disk
- Edge type filter: restrict the rendered graph to one edge type such as
CALLSorIMPORTS - Show ambiguous: hide inferred/ambiguous edges when you want a cleaner exact-only visualization of the current graph
- Path Inspector: enter a
fromnode andtonode, then click Find paths
Interpreting the graph:
- Larger nodes usually represent higher-level entities like services and components
- Colored dashed hulls group nodes that belong to the same detected service/component boundary
- Selecting a node highlights directly connected neighbors and dims unrelated parts of the graph
- The top stat tiles are a quick orientation aid, not a replacement for detailed analysis
Keeping the UI fresh after code changes:
- If you are using the CLI directly, rerun
constrictor scan . -o graph.json - If you are using the MCP server, call
constrictor_rescan_graphafter a batch of edits - If you want automatic refresh on file changes, use
constrictor watch . -o graph.jsonin a separate terminal and reload the b
