Initial launch: Nuanced call graph context layer for AI coding tools

February 19, 2025

We're excited to announce the initial launch of Nuanced, an open-source Python library that provides LLMs with precise call graph context. By analyzing function relationships, we generate a structured representation of code dependencies. This is our first step toward building a richer context layer that can help AI coding assistants make more informed decisions about your codebase.

Why AI coding needs relevant context

AI coding assistants are surprisingly primitive when it comes to understanding code structure. The LLMs underlying them The LLMs powering these assistants have no equivalent to the Language Server Protocols (LSPs) that developers take for granted — they can't jump to definitions, find references, or understand type hierarchies.

Instead, they examine source code as chunks of text (tokens) with a limited context window, and use embeddings — vector representations that capture statistical patterns but don't preserve actual program structure.

This lack of "dev tools for AI" creates a significant gap: while they excel at pattern matching and local transformations, they lack the fundamental program analysis capabilities that compilers and developers use. These capabilities include following control flow, understanding data dependencies, and reasoning about runtime behavior.

This means when an LLM suggests changing a function's signature or behavior, it can't reliably identify which other parts of the codebase depend on that function or might break as a result of the change. They struggle with basic questions like "what will break if I change this return type?" or "which components depend on this function?" because they lack real semantic understanding of the codebase.

The solution isn't about overwhelming LLMs with all possible context — it's about identifying and providing the most relevant context for each specific task. We can do this by precisely extracting the function relationships and dependencies that matter for a given modification.

Introducing Nuanced CodeGraph

Nuanced leverages static analysis to extract call graphs from your codebase. Rather than relying on the limited context windows or embeddings used by current AI tools, we parse the AST to build a traversable graph of function relationships. The result is structured, semantic information that captures actual program behavior.

The library provides two main interfaces:

  • init for generating the call graph
  • enrich for querying specific functions.

init: initializing the call graph

# Create a call graph for your module
$ nuanced init .

The init command analyzes Python files in the specified directory, creates a .nuanced directory to store analysis results where the full call graph is written to a file called nuanced-graph.json, and returns a CodeGraphResult with either the graph or any errors encountered.

enrich: querying function relationships

# Find what a specific function calls
$ nuanced enrich app/helpers.py format_data
{
  "app.helpers.format_data": {
    "filepath": "/app/helpers.py",
    "callees": [
      "<builtin>.dict",
      "app.utils.validate_input",
      "<builtin>.str"
    ]
  }
}

The enrich command takes two arguments: (1) the path to the Python file containing your function, and (2) the function name (just the name, not the fully qualified name), and returns an EnrichmentResult containing the function's call graph when found, and any errors encountered (e.g., ValueError when multiple matching functions exist). Unlike the result of init, which is written to a file, the result of enrich is held in memory.

This gives AI tools access to the same structured program understanding that developers rely on—actual call paths and dependencies rather than probabilistic guesses from embeddings or regex matches.

By extracting function call relationships, Nuanced can help AI coding tools resolve imports, and maintain a structured graph that can be queried efficiently.

What Nuanced provides today

This initial release focuses on:

  • Call graph generation: create a queryable JSON representation of function relationships
  • Function discovery: find specific functions and their dependencies
  • Simple CLI: Easy-to-use commands for exploring code structure

Get started

Nuanced is supported for Python versions >= 3.8.

# Install
$ uv tool install nuanced

# Initialize graph for current directory
$ cd your_project
$ nuanced init .

# Query specific functions
$ nuanced enrich path/to/file.py function_name

Graph updates

Nuanced call graphs can be updated whenever they're most useful to you. You might have them update automatically in your commit hooks, run them manually while debugging, or set them up as part of your CI pipeline. For example, you might update the call graph while investigating a complex dependency chain, when refactoring a module's interface, or during code review to visualize recent changes. The library lets you capture relationships in your code without disrupting your development process.

Running Nuanced

Nuanced runs anywhere you've got Python 3.8+ installed. No special dependencies, no complex setup — it works the same way whether you're coding on your laptop, running it in CI, a sandbox, or deploying it to a cloud environment. The lightweight design means you can drop it into any Python project without worrying about compatibility or environment-specific configurations.

Since Nuanced runs entirely in your environment and never sends data externally, you maintain complete control over your code analysis. Whether you're working with proprietary code or sensitive projects, you can generate call graphs without any data leaving your systems. The library's minimal requirements ensure consistent call graph generation across all these environments with simple setup and installation.

Architecture: Building on JARVIS

When we started building Nuanced, we needed a solid foundation for Python call graph generation. After evaluating several tools (pycg, tree-sitter-stack-graphs, Glean, scip-python, and pytype), we chose JARVIS as our starting point.

Anyone who's tried to build static analysis for Python knows the challenges: dynamic imports, monkey patching, decorators that transform functions, and metaprogramming can all confuse static analyzers. JARVIS handles these Python quirks better than most tools we evaluated:

  • It correctly resolves most import patterns (even the weird ones)
  • It tracks calls through variables and attributes reasonably well
  • It preserves enough context to reconstruct fully qualified names

In our tests with real codebases, pycg would regularly miss important connections or time out on larger projects, while JARVIS maintained good performance. It's not perfect—no static analyzer for Python can be—but it gave us a practical foundation to build upon.

We've extended JARVIS with several practical improvements:

  • Better error handling for malformed Python
  • Consistent function identification across different parts of the graph
  • Path resolution that works with how developers actually navigate projects
  • A simpler query interface designed specifically for AI tool integration

Our goal wasn't to create the perfect static analyzer, but to build something that works well enough in practice to give AI tools better context than they have today.

Roadmap

We’re building towards a more comprehensive AI-powered code analysis toolkit. Future work includes:

  • Function purity analysis: detecting state modifications.
  • Code complexity metrics: highlighting refactoring needs.
  • Type inference: extracting parameter and return types.
  • Dead code detection: finding unused functions.
  • Data flow tracking: mapping variable transformations across function calls.

Help shape the future

We’re focusing on precise function-level analysis and evolving towards runtime insights. We want your feedback—what context do your AI tools need? What problems are you facing when navigating large codebases?

Nuanced is open-source and built for both human developers and AI tools. We welcome you to:

Connect with us on X or email ayman@nuanced.dev.