GitHub - tanishqkancharla/calldiff: Diffs for function call stacks across git commits. 22 languages supported (AST-based, built using Tree-sitter). Great for agentic review. · GitHub
/" data-turbo-transient="true" />
Skip to content
Type / to search
Sign in<br>Sign upAppearance settings
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
tanishqkancharla
calldiff
Public
Notifications<br>You must be signed in to change notification settings
Fork<br>13
Star<br>284
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>19 Commits<br>19 Commits
examples
examples
src
src
test
test
.gitignore
.gitignore
AGENTS.md
AGENTS.md
LICENSE
LICENSE
README.md
README.md
package-lock.json
package-lock.json
package.json
package.json
tsconfig.json
tsconfig.json
vitest.config.ts
vitest.config.ts
View all files
Repository files navigation
calldiff
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 22 languages .
PiService.createAgentSession(options)<br>- ├─ AuthStorage.create()<br>- ├─ new ModelRegistry<br>- ├─ createCodingTools()<br>+ ├─ PiService.getServices()<br>+ │ ├─ SettingsManager.create()<br>+ │ ├─ AuthStorage.create()<br>+ │ └─ new ModelRegistry
Prompt for agents
Paste this when you want a walkthrough of call-flow changes:
dearest clod, walk me through the code changes you made using npx calldiff@latest
Install
npx calldiff@latest<br># or<br>npm install -g calldiff
Usage
# HEAD vs working tree<br>calldiff diff
# one ref vs working tree<br>calldiff diff main
# two commits / branches<br>calldiff diff abc123 def456<br>calldiff diff --from main --to feature
# force entrypoints (functionName or ClassName.method)<br>calldiff diff main feature --entry createAgentSession<br>calldiff diff main feature -e PiService.createAgentSession -e boot
# limit to paths (trailing positionals; leading -- also accepted)<br>calldiff diff main feature src/lib
# view a call tree (no diff) — requires --entry<br>calldiff tree -e createAgentSession<br>calldiff tree HEAD -e PiService.createAgentSession<br>calldiff tree main -e boot --max-depth 8 src/lib<br>calldiff tree -e runCheckout --locs examples/checkout
# find all call paths from one symbol to another — requires --entry and --to<br>calldiff reach -e runCheckout --to sendEmail<br>calldiff reach HEAD -e runCheckout --to sendEmail examples/checkout
# agent / machine-readable output (via incur)<br>calldiff diff --format json<br>calldiff --llms<br>calldiff skills add # install agent skill files<br>calldiff mcp add # register as MCP server
diff semantics (git-diff shaped)
Invocation<br>From<br>To
calldiff diff<br>HEAD<br>working tree
calldiff diff
working tree
calldiff diff
- lines were present in from and gone in to .
+ lines are new in to .
If you omit --entry, calldiff infers exported functions whose expanded call trees changed (and may show several).
tree
Invocation<br>Tree from
calldiff tree -e<br>working tree
calldiff tree -e<br>that commit/ref
Prints a plain ASCII call tree (no +/− markers). --entry / -e is required.<br>With --locs, each node shows a source location: the root uses the definition<br>file:line, and children use the call site in the parent (file:line or<br>file:line-line) — same idea as LSP Call Hierarchy fromRanges, not Go to<br>Definition.
reach
Invocation<br>Paths from
calldiff reach -e --to<br>working tree
calldiff reach -e --to<br>that commit/ref
Prints every call path from the entrypoint to the target (including alternate if / else arms). Both --entry / -e and --to are required.
Labels
functionName — free function
ClassName.method — class method
new ClassName — constructor / new call
Component — JSX/TSX component tags (); children nest under the parent
if (cond) / else / else if (cond) — conditional arms (no continuing │ rail)
file:line — call-site (or root definition) location; enable with --locs (default off)
Supported languages
TypeScript, TSX, JavaScript, JSX, Python, Go, Rust, Java, Ruby, C, C++, C#, PHP, Kotlin, Swift, Scala, Lua, Elixir, Bash, Haskell, Zig, Solidity, OCaml.
Output
Default: colored ASCII callstack trees (TTY) / colorless ASCII when piped — same shape as before.
--format json|yaml|md|jsonl: structured result (from/to/trees or paths with nested nodes + per-entry ascii) for agents and scripts.
Built on incur: skills add, mcp add, --llms, CTAs after diffs, typed flags.
How it works
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...