The “cheapest tool that answers the question” principle is probably the most practical takeaway here. An agent doesn't need deeper semantic understanding for every lookup, and using an expensive project-wide tool for simple symbol discovery can waste both latency and context. Treating code navigation as an escalation path, from local structure to project relationships, feels like a much better fit for agent workflows.
The entire approach is an older style of navigating codebase. A MCP server like repowise or graphify is replacing the LSP server these days. The MCPs use an indexing algorithm to expose entities to any LLM tool.
The entire process totally depends on the sophistication in the indexing layer.
Also, would love to hear your thoughts on AST vs code-specific embeddings like voyage3 in crawling the codebase?
Really interesting perspective on how coding agents understand and work with code. The idea that different levels of code reading are needed for better reasoning, navigation, and problem-solving highlights the complexity behind building truly useful AI developer tools. I enjoyed how you broke down the importance of context and depth when analyzing code. Great insights for anyone interested in the future of AI-assisted programming!
interesting perspective , most of the similar things i have read in one more course called RAMP, where A stands for agentic or agents,
The detail I want to underline is find_symbol returning a 1-based position "specifically so that position can be fed straight into goto_definition". Models really are bad at deriving line/column from a text dump, and making the cheap tool emit coordinates for the expensive one is the cleanest fix I have seen written down. One more property of tree-sitter worth naming for this use case: its error recovery. Mid-edit files parse to a tree with error nodes instead of failing, so find_symbol keeps working while the agent is halfway through a refactor, exactly when the language server starts complaining. On your open question about invalidation: pyright republishes diagnostics on didChange without a didOpen round trip, so a thin didChange with a debounce may get you fresh diagnostics cheaper than reopening files. Did you consider caching find_references results, or is the staleness risk after edits too high to bother?
The idea that a coding agent needs several different ways to read code matches what I see: keyword search, structural parsing, and semantic retrieval each catch what the others miss. I lean on the structural view most when the agent needs to reason about what calls what, and on retrieval when it needs intent. Nice articulation of why one representation is never enough.
Julian Neagu
500+ AI tools shipped solo. Founder of VisionVix.
The “cheapest tool that answers the question” idea is the part I’d keep. Agents waste a lot of context when they treat every code lookup like a file read. Tree-sitter for local stuff and LSP for relationships feels like the right split.