Skip to content

LSP / Code Intelligence#

What it is#

LSP / code intelligence is the capability class that gives a model structural understanding of a codebase beyond plain text: jump-to-definition, find-references, symbol search, type/compile diagnostics, code actions (quick-fixes/refactors), rename-across-references, and call hierarchies. It sits between two more primitive capabilities a coding agent already has — grep/glob (textual search) and shell/bash (running a compiler or linter directly) — and gives the model a shortcut to semantically accurate answers that would otherwise require either an expensive full-repo grep or an ad hoc shell invocation of a language-specific tool.

Two distinct implementation strategies converge under this one capability name: wrapping an actual Language Server Protocol server (gopls, tsserver, pyright, etc. — the same protocol editors use) as a backing process, versus using a lighter-weight structural parser (tree-sitter) that gets syntax-level structure without spinning up a per-language server. A few implementations hybridize both. The capability typically also absorbs a closely related concern, diagnostics (compiler/linter errors and warnings), since LSP servers naturally expose diagnostics as part of the same protocol — though diagnostics is sometimes tracked as its own separate capability even where the same LSP-backed tool implements both.

In a coding agent's workflow, this capability matters most for large or unfamiliar codebases where "grep for the identifier" produces false positives (shadowed names, string literals, comments) or misses call sites reached through interfaces/generics that only a type-aware server can resolve. It also enables safer refactors — a project-wide rename via LSP is categorically more reliable than a regex-based find/replace.

Common implementation patterns#

Tool granularity splits two ways. Some implementations bundle the whole capability behind a single tool name with an operation parameter (or automatic mode selection). Others go the opposite direction: several separate tools, each independently feature-gated, each mapping to exactly one LSP protocol method (diagnostics, go-to-definition, find-references, get-code-actions, apply-code-action, rename-symbol) — covering more distinct operations than a single bundled tool typically exposes, at the cost of more surface area to gate.

LSP-proper vs. tree-sitter-only vs. hybrid. Some implementations wrap an actual language server. Others are tree-sitter only — no language server process, which trades semantic accuracy (no cross-file type resolution) for zero setup cost and broader out-of-the-box language coverage. A hybrid pattern keeps tree-sitter always-on and bundled for baseline structure, with LSP as an optional upgrade a user explicitly activates.

Feature-gating is the norm, not the exception. Several implementations ship this capability behind an explicit opt-in flag. This is unusual relative to this capability's neighbors (file read/write/edit, shell, grep are all unconditionally present) and reflects a genuine cost: spinning up and managing a language-server subprocess per language is heavier infrastructure than a stateless grep or glob call. An alternative to a flag: the tool exists unconditionally but is inert until a language-specific plugin/server is installed, pushing the setup cost to a separate installation step rather than a runtime flag.

Diagnostics is a closely related but often separately tracked sibling capability. Some implementations fold project-wide LSP error/warning retrieval directly into the same mechanism as definition/reference lookup. Others implement diagnostics through entirely separate, non-LSP mechanisms (a compiler wrapper, a linter subprocess, tree-sitter heuristics) as their own distinct tool.

Permission treatment is unusually permissive for a stateful tool. Every implementation that documents a permission stance treats LSP/code-intel reads as free of approval. This tracks with the operation's read-only nature (querying a language server never mutates source) but is notable because the underlying mechanism (a long-lived subprocess with its own memory/state) is heavier than the typical data-source operation, yet the approval treatment is identical to a stateless grep.

Permission, sandbox & safety#

Every documented instance of this capability is read-only in effect — even a rename or apply-code-action operation, which sound mutating, only propose or execute editor-mediated code changes; the risk profile is closer to edit_file's than to bash's, since the actual write still goes through the harness's normal file-edit path. No implementation documents a distinct approval prompt specific to LSP operations beyond whatever feature-flag or plugin-installation gate controls whether the capability is available at all — the gate is "is this feature turned on," not "does this specific call need approval."

Sandboxing is essentially a non-issue for this capability. OS-level process isolation is discussed almost exclusively in the context of the shell/bash capability. A language-server subprocess is a comparatively low-risk process to run unsandboxed: it reads source files and returns structured data, with no documented case of an LSP integration executing arbitrary shell commands or writing files directly. One caveat worth flagging in general: a language server that phones home (e.g. a package-index lookup for import resolution) would touch network sandboxing, though no implementation calls this out as an observed concern for this capability specifically.

The rename/apply-code-action case is the closest this capability gets to carrying real risk, since a project-wide rename touches every reference to a symbol — but this is routed through the same file-write path as any other edit, not treated as a separately elevated risk tier.

Design considerations#

Where this capability exists, it is read-only in permission treatment (no approval prompt gates it), it is layered on top of either a real language server or tree-sitter (never invented from scratch), and it is treated as optional infrastructure rather than a baseline expectation — unlike file read/grep/shell, which every implementation ships unconditionally. The deepest integrations tend to pair the capability with a genuine LSP backend rather than relying on tree-sitter alone, suggesting that when implementers invest in this capability at all, they invest in the more semantically accurate version.

Divergent: granularity (one bundled tool vs. many single-purpose tools), feature-gating posture (always-on-but-inert vs. explicit flag vs. unconditional), and scope (full LSP surface vs. references-only). There is no naming convergence either — contrast this with grep/grep_search, which converges on far fewer name variants across a larger population.

This is one of the rarer capabilities, and several instances are explicitly experimental/flagged — the concentration of feature flags among implementations that otherwise ship mature core tool sets suggests this capability is actively being hardened rather than settled.

Implications for PluggableHarness Agent#

The tool reference catalog is scoped to common-core capabilities — read_file, write_file, edit_file, glob, grep, bash, web_search, web_fetch, the task family, spawn_subagent, and ask_user. It names browser, cron, and memory-as-a-tool as capabilities that were considered and deliberately left out as differentiators for third-party providers. LSP/code-intel sits below the common-core threshold and, if anything, below the differentiators the catalog already calls out by name — so on current evidence, this capability does not clear the bar the catalog applies, and belongs alongside browser/cron/memory-as-a-tool as a third-party differentiator, not a first-party addition to the reference catalog.

That said, the evidence weakly complicates leaving it out entirely, for a different reason than raw prevalence: this capability's closest cousin, diagnostics, is similarly niche and similarly unlisted, and both together represent a meaningfully large fraction of "structural code understanding" tooling that none of PluggableHarness Agent's current reference operations (grep, glob, read_file) can approximate for anything requiring type-awareness (e.g. resolving an interface implementation, or a rename that must not miss a call site reached through an alias). If PluggableHarness Agent's reference search category ever grows a code_intel operation, this evidence points toward: kind = data_source, risk = read_only (every documented instance is read-only in permission treatment), classified in the search provider category alongside glob/grep rather than a new top-level category — consistent with how the reference catalog groups capability-adjacent operations. A rename/code-action variant, if ever added separately, would need its own classification discussion since it produces file mutations, unlike lookup/reference/diagnostic operations; the evidence here doesn't settle that case since every implementation routes it back through its ordinary file-edit path rather than treating it as a novel risk tier.

This capability does not bear on the tool reference catalog's ambiguous classification calls (bash, web_fetch, task, ask_user) — it's a clean data_source case with no disambiguation problem, unlike those. It also does not intersect the memory provider, agent-loop, or kernel-callback protocols — this is squarely a tool-provider-shaped operation, not a model input modality or kernel-loop mechanism. No open question in tool/conformance.md is implicated by this capability specifically.