Diff call stacks across git commits — like git diff, but for who-calls-whom.
Built for agentic code review: when an agent (or you) rewires call flow, plain line diffs bury the shape of the change. calldiff shows which callees appeared, disappeared, or moved under an entrypoint — across 23 languages.
PiService.createAgentSession(options)
- ├─ AuthStorage.create()
- ├─ new ModelRegistry
- ├─ createCodingTools()
+ ├─ PiService.getServices()
+ │ ├─ SettingsManager.create()
+ │ ├─ AuthStorage.create()
+ │ └─ new ModelRegistryPaste this when you want a walkthrough of call-flow changes:
dearest clod, walk me through the code changes you made using
npx calldiff@latest
npx calldiff@latest
# or
npm install -g calldiff# HEAD vs working tree
calldiff diff
# one ref vs working tree
calldiff diff main
# two commits / branches
calldiff diff abc123 def456
calldiff diff --from main --to feature
# force entrypoints (functionName or ClassName.method)
calldiff diff main feature --entry createAgentSession
calldiff diff main feature -e PiService.createAgentSession -e boot
# file as entrypoint (every export in that indexed source file)
calldiff tree --file src/routes.ts
calldiff tree -F packages/api/src/boot.ts
calldiff diff main HEAD --file src/routes.ts
# limit to paths (trailing positionals; leading -- also accepted)
calldiff diff main feature src/lib
# view a call tree (no diff) — requires --entry
calldiff tree -e createAgentSession
calldiff tree HEAD -e PiService.createAgentSession
calldiff tree main -e boot --max-depth 8 src/lib
calldiff tree -e runCheckout --locs examples/checkout
# find all call paths from one symbol to another — requires --entry and --to
calldiff reach -e runCheckout --to sendEmail
calldiff reach HEAD -e runCheckout --to sendEmail examples/checkout
# agent / machine-readable output (via incur)
calldiff diff --format json
calldiff --llms
calldiff skills add # install agent skill files
calldiff mcp add # register as MCP server| Invocation | From | To |
|---|---|---|
calldiff diff |
HEAD |
working tree |
calldiff diff <from> |
<from> |
working tree |
calldiff diff <from> <to> |
<from> |
<to> |
- lines were present in from and gone in to.
+ lines are new in to.
If you omit --entry / --file, calldiff infers exported functions whose expanded call trees changed (and may show several).
--file / -F takes an indexed source path and expands to every exported symbol defined in that file (useful in monorepos). Matching is exact path, or a unique suffix (boot.ts → packages/api/src/boot.ts). Ambiguous matches error so you can pass a more specific path. --entry / -e is symbols only.
| Invocation | Tree from |
|---|---|
calldiff tree -e <name> |
working tree |
calldiff tree <ref> -e <name> |
that commit/ref |
Prints a plain ASCII call tree (no +/− markers). --entry / -e or --file / -F is required.
With --locs, each node shows a source location: the root uses the definition
file:line, and children use the call site in the parent (file:line or
file:line-line) — same idea as LSP Call Hierarchy fromRanges, not Go to
Definition.
| Invocation | Paths from |
|---|---|
calldiff reach -e <from> --to <target> |
working tree |
calldiff reach <ref> -e <from> --to <target> |
that commit/ref |
Prints every call path from the entrypoint to the target (including alternate if / else arms). --entry / -e or --file / -F, plus --to, are required.
functionName— free functionClassName.method— class methodnew ClassName— constructor /newcallComponent— JSX/TSX component tags (<Button />); children nest under the parentif (cond)/else/else if (cond)— conditional arms (no continuing│rail)file:line— call-site (or root definition) location; enable with--locs(default off)
TypeScript, TSX, JavaScript, JSX, Python, Go, Rust, Java, Ruby, C, C++, C#, PHP, Kotlin, Swift, Scala, Lua, Elixir, Bash, Haskell, Zig, Solidity, OCaml, Perl.
- Default: colored ASCII callstack trees (TTY) / colorless ASCII when piped — same shape as before.
--format json|yaml|md|jsonl: structured result (from/to/treesorpathswith nested nodes + per-entryascii) for agents and scripts.- Built on incur:
skills add,mcp add,--llms, CTAs after diffs, typed flags.
- Reads source from both git trees (
git show/ working tree) - Detects language by file extension, loads a tree-sitter grammar (bundled or on-demand into
~/.cache/calldiff/grammars), and parses - Builds per-function callee lists and expands them into call trees
- Diffs the trees, prints a tree, or searches paths — plus structured output for agents
Grammars install on first use (override cache with CALLDIFF_GRAMMAR_CACHE). This is syntactic (AST-based), not a full typechecker — dynamic calls won’t resolve.
npm run dev -- diff main HEAD --entry PiService.createAgentSession
npm run dev -- tree -e runCheckout -- examples/checkout
npm run dev -- reach -e runCheckout --to sendEmail -- examples/checkout