Skip to content

feat: add Claude Code marketplace and dexter-lsp plugin#59

Merged
JesseHerrick merged 6 commits into
remoteoss:mainfrom
pquadri:docs/claude-code-lsp-setup
May 26, 2026
Merged

feat: add Claude Code marketplace and dexter-lsp plugin#59
JesseHerrick merged 6 commits into
remoteoss:mainfrom
pquadri:docs/claude-code-lsp-setup

Conversation

@pquadri
Copy link
Copy Markdown
Contributor

@pquadri pquadri commented May 5, 2026

Summary

Turns the dexter repo into a Claude Code marketplace, so users can install Dexter as their Elixir LSP in Claude Code with just two commands:

claude plugin marketplace add remoteoss/dexter
claude plugin install dexter-lsp@dexter

Changes

  • .claude-plugin/marketplace.json — makes this repo a Claude Code marketplace named dexter
  • plugins/dexter-lsp/.claude-plugin/plugin.json — plugin manifest that wires up dexter lsp for .ex, .exs, and .heex files, with followDelegates and debug exposed as user-configurable options
  • README.md — adds a Claude Code section to the editor setup docs

How it works

Claude Code's LSP tool supports a plugin system. The lspServers entry in plugin.json tells Claude Code to spawn dexter lsp when opening Elixir files, giving it go-to-definition, hover docs, find references, workspace symbols, and more.

Test plan

  • claude plugin marketplace add remoteoss/dexter succeeds
  • claude plugin install dexter-lsp@dexter succeeds
  • Open an Elixir project — LSP tool resolves hover and go-to-definition on .ex files
  • userConfig prompts appear for followDelegates and debug on install

Note

Low Risk
Plugin manifests, documentation, and defensive init-option parsing with expanded tests; no changes to indexing or core LSP behavior beyond config parsing.

Overview
This PR turns the dexter repo into a Claude Code marketplace and ships a dexter-lsp plugin that runs dexter lsp for .ex, .exs, and .heex, with user settings for followDelegates and debug.

The LSP server now accepts boolean initialization options as strings (via coerceBool), because Claude Code’s ${user_config.*} substitution sends strings instead of JSON booleans. Tests cover bools, "true"/"false", "1"/"0", and invalid values.

README adds a Claude Code editor section: enable ENABLE_LSP_TOOL, then claude plugin marketplace add / plugin install.

Reviewed by Cursor Bugbot for commit 23a339e. Bugbot is set up for automated code reviews on this repo. Configure here.

pquadri added 2 commits May 5, 2026 16:51
Explains how to wire up Dexter as the Elixir LSP for Claude Code's LSP
tool (go-to-definition, hover docs, find references) using a local plugin
manifest.
Turns the dexter repo into a Claude Code marketplace so users can install
Dexter as their Elixir LSP with two commands:

  claude plugin marketplace add remoteoss/dexter
  claude plugin install dexter-lsp@dexter

The plugin wires up `dexter lsp` for .ex/.exs/.heex files and exposes
followDelegates and debug as user-configurable options.
@pquadri pquadri changed the title docs: add Claude Code LSP setup guide feat: add Claude Code marketplace and dexter-lsp plugin May 5, 2026
Comment thread plugins/dexter-lsp/.claude-plugin/plugin.json Outdated
@JesseHerrick JesseHerrick self-requested a review May 6, 2026 04:04
@JesseHerrick
Copy link
Copy Markdown
Member

Thanks for the PR @pquadri! I think this is a great addition. Going to sleep on whether to keep this in the same repo or in a different one. If you have any docs on the matter, I'd also be glad to read them. Should be able to merge this tomorrow.

Comment thread plugins/dexter-lsp/.claude-plugin/plugin.json Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 305f540. Configure here.

Comment thread plugins/dexter-lsp/.claude-plugin/plugin.json
Comment thread plugins/dexter-lsp/.claude-plugin/plugin.json
Claude Code plugin template substitution (${user_config.X}) always
produces a JSON string even when the userConfig type is "boolean".
The strict `.(bool)` type assertions silently dropped the user's
followDelegates/debug settings, leaving them stuck at hardcoded defaults.

Add a coerceBool helper that accepts both native bool and string forms
("true"/"false"/"1"/"0"). Expand the initializationOptions test to call
server.Initialize and cover both forms.
JesseHerrick added a commit that referenced this pull request May 25, 2026
"Headless" LSP clients such as Claude Code don't actually open files
when doing lookups or changing them. This means that some of our tricks
for looking things up via the context of the files breaks.

This PR adds lazy disk-fallback to the document store so LSP clients
that don't drive the full `didOpen`/`didChange`/`didClose` lifecycle
(e.g. Claude Code) can still query definitions, hovers, references, and
other text-dependent handlers. Use-injected lookups in particular:
`lookupThroughUse`, `lookupThroughUseOf`. Alias merging also previously
returned `nil` for any file the editor hadn't explicitly opened.

The goal of these changes is enablement work for a proper Claude Code
plugin: #59.

## What changed

- **`DocumentStore.GetOrLoad(uri)`**: lazy disk read for any `file://`
URI that isn't already in the store. Disk-loaded entries are marked
`transient: true` and tracked in a Least Recently Used (LRU) cache.
Non-`file://` URIs (e.g. `untitled:`) return `(false)` without touching
disk to avoid the `uriToPath` panic.
- **LRU eviction**: transient entries are capped (default 50).
Editor-owned buffers (`Set` via `didOpen`) are never counted, never
reordered, never evicted. `Set` cleanly promotes a transient entry to
editor-owned, dropping its LRU bookkeeping.
- **Cap is configurable**: new `maxTransientDocuments` initialization
option (default 50, accepts integer or JSON number, clamps negatives to
0). Documented in `README.md`.
- **Handler migration**: 18 read-only handlers (`Definition`, `Hover`,
`References`, `Completion`, `CodeAction`, `Declaration`,
`DocumentHighlight`, `DocumentSymbol`, `FoldingRanges`,
`Implementation`, `PrepareRename`, `Rename`, `SignatureHelp`,
`TypeDefinition`, `PrepareCallHierarchy`, …) now call `GetOrLoad`.
`Formatting` deliberately keeps `Get` — it only makes sense for
in-memory editor buffers.

## Correctness notes

- File I/O happens outside the write lock; a re-check inside the lock
returns the existing entry if a concurrent `Set` or `GetOrLoad`
populated the URI first.
- `bumpLRU` is a no-op if the URI was promoted to editor-owned between
the RLock and Lock, so the fast-path race is safe.
- `evictTransientLocked` closes the cached tree-sitter tree before
deletion - no leak.
- Race-clean under `go test -race`.
@JesseHerrick
Copy link
Copy Markdown
Member

Hey @pquadri, the changes in #62 to enable this change have been merged! Could you just run gofmt ./... and push up the change? Then this should be good to merge.

@JesseHerrick JesseHerrick merged commit e72e5d7 into remoteoss:main May 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants