<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Agentic Code Review on RockB</title><link>https://baeseokjae.github.io/tags/agentic-code-review/</link><description>Recent content in Agentic Code Review on RockB</description><image><title>RockB</title><url>https://baeseokjae.github.io/images/og-default.png</url><link>https://baeseokjae.github.io/images/og-default.png</link></image><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 11 Aug 2026 01:01:59 +0000</lastBuildDate><atom:link href="https://baeseokjae.github.io/tags/agentic-code-review/index.xml" rel="self" type="application/rss+xml"/><item><title>CallDiff 2026 — Diffs for Function Call Stacks Across Git Commits</title><link>https://baeseokjae.github.io/posts/calldiff-function-call-stack-diffs-2026/</link><pubDate>Tue, 11 Aug 2026 01:01:59 +0000</pubDate><guid>https://baeseokjae.github.io/posts/calldiff-function-call-stack-diffs-2026/</guid><description>CallDiff 2026 diffs function call stacks across git commits in 22 languages — a tree-sitter-based call graph diff for agentic code review.</description><content:encoded><![CDATA[<p>CallDiff is an open-source, tree-sitter-based CLI that shows how function call stacks change between two git commits, &ldquo;like git diff, but for who-calls-whom.&rdquo; It compares call graphs across 22 languages (TypeScript, Python, Go, Rust, Java, C/C++, and more) so you can see which callees appeared, disappeared, or moved — instead of wading through buried line diffs. Built for AI-agent code review, it ships <code>diff</code>, <code>tree</code>, and <code>reach</code> commands plus machine-readable JSON output.</p>
<h2 id="what-is-calldiff-and-why-do-call-stack-diffs-matter-for-agentic-review">What Is CallDiff and Why Do Call-Stack Diffs Matter for Agentic Review?</h2>
<p>When an AI coding agent rewires call flow across a codebase, plain line diffs bury the shape of the change. You see dozens of removed and added lines, but the important question — <em>did the agent actually reroute this function to the intended new callee?</em> — stays hidden. CallDiff answers that question by diffing the call graph itself: which callees appeared, which disappeared, and which moved under an entrypoint.</p>
<p>The tool was created on 2026-08-07 by tanishqkancharla and already sits at 296 stars with 14 forks as of research on 2026-08-11 (GitHub API, api.github.com/repos/tanishqkancharla/calldiff). It is MIT-licensed, written in TypeScript, and installable via <code>npx calldiff@latest</code> or <code>npm install -g calldiff</code>.</p>
<p>The philosophy is an extension of the &ldquo;shape-of-the-change&rdquo; idea popularized by stacked-diff workflows. Jackson Gabbard&rsquo;s widely-cited post &ldquo;Stacked Diffs Versus Pull Requests&rdquo; argues that diff-shaped review beats PR-shaped review because engineers review the <em>shape</em> of a change, not just the file layout. CallDiff applies that same insight one level deeper: to the call graph, not the file diff.</p>
<h2 id="how-do-you-install-calldiff-and-what-are-the-three-commands">How Do You Install CallDiff and What Are the Three Commands?</h2>
<p>Installation is a one-liner. With Node.js installed, run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npx calldiff@latest
</span></span></code></pre></div><p>or globally:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npm install -g calldiff
</span></span></code></pre></div><p>On first use, CallDiff installs the tree-sitter grammars it needs into <code>~/.cache/calldiff/grammars</code>. You can override this location with the <code>CALLDIFF_GRAMMAR_CACHE</code> environment variable if you need a custom or shared cache path.</p>
<p>CallDiff exposes three commands:</p>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>What It Does</th>
          <th>Required Flags</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>diff</code></td>
          <td>Git-diff-shaped call-stack diff between two commits</td>
          <td>none</td>
      </tr>
      <tr>
          <td><code>tree</code></td>
          <td>Plain ASCII call tree of a single commit</td>
          <td><code>--entry</code></td>
      </tr>
      <tr>
          <td><code>reach</code></td>
          <td>All call paths from one symbol to another</td>
          <td><code>--entry</code> and <code>--to</code></td>
      </tr>
  </tbody>
</table>
<p>The <code>diff</code> command is the core. It compares two git refs (for example <code>main</code> and <code>feature</code>) and produces an output shaped like <code>git diff</code>: <code>-</code> means a callee that is gone from the &ldquo;from&rdquo; commit, and <code>+</code> means a callee that is new in the &ldquo;to&rdquo; commit.</p>
<h2 id="how-do-you-read-a-call-diff-output-ascii-call-trees-and---semantics">How Do You Read a Call-Diff Output: ASCII Call Trees and +/- Semantics?</h2>
<p>CallDiff prints colored ASCII call-stack trees by default. Each tree is rooted at an entrypoint, and the branches show which functions call which. When you run a diff, you get side-by-side or sequential trees where the +/- markers tell you precisely what changed in the call flow.</p>
<p>A minimal read: if a <code>-</code> appears under an entrypoint, that callee existed before and is now gone. If a <code>+</code> appears, a new callee was introduced. If a branch &ldquo;moved,&rdquo; you&rsquo;ll see a function appear under a different parent — the same symbol relocated in the call graph. That moved-branch signal is exactly what a line diff cannot show you, and it is the most valuable output for verifying an agent&rsquo;s work.</p>
<p>For agents and scripts, you can switch the output format with <code>--format json|yaml|md|jsonl</code>. JSON output is the most useful for programmatic consumption: you can pipe it into CI checks, feed it into a review agent, or write assertions that a specific callee did or did not appear in the new call stack.</p>
<h2 id="calldiff-vs-codiff-22-languages-vs-2">CallDiff vs Codiff: 22 Languages vs 2</h2>
<p>The closest direct competitor is codiff, a structural call-graph diff tool by issahammoud that is also built for coding agents. Both solve the same problem — showing what changed at the function/call level instead of the line level — but they diverge sharply on language support and ecosystem.</p>
<table>
  <thead>
      <tr>
          <th>Feature</th>
          <th>CallDiff</th>
          <th>Codiff</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Languages</td>
          <td>22 (TS, Python, Go, Rust, Java, C/C++, C#, Ruby, PHP, Kotlin, Swift, Scala, Lua, Elixir, Bash, Haskell, Zig, Solidity, OCaml, JS/JSX/TSX)</td>
          <td>2 (Python, TypeScript)</td>
      </tr>
      <tr>
          <td>Install</td>
          <td><code>npx calldiff@latest</code> / <code>npm install -g calldiff</code></td>
          <td><code>pip install codiff</code></td>
      </tr>
      <tr>
          <td>Language</td>
          <td>TypeScript</td>
          <td>Python</td>
      </tr>
      <tr>
          <td>Diff modes</td>
          <td><code>diff</code>, <code>tree</code>, <code>reach</code></td>
          <td><code>diff</code> (working tree vs HEAD, or <code>--base</code>/<code>--head</code>)</td>
      </tr>
      <tr>
          <td>Agent output</td>
          <td>`&ndash;format json</td>
          <td>yaml</td>
      </tr>
      <tr>
          <td>CI/action</td>
          <td>n/a (built on incur, MCP-ready)</td>
          <td>GitHub Action on Marketplace</td>
      </tr>
      <tr>
          <td>Stars (2026-08-11)</td>
          <td>296</td>
          <td>7</td>
      </tr>
      <tr>
          <td>Offline</td>
          <td>Yes (syntactic)</td>
          <td>Yes (no LLM, no embeddings)</td>
      </tr>
  </tbody>
</table>
<p>The single strongest objective advantage is breadth: 22 languages versus codiff&rsquo;s 2. In a polyglot 2026 codebase, that is the difference between a tool you can standardize on and one you can only use in isolated corners. Codiff compensates with Mermaid diagram output for PR descriptions and a ready-made GitHub Action, and both are fully offline and syntactic. But if your team touches Python <em>and</em> TypeScript <em>and</em> Go, CallDiff&rsquo;s 22-language reach is decisive.</p>
<h2 id="is-calldiff-agent-first-json-llms-skills-add-and-mcp">Is CallDiff Agent-First? JSON, &ndash;llms, skills add, and MCP</h2>
<p>CallDiff is designed to be consumed by AI agents, not just humans. That agent-first orientation shows up in several concrete features:</p>
<ul>
<li><strong><code>--format json|yaml|md|jsonl</code></strong>: machine-readable output so an agent or CI script can parse the call-flow diff directly.</li>
<li><strong><code>--llms</code></strong>: an incur-native flag that emits an LLM-friendly rendering of the tool&rsquo;s help and behavior.</li>
<li><strong><code>skills add</code> and <code>mcp add</code></strong>: CallDiff builds on the incur CLI framework (wevm/incur, 594 stars, TypeScript), which lets you register CallDiff as an MCP server or add it as an agent skill.</li>
<li><strong>CTAs after diffs</strong>: incur prints call-to-action prompts after diffs, guiding the next review step.</li>
</ul>
<p>The underlying framework, wevm/incur, describes itself as a &ldquo;CLI framework for agents and humans.&rdquo; That dual target is the whole point: CallDiff is built to slot into agent toolchains as easily as it sits in a human developer&rsquo;s terminal. The tool even nudges users to have agents walk through their changes — the prompt is &ldquo;dearest clod, walk me through the code changes you made using <code>npx calldiff@latest</code>.&rdquo;</p>
<h2 id="what-are-calldiffs-realistic-limitations">What Are CallDiff&rsquo;s Realistic Limitations?</h2>
<p>CallDiff is syntactic (AST-based via tree-sitter), not a full typechecker. That design choice buys speed, error tolerance, and 22-language breadth, but it carries real limits you should know before trusting it blindly:</p>
<ul>
<li><strong>Dynamic calls won&rsquo;t resolve.</strong> If a function is called through a variable, dispatch table, or reflection, the AST has no static binding to follow, so CallDiff cannot trace it.</li>
<li><strong>Entrypoint inference is conservative.</strong> CallDiff only reports entrypoints whose expanded call trees changed, and it catches exported functions — not every internal helper.</li>
<li><strong>Grammars install on first use.</strong> The first run can be slow while tree-sitter grammars download into the cache; plan for that in CI.</li>
</ul>
<p>These are the standard trade-offs of static call-graph extraction. CallDiff is a review aid, not a runtime profiler. It tells you what the code <em>says</em> is called at a structural level; it does not tell you what is actually executed under load. For verifying agent rewiring, that is usually exactly what you want — a fast, deterministic, offline check of call-flow intent.</p>
<h2 id="a-walkthrough-verifying-an-agent-rewired-a-call-flow-across-commits">A Walkthrough: Verifying an Agent Rewired a Call Flow Across Commits</h2>
<p>Here is the practical workflow that makes CallDiff shine. Imagine an agent claimed it moved authentication logic from a legacy <code>auth/</code> module into a new <code>iam/</code> service, and you want to verify the rewiring without reading 200 lines of diff.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># 1. Install</span>
</span></span><span style="display:flex;"><span>npx calldiff@latest
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2. Diff the two commits you care about</span>
</span></span><span style="display:flex;"><span>calldiff diff main feature
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3. Machine-check the result in CI or from an agent</span>
</span></span><span style="display:flex;"><span>calldiff diff main feature --format json | jq <span style="color:#e6db74">&#39;.entrypoints[].callees&#39;</span>
</span></span></code></pre></div><p>In step 2 you read the ASCII call tree: you should see <code>-</code> markers under the old <code>auth.authenticate</code> entrypoint and <code>+</code> markers under the new <code>iam.authorize</code> entrypoint, with the callee branches relocated. That relocation is the proof the agent actually rerouted the flow. In step 3 you can automate the assertion: check that no <code>-</code> remains under <code>iam.authorize</code> and that the expected new callee appears.</p>
<p>For a full review loop, hand the tool to an agent: paste &ldquo;dearest clod, walk me through the code changes you made using <code>npx calldiff@latest</code>&rdquo; and let it produce a call-flow walkthrough from the structured output.</p>
<h2 id="who-should-use-calldiff-and-how-does-it-fit-a-2026-review-stack">Who Should Use CallDiff and How Does It Fit a 2026 Review Stack?</h2>
<p>CallDiff is for two audiences:</p>
<ol>
<li><strong>Teams reviewing AI-agent changes.</strong> If your workflow includes agents rewriting call flow, line diffs are no longer enough. CallDiff surfaces whether the call graph was rewired as intended — the check that matters most.</li>
<li><strong>Polyglot teams that want one review tool.</strong> With 22 languages, you can standardize call-graph review across Python, TypeScript, Go, Rust, Java, and more, where codiff only covers Python and TypeScript.</li>
</ol>
<p>It fits naturally alongside your existing review stack: use <code>git diff</code> for the file-level shape, CallDiff for the call-graph shape, and CI assertions over the JSON output for automated verification of agent changes. It is MIT-licensed, offline, syntactic, and free — the only costs are the first-use grammar download and the honest caveat that dynamic calls stay invisible.</p>
<p>If you are reviewing agent-produced rewiring in 2026, CallDiff is the fastest way to see who-calls-whom change between commits.</p>
<h2 id="faq">FAQ</h2>
<p><strong>What is CallDiff?</strong>
CallDiff is an open-source CLI that diffs function call stacks between two git commits, &ldquo;like git diff, but for who-calls-whom.&rdquo; It uses tree-sitter AST parsing to compare call graphs across 22 languages and is built for agentic code review.</p>
<p><strong>How do I install CallDiff?</strong>
Run <code>npx calldiff@latest</code> or <code>npm install -g calldiff</code>. It is MIT-licensed and written in TypeScript. On first use it downloads the tree-sitter grammars it needs into <code>~/.cache/calldiff/grammars</code>.</p>
<p><strong>What languages does CallDiff support?</strong>
22 languages: TypeScript, TSX, JavaScript, JSX, Python, Go, Rust, Java, Ruby, C, C++, C#, PHP, Kotlin, Swift, Scala, Lua, Elixir, Bash, Haskell, Zig, Solidity, and OCaml.</p>
<p><strong>How is CallDiff different from codiff?</strong>
CallDiff supports 22 languages versus codiff&rsquo;s 2 (Python and TypeScript), and at research time had 296 stars versus codiff&rsquo;s 7. Codiff adds Mermaid output and a GitHub Action; CallDiff adds JSON/YAML/MD/JSONL output, <code>tree</code> and <code>reach</code> commands, and MCP/skills integration via the incur framework.</p>
<p><strong>Does CallDiff resolve dynamic calls?</strong>
No. CallDiff is syntactic (AST-based), not a full typechecker, so dynamic or dispatched calls won&rsquo;t resolve. It&rsquo;s best used as a fast, offline check of static call-flow intent, not as a runtime profiler.</p>
]]></content:encoded></item></channel></rss>