Short answer
A language server resolves types, so its "who calls this" is more exact than a syntax graph's. It also needs one running server per language and answers one cursor position at a time. Pixel is one binary for every language its graph parses, adds your Git history, and says when an answer may be incomplete: static analysis never sees every dynamic call, and every graph answer carries that warning.
Side by side
Not benchmarked. No figure: how Pixel and a language server work, side by side. Nothing on this page is a measurement.
| Measure | Pixel | Language server |
|---|---|---|
| Callers and references | From a syntax graph, marked when incomplete | Type-resolved, more exact |
| Languages | One binary for all of them | One server per language |
| Question shape | A symbol, a file, a task | One cursor position |
| Git history | Yes | No |
Where a language server wins
It resolves types, so its callers and references are more exact than a syntax graph's.
How they differ
A language server answers from resolved types, for one language and one cursor position at a time, inside the editor that started it. Pixel answers from a syntax graph parsed with tree-sitter, every language it knows in the same index, and takes a symbol name, a file or a task description: pixel who-calls, pixel impact, pixel scope-task. Its graph answers carry an epistemics object that says what static analysis could not see.
Choosing
Use the language server for exact references in one language, a rename your editor drives, or type errors. Use Pixel when an agent in a shell needs callers, blast radius or history across a repository, with no server to start per language.