Skip to content

drey 0.1.0

Choose a tag to compare

@mario mario released this 20 Jul 20:21
· 16 commits to main since this release

One language server per workspace, shared by every editor and agent.

Every LSP client starts its own language server. Two Claude Code sessions on one
Rust workspace means two rust-analyzer processes, each holding a complete salsa
database, and 7.4 GB of memory to answer questions about one copy of one
codebase. drey makes them share.

The same applies to gopls, tsserver, clangd, pyright and jdtls. Rust is the
example because it is the one with the measurement.

Install

cargo install drey
# or
brew install mario/drey/drey

Then ./scripts/install.sh puts wrapper scripts on your PATH, so existing
editor and agent configs pick up drey without being changed.

What it does

The shim looks exactly like a language server on stdio. The daemon owns one real
server per workspace and autostarts on first use.

Clients attach by root containment rather than equality, so opening a single
crate inside a Cargo workspace costs nothing: it joins the server that already
indexed it. Git worktrees and branches deliberately stay separate, because
merging them would produce wrong answers, which is worse than using memory.

Two clients with different unsaved edits to the same file still share one
process. Each document keeps a base text and a loaded text, and the daemon swaps
the loaded one rather than forking a second server. Verified against a real
rust-analyzer: with one client holding pub size: u32 and another holding
u64, the same process reports size = 4, align = 0x4 to the first and
size = 8, align = 0x8 to the second. That is a type layout recomputed per
client, not an echo of the text they sent.

Server-initiated requests (workspace/configuration,
client/registerCapability, workspace/applyEdit) are answered by one attached
client on behalf of all. A proxy that drops those silently runs rust-analyzer on
defaults, which is the opposite of what you want when you adopted a proxy to
control memory.

Builtins

rust-analyzer, gopls, typescript, pyright, ruff, clangd, zls, lua, elixir,
jdtls. Anything in ~/.config/drey/config.toml overrides them.

Testing

150 unit tests, 11 CLI integration tests, an end-to-end suite driving the real
binary over stdio against a mock server, and a smoke test against a real
rust-analyzer. CI runs fmt, clippy with warnings as errors, tests on Linux and
macOS, an MSRV 1.85 check, and cargo-deny for licences and advisories.

Status

First release. The daemon has been running my own sessions for a while, but it
has not been through anyone else's setup yet, so expect rough edges and please
report them. Sharing policy is the part where a bug is silent, so bug reports
about clients sharing when they should not are the most valuable kind.