PlatformFinding things

Code health and dependencies

Trace dependencies, callers, paths, and blast radius; inspect cycles, unused code, complexity, contradictions, drift, scan history, and trends.

what would break if I change this function?

Callers and dependents, from the graph.

show me this project's code health

Circular dependencies, unused code, and complexity hot spots.

is anything still using the legacy client?

Every dependent, or an honest nothing.

You can ask about the change you want to make. The assistant should recognize when a text lookup is not enough and inspect relationships, callers, and blast radius without waiting for you to name the graph operation.

Text search finds the name. A graph knows the relationship. "What calls this" is a different question from "what mentions this", and only one of them is safe to base a refactor on.

What it reports

Relationships around one change

QuestionWhat the graph can return
What does this depend on?Direct and, when useful, transitive dependencies
What uses this?Reverse dependencies and every known usage of a module, function, type, constant, or component
What extends or implements this?The types that extend, implement, or hold a type, and the functions that name it
How does A reach B?A path between two graph nodes, or between two pieces of saved knowledge
Who calls this function?A bounded call path
What is related?Everything linked to a decision, plan, task, doc, ticket, or handoff, and the code it names
What would this change affect?Impact and blast radius for a modification, rename, signature change, or deletion
Why was this area shaped this way?The decisions, lessons, tasks, and docs that refer to a file, function, or type

Project-wide health

SignalWhat it means
Circular dependenciesCycles between modules—the reason a “small” change spreads
Unused codeFunctions, types, modules, and constants nothing calls, extends, implements, names, or reads
ComplexityLong or highly branching functions that deserve inspection
ContradictionsSaved knowledge that conflicts with other current context
Code driftAreas where code and the recorded project understanding have diverged

Using it before a refactor

The order that saves time:

  1. Search for the exact symbol or area so the target is unambiguous.
  2. Check reverse usages and blast radius. If it is larger than expected, that is the first finding.
  3. Trace the important call or dependency path rather than opening every related file.
  4. Check cycles, drift, and linked decisions in the area.
  5. Treat unused code as candidates, then verify before deleting.

A refactor with a real blast radius

Suppose you want to change verifyToken so it returns a typed failure instead of a boolean. An exact source search identifies the symbol; the graph answers the questions that decide whether the change is small:

  1. Which middleware, background jobs, tests, and command-line paths call it?
  2. Is there a call path from the public request handler to the verifier through wrappers whose names never mention tokens?
  3. Which modules depend on the current return type?
  4. Does the auth package already participate in a cycle that this change could deepen?
  5. Is there a linked decision explaining why one caller bypasses the normal middleware?

If the graph shows twelve callers rather than the expected two, split the work or write a plan before editing. After the refactor, rerun the same checks and save a new quality snapshot. The useful comparison is not “the build passed”; it is “all known callers moved, no new cycle appeared, and the baseline did not regress.”

An “unused” verifyLegacyToken result still needs inspection. It may be loaded by reflection, called through an interface, or used only by an external consumer. The graph supplies a candidate and its known relationships, not a guarantee that deletion is safe.

Calls across services

Within one project, a call path does not stop where one service hands work to another. The graph links:

  • An HTTP request to the route that serves it. When the method and path are in the source, as a literal or a constant, the request links to the handler registered for them. A base URL read from configuration is fine; the path is what has to match.
  • A published event to its consumers. A publish links to the handlers subscribed to the same topic, queue, subject, event class, or job.
  • An in-process signal to its listeners, such as an Unreal delegate, a Swift notification, a Laravel event, a Sidekiq job, or a Roblox remote event.

Each path says how every step is made:

Code
Purchase -> Complete -> GrantItems =http POST /inventory/grant=> Grant -> GrantInventory
Purchase -> Complete =event purchase.completed=> OnPurchaseCompleted -> RecordPurchase

Paths cross languages too. A TypeScript front end calling a C# API that publishes to a Python worker is one path, and so is a Roblox purchase that ends in a Go inventory service.

The graph does not link:

  • Services in different projects. Index the services together to trace across them.
  • A route or event name the source never spells out, because it is assembled at run time from configuration or input.
  • An ambiguous match. When two routes answer a request equally well, no link is drawn rather than a guess.
  • gRPC, GraphQL, and queues bound only in infrastructure configuration.

Types and constants

Besides calls, the graph records how types relate and where constants are read:

  • A type extends or implements another. A class and its base class, a class and the interfaces it implements, a Rust impl Trait for Type, a Go struct and the types it embeds, a Ruby class and the modules it includes.
  • A type holds another. A field, property, or constructor property of another project type.
  • A function names a type. In its signature or its body, for example by constructing it.
  • A function reads a constant. Module-level constants and globals, and static members, such as Rust const, a Go package var, a Java static final field, or a C #define.

So “what implements Repo?”, “what breaks if I change Order?”, and “is MAX_RETRIES still used?” have answers. A name is matched to the type or constant it means the way the language scopes it: the same file, then the same directory or package, then what the file imports. When two candidates remain, nothing is linked rather than a guess.

Why code is the way it is

Ask for the decisions about a file, function, or type, and the assistant returns the saved knowledge that refers to it:

  • decisions, lessons, and constraints that record a reference to the code, or name it, its file, or a distinctive symbol name;
  • tasks and notes with a reference to it;
  • docs that name its file or its qualified name.

Recorded references rank first. Impact analysis lists the team's decisions, lessons, and constraints about its target, so a change shows its reasons along with its blast radius. Personal notes appear only for their owner.

The knowledge graph

Saved knowledge is a graph of its own. From any decision, lesson, plan, task, note, doc, ticket, or handoff, the assistant can list what links to it, and find the chain of links between two of them:

  • relations between pieces of knowledge, and which decision superseded which;
  • the events a piece of knowledge was learned from;
  • the tasks of a plan, and the tickets under an epic;
  • what a plan or a handoff lists;
  • the code a decision or task refers to.

A walk never passes through an item you cannot see, such as another person's personal note or a project you do not have access to.

Languages

“Full” means functions, calls resolved the way the language scopes them (packages, imports, and the type a method is called on), types with what they extend, implement, and hold, constants with the functions that read them, and file imports.

LanguageGraphHTTP and events covered by tests
GoFullchi, net/http requests, NATS
C#FullASP.NET Core controllers and minimal APIs, HttpClient, MassTransit
JavaFullSpring MVC, OpenFeign, Spring Kafka
KotlinFullKtor server and client, Spring Kafka
PythonFullFastAPI, requests, kafka-python, Faust
PHPFullLaravel routes, the Http client, Laravel events and listeners
RubyFullRails routes, Faraday, Sidekiq
C++FullUnreal IHttpRequest and delegates, cpp-httplib
SwiftFull, without file importsVapor, URLRequest, NotificationCenter
LuaFull, without typesRoblox remotes, ProcessReceipt, HttpService
TypeScript, JavaScriptCalls matched by nameExpress, NestJS, fetch, axios, Kafka
RustCalls matched by nameaxum, reqwest, NATS
CFunctions, calls, types, constants, and includes—

Other frameworks with the same shapes usually link too; the table lists what the test suite proves.

Ask the assistant to save a code-health baseline after a meaningful scan or cleanup. Later scans can show whether cycles and complexity are going up or down over a quarter — which turns "the codebase feels worse" into a number.

There are three different time views:

  • Freshness says whether the dashboard cache is current enough to trust.
  • History lists saved scan runs and their state.
  • Trends compare counts over time.

A saved snapshot makes a deliberate baseline. It does not refresh the source index by itself.

Building and refreshing the graph

The graph is derived after source indexing. A new project or a large batch of changes may need graph ingestion before relationship queries are complete. Check freshness before treating an empty result as proof that no dependency exists.

Repository text remains the authority for a newly edited file that has not been indexed yet.

Believing "unused"

Reflection, dynamic dispatch, and code called only from outside the repository can look unused. So can a type used only through a name the graph could not tie to one definition, or a constant read only by code outside any function. Treat the list as candidates, not a delete queue — check the blast radius of each before removing it.

If it doesn't work

Empty results on a new project. The graph builds after indexing. Give it a few minutes, then rerun.

It missed a caller. Dynamic dispatch and reflection aren't traceable statically. The graph is a strong signal, not a proof.

A call path stops at an HTTP call or a queue. Check that both services are in the same project, that the request's path or event name appears in the source, and that only one route matches it. Then connect the remaining hop with search.

Complexity flags code I'm happy with. It measures shape, not quality. A long switch statement is fine; it just measures long.

A dashboard count differs from the code I just changed. Check freshness and the latest scan history, refresh the index and graph, then compare again.

A diagram disagrees with the graph. The diagram is a deliberately saved model; the graph is derived from indexed code. Verify the current source and update the stale record.

Next