Local code navigation for AI agents
Give your coding agent a map.
PhoenixCodeNav helps Claude Code, Codex, and other MCP clients navigate large C# workspaces—locally, efficiently, and with every answer labeled by confidence.
It is the connection that lets your coding agent use local tools. Phoenix runs behind the agent—it is not another editor or chat app.
“What breaks if I change InvoiceService?”
- ✓Find the definitionexact
- ✓Trace its callersexact
- ◫Suggest likely test leadsheuristic
One symbol, two very different journeys
Grep finds the word.
Phoenix understands the symbol.
Text search is great when you need text. But a coding agent also needs definitions, dependency direction, callers, and the smallest useful source span.
Keep both. Phoenix complements your editor and rg; it gives agents the structured path those tools do not.
Start with what you want to know
Ask the repo a
better question.
You do not need to memorize the tool names. Teach your agent the intent; Phoenix supplies a small, line-addressable answer.
“Where is this defined?”
Jump to the owning declaration and the exact source span instead of opening five possible files.
definition
“Who uses it?”
Follow references across projects with compiler-checked results whenever the semantic layer is available.
references
“What could this change break?”
Summarize dependent projects, change surface, and coupling risks before the edit becomes a surprise.
impact
“Which tests matter?”
Surface related test leads beside the symbol and its project neighborhood.
related_tests
“Which project owns this file?”
See which project compiles the file instead of guessing ownership from folder names.
projects_containing
“Help me review this change.”
Turn changed symbols into a compact review map with context, risks, and test leads.
review_pack
Trust is part of the response
Three depths.
No false certainty.
Phoenix uses the cheapest layer that can answer the question, then labels the result so your agent knows whether it has a fact or a lead.
Find the words
Fast ranked text search over the persisted local index. Best for config keys, routes, errors, and literal text.
SQLite FTS · ranked · budgetedSee the structure
Roslyn parses types, members, signatures, and spans so the agent can inspect an outline before reading source.
syntax map · file spans · no compileProve the connection
Lazy Roslyn compilations resolve definitions, references, implementations, and call graphs with compiler semantics.
compiler-verified · bounded coverageA heuristic result is a lead to verify—not a fact in disguise. Partial, stale, or bounded coverage is reported too.
From syntax to meaning
How an agent turns
var into a fact.
This is a real example from Phoenix’s pinned Roslyn test repository. The agent starts with var newCompilation, resolves the exact method call in a semantic snapshot, and separately reads bounded live source context. From those labeled pieces of evidence — plus the C# rule for await — it can explain the variable’s type without guessing from text.
-
01
The question in the code
varhides the answer from plain text.The call site says what happens, but not which overload the compiler chose or what
newCompilationmeans. A text search forGetCompilationAsyncreturns declarations and calls across the repository; the agent still needs the identity attached to this exact token.Roslyn · real source, shortened 39 | public RegularCompilationTracker UnderlyingTracker { get; } | 123| var newCompilation = await | UnderlyingTracker.GetCompilationAsync( | compilationState, cancellationToken) | .ConfigureAwait(false); | 136| newCompilation = newCompilation.ReplaceSyntaxTree( | existingSyntaxTree, replacementSyntaxTree); -
02
Address the token, not the spelling
The agent asks about one call in one snapshot.
definitionaccepts the real workspace-relative path, 1-based line, and 1-based column. The optional name is an additional guard on a line that also declares a local variable.mode: "semantic"forbids a silent indexed guess, whileincludeBodyreturns the live declaration and its written return type.MCP · compiler-semantic definition request definition( name: "GetCompilationAsync", path: "src/Workspaces/Core/Portable/Workspace/Solution/" + "SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs", line: 123, column: 58, mode: "semantic", includeBody: true, timeoutMs: 30000 ) -
03
The evidence chain
Small facts compose into code understanding.
Compile ownership comes from the index; a bounded live source read supplies the declared receiver type. Roslyn then binds the call to one symbol:
RegularCompilationTracker.GetCompilationAsync. Its declaration returnsTask<Compilation>; C#awaitunwraps that task, so the agent can state thatnewCompilationis aCompilationand explain why.Agent reasoning · every arrow has evidence UnderlyingTracker └─ declared type → RegularCompilationTracker └─ exact call → GetCompilationAsync(...) └─ return type → Task<Compilation> └─ await unwraps → Compilation └─ therefore → newCompilation : Compilation Follow-on check: newCompilation.ReplaceSyntaxTree(...) └─ receiver remains → Compilation -
04
The compiler-backed result
The response carries identity, source, and provenance.
The real integration case separately asserts the compiler-bound containing type, declaration path,
Task<Compilation>signature, exact confidence, semantic navigation layer, and the live freshness of each source read. The representative envelope below uses the production field names and is parsed by the website gate so this explanation cannot drift into a fictional API.definition · representative response { "name": "GetCompilationAsync", "symbol": { "display": "Microsoft.CodeAnalysis.SolutionCompilationState.RegularCompilationTracker.GetCompilationAsync(Microsoft.CodeAnalysis.SolutionCompilationState, CancellationToken)", "kind": "method", "containingType": "RegularCompilationTracker", "ns": "Microsoft.CodeAnalysis", "assembly": "Microsoft.CodeAnalysis.Workspaces" }, "declarations": [ { "path": "src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs", "startLine": 216, "endLine": 233 } ], "body": { "path": "src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs", "startLine": 216, "endLine": 233, "source": " 216| public async Task<Compilation> GetCompilationAsync(...)", "truncated": false, "freshness": "live" }, "timing": { "deadlineMs": 30000, "elapsedMs": 54 }, "meta": { "indexStatus": "ready", "indexVersion": "7f4c2a9d18e64b3a92c01d5f6e8a7b40", "pendingChanges": 0, "confidence": "exact", "navigationLayer": "semantic", "build": "0.12.55+7b0b8112028b", "indexSchema": "28", "indexMode": "daemon" } } -
05
The honest boundary
Understanding is a proof trail, not a magic label.
Phoenix does not claim that
definitiondirectly performs full expression inference for arbitrary C#. The agent composes a compiler-bound member identity, a separately read live declaration body, receiver context from another bounded live read, and a language rule. If the project cannot be loaded or the token cannot be resolved, the tool returns explicitsemantic_unavailableor partial evidence instead of inventing the type.Agent conclusion · explainable and bounded What I can say: newCompilation is Compilation. Why: receiver declaration → RegularCompilationTracker compiler-bound method → Task<Compilation> C# await rule → Compilation What I cannot say: “Phoenix inferred every arbitrary expression type.” Evidence: indexed ownership text · live receiver context exact · semantic call binding separately read · live declaration body
Fast feedback without frozen promises
Progress you can see.
Confidence you can use.
Repository shape and hardware decide timings. Phoenix reports live progress, freshness, and bounded coverage instead of pretending one benchmark fits every workspace.
phase · files · throughput
Measured on your machine, for your repositoryedits, additions, and deletes update the index
compare indexed state with the repository commit
compile only the project clusters an agent needs
compact, line-addressable context stays focused
every agent on a workspace joins one shared runtime — one index writer, one watcher, one warm semantic estate — transparently, with nothing to configure
early-access loopback view of observed instances across up to eight configured workspaces, with index health and available live build progress — setup guide ↗
From source to first answer
Three steps.
One new superpower.
Build the documented self-contained Windows executable from source, connect it once, and let the index warm in the background.
-
01
Build it
Create the local server.
Clone the repository and publish the complete self-contained
win-x64output. Keep the generated directory together: it contains the executable, its adjacentFSharp.Core.dllreference sidecar, and theportal/companion. Building from source requires the .NET 10 SDK.PowerShell git clone https://github.com/grlap/PhoenixCodeNav.git cd PhoenixCodeNav dotnet publish src/CodeNav.Mcp -c Release -r win-x64 --self-contained ` -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true ` -p:IncludeNativeLibrariesForSelfExtract=true -o artifacts/win-x64 -
02
Connect it
Give your agent the key.
Point your MCP client at the executable you just built and the repository it should map. Put
.mcp.jsonin that target repository's root; there,.means the repository itself..mcp.json { "mcpServers": { "phoenix": { "command": "C:\\path\\to\\PhoenixCodeNav\\artifacts\\win-x64\\ PhoenixCodeNav.Mcp.exe", "args": [ "--workspace-root", "." ] } } } ~/.codex/config.toml [mcp_servers.phoenix] command = "C:\\path\\to\\PhoenixCodeNav\\artifacts\\win-x64\\ PhoenixCodeNav.Mcp.exe" args = [ "--workspace-root", "C:\\path\\to\\repo", ] -
03
Ask it
Start with orientation.
Add
.codenav/to your repository’s.gitignore, attach the provided agent instructions, and begin with a simple request.YouUse Phoenix to map this repository before we change anything.
AgentI’ll check
repo_overview, index freshness, and project structure first.Phoenix connected · index builds in background
Local server, honest boundary
A local server.
An honest boundary.
PhoenixCodeNav runs locally; there is no hosted Phoenix service. Every agent you attach converges on one shared Phoenix daemon per workspace — elected and rejoined automatically, never configured. It reads your C# workspace, serves bounded results to each MCP client, and leaves tracked source files and Git refs unchanged. It does write local indexes under .codenav/.
Like other Git tooling, repository configuration still matters: Git may invoke configured helpers or fetch missing objects in a partial clone.
Important: your attached AI client may transmit returned context under its own data policy. Phoenix cannot control that boundary.
Complement, do not replace
One toolbox.
Three strengths.
Use rg
For logs, generated output, unindexed file types, and raw text outside the indexed workspace. Phoenix also indexes Markdown and SQL for bounded text search.
Use your editor
For human exploration, refactoring UI, diagnostics, debugging, and writing the actual change.
Use Phoenix
When an agent needs ranked C#/F#/Markdown/SQL text search, C# structure and ownership, dependencies, or compiler-backed symbol facts.
Good questions before you start
Does Phoenix support every language?+
No. PhoenixCodeNav is C#-first, with deliberately bounded F# support: .fs/.fsi declarations support indexed symbol-name search across at most 64 owner-aware contexts per file, compile-owned files get syntax outlines, and a bounded same-project semantic layer answers position lookups and definitions. Truncated indexed contexts and affected owners are disclosed as partial coverage. Markdown and SQL are indexed for text navigation only. Everything beyond those bounds is labeled unsupported instead of returning a misleading empty answer.
Is every answer compiler-exact?+
No—and that honesty is a feature. Semantic answers are exact when the required Roslyn cluster and references load. Otherwise Phoenix labels indexed, heuristic, partial, or stale coverage so the agent can verify or widen deliberately.
Does it require MSBuild to load my solution?+
No. Phoenix builds lazy Roslyn workspaces directly from parsed project facts. Building Phoenix from source requires the .NET 10 SDK; exact legacy semantics may also need .NET Framework reference assemblies.
What if I run five agents on one repository?+
They share one Phoenix daemon per workspace. The first launch elects it; every later agent joins it transparently through a lightweight proxy — no flags, no topology to learn. One index writer, one file watcher, and one warm compiler estate serve every session, so each additional agent costs far less than another full process. And when startup cannot succeed, the tools stay alive and report a typed, actionable cause instead of presenting a dead server.
Will it edit my repository?+
It does not edit tracked source files, apply code changes, or change Git refs. It writes local indexes under .codenav/, including inside an existing worktree you explicitly ask it to index; those files should be ignored by Git.
Ready for unfamiliar C# codebases
Stop hunting.
Start navigating.
Follow the source setup, attach PhoenixCodeNav to your coding agent, and give every unfamiliar C# repository a map.