The Arbor engine · Open source · MIT licensed
Who calls it? What does it reach?
Arbor reads your source into a graph of functions, classes and modules, joined by the calls and inheritance it resolves. Query it from the arbor CLI or over MCP. It runs on your machine.
Ask the graph.
Who calls this function?
arbor callers your_functionReplace your_function with a symbol from your project. If several files define it, narrow with src/parser.py:your_function.
arbor setup indexes the project into .arbor/ at its root; add that folder to .gitignore. Callers and callees come back with the file and line to check. Tree-sitter parsers cover Rust, TypeScript/JavaScript, Python, Go, Java, C/C++, C# and Dart; Kotlin, Swift, Ruby, PHP and Shell use a simpler line-based fallback.
Review a branch.
arbor diff --base main reports a branch the way its pull request shows it. Each modified symbol gets its own blast radius; new ones are listed separately. arbor check can fail a CI job when a change reaches more than you allow or touches an entry point. A passing check isn’t proof the change is safe.
Bring your assistant.
arbor bridge gives Claude Code, Cursor, VS Code or another stdio MCP client the engine’s tools. v3.1.1 has 17, including get_callers and analyze_impact. Your assistant, and its model provider if it uses one, can receive what those tools return.
A map, not proof.
A static graph is a map, not proof that a change is safe. Arbor reads source; it doesn’t run your program or see production traffic. Dynamic imports and reflection can be missing and inheritance is only partly followed, so an empty answer doesn’t prove that nothing calls a function. Some impact counts also run high. Review the documented limitations and keep running your tests.