LSP integration

May 29, 2026 · View on GitHub

When built with the lsp feature (on by default), dirge attaches Language Server Protocol clients to your project and surfaces compile-time diagnostics directly in the agent's tool output. After every write or edit, the LSP server gets a didChange, waits for a fresh diagnostic publish, and any ERRORs land in the tool result as a <diagnostics file="..."> block — so the agent corrects compile errors on the same turn instead of writing broken code and discovering it later via cargo check.

ToolEffect
readFire-and-forget didOpen so the server has the file in memory by the time the agent edits it. No diagnostic block in read output.
writeAfter write: didChange + wait for diagnostics + append errors-block.
editSame as write.
lspAgent-facing tool that exposes definition, references, hover, documentSymbol, workspaceSymbol, implementation, prepareCallHierarchy, incomingCalls, outgoingCalls. 1-based coordinates.

Built-in server set

Server idBinaryExtensions
rustrust-analyzer.rs
typescripttypescript-language-server --stdio.ts, .tsx, .mts, .cts, .js, .jsx, .mjs, .cjs
pyrightpyright-langserver --stdio.py, .pyi
clojure-lspclojure-lsp.clj, .cljs, .cljc, .edn, .bb
goplsgopls.go
jdtlsjdtls.java
clangdclangd.c, .cc, .cpp, .cxx, .h, .hh, .hpp, .hxx, .m, .mm
ruby-lspruby-lsp.rb, .rake, .gemspec
bash-language-serverbash-language-server start.sh, .bash

Missing binaries trip the broken-server backoff (1s → 2s → … capped at 10 min) rather than failing dirge — the rest of the session keeps working. Override the spawn command per server via the lsp config key; see config.md.

Workspace root resolution

Resolution is per-server: rust-analyzer walks past nested member crates to the workspace Cargo.toml declaring [workspace]; typescript stops at the nearest package.json/tsconfig.json and yields to deno when a deno.json is closer; pyright looks for pyproject.toml/setup.py/etc.; clojure-lsp looks for deps.edn/project.clj/shadow-cljs.edn/bb.edn/.clj-kondo; gopls follows go.mod/go.work; jdtls looks for pom.xml/build.gradle; clangd uses compile_commands.json/CMakeLists.txt/Makefile/meson.build; ruby-lsp follows Gemfile/Rakefile; bash-language-server uses the file's parent.

Disable: --no-lsp flag or { "lsp": false } in the config. Per-server overrides (custom command, env, init options) live in the config — see config.md.