All writing

Claude Code doesn't need to search harder. It needs to see the code.

Claude Maxxing, part 3: give Claude Code a language server, so it finds code by what it is instead of by matching text or trusting line numbers that went stale.

On this page
  1. 01How Claude Code finds code today
  2. 02The fix: a language server
  3. 03Why not just search better?
  4. 04Set it up
  5. 05Check it worked
  6. 06The one rule I add to every project
  7. 07Gotchas
  8. 08What it doesn't fix
  9. 09Next in Claude Maxxing

Every line number in the task notes was wrong.

Not one or two. All of them. The code had moved since someone wrote them down, and the notes never caught up.

A person would notice in a minute. An agent that trusts the notes reads the wrong lines, then writes a confident explanation of code that isn't there anymore.

In part 1 I gave Claude a desk. In part 2 I gave it a memory. This post gives it eyes: a way to find code by what it is, not by what the text looks like.

How Claude Code finds code today

Out of the box, Claude Code finds code the way you'd press Ctrl+F. It searches for matching text.

That works until it doesn't. Say your app has a function called getUser, and you ask: "Where is getUser used?"

A text search returns:

  • The real calls to getUser.
  • getUserSettings, because it contains the same letters.
  • A comment that says "TODO: getUser is slow".
  • A different getUser in another file that has nothing to do with yours.

And it can miss a call that's there, if the code reaches the function under another name.

None of this throws an error. The agent just gets a slightly wrong picture, and builds on it.

The fix: a language server

A language server is the program behind "go to definition" and "find all references" in your editor. It doesn't read your code as text. It understands it: which getUser is which, what calls what, and what type everything is.

Claude Code can use one too. Once it's installed, Claude can:

  • Jump to where something is defined, even across files.
  • Find every real caller of a function, and only those.
  • See what a function calls and what calls it.
  • Check types without running anything.

Why not just search better?

Because text search answers a different question. It finds where these letters appear. You almost always want where this thing is used.

You askText search findsLanguage server finds
"Where is getUser used?"Every match for the letters, including comments and lookalikesOnly the real calls to this getUser
"What breaks if I rename it?"A guessThe exact list
"Where is this defined?"Every file that mentions the nameThe one definition
"Is this still at line 200?"It reads line 200, whatever is there nowIt finds the function wherever it moved

The last row is the one that bit me. Line numbers are an address. Names are an identity. Code moves and line numbers break, but a language server still finds the thing by name.

Set it up

Two steps per language. The plugin connects Claude Code to the language server, but you install the language server itself.

1. Install the language server (once per machine):

terminalbash
# Python
npm install -g pyright
 
# TypeScript and JavaScript
npm install -g typescript-language-server typescript

2. Install the matching plugin inside Claude Code:

Claude Codetext
/plugin install pyright-lsp@claude-plugins-official
/plugin install typescript-lsp@claude-plugins-official

There are official plugins for Go, Rust, Java, C#, PHP, Ruby, Swift and more. Run /plugin and search for "lsp" to see them.

Check it worked

Open a session in your project and ask:

first messagetext
Find every place that calls <a function in your project>. Use the language server, not text search.

Watch the tool calls. If you see LSP instead of a text search, it's working.

The one rule I add to every project

This line goes in every project's CLAUDE.md:

CLAUDE.mdmd
Find code by name, never by line number. Line numbers in notes,
task descriptions and old messages are probably out of date.

It's cheap to write and it saves you from a whole wrong analysis. Line numbers go stale in a couple of weeks. A function's name usually lasts a lot longer.

Gotchas

The plugin alone does nothing. Without the language server installed, Claude falls back to text search, quietly. Do step 1.

Your project needs to be installed too. A language server reads your dependencies to understand imports. Run npm install, or activate your Python environment, before you start the session.

Text search still has a job. Config files, error messages and comments aren't code the language server tracks. Searching text is the right tool there.

What it doesn't fix

A language server shows Claude the code as it really is. It doesn't check whether Claude's conclusions about that code are true.

An agent can find exactly the right function and still explain it wrong. Making it prove what it claims is the next post.

Next in Claude Maxxing

The desk, the memory and the eyes make a session start well and see clearly.

Part 4 is about trust: getting the agent to show its evidence before you believe it.

If you set this up, I'd like to hear which language you started with. Get in touch.

Hatim Patwa

SDE-3 · Forward Deployed Engineer. I write about systems I've had to untangle.

Get in touch