Skip to content

fix: restore .lsp.json — empirically required for third-party LSP plugins - #2

Merged
avifenesh merged 1 commit into
mainfrom
fix/restore-lsp-json
Apr 26, 2026
Merged

fix: restore .lsp.json — empirically required for third-party LSP plugins#2
avifenesh merged 1 commit into
mainfrom
fix/restore-lsp-json

Conversation

@avifenesh

@avifenesh avifenesh commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The previous PR (#1) deleted .lsp.json based on the (correct) observation that official LSP plugins ship only README.md + LICENSE in their source. The (incorrect) inference was that marketplace.json's lspServers block was the universal mechanism. Empirical testing on Claude Code v2.1.119 disproved that.

Investigation summary

Two-path picture:

Plugin type Mechanism
Official LSP plugins (*-lsp@claude-plugins-official) Hardcoded path inside the binary, gated on the marketplace name. Source ships only README.md + LICENSE; lspServers in marketplace.json is metadata.
Third-party LSP plugins (us) Must ship .lsp.json at plugin root in the source repo. It's copied to ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.lsp.json on install. The runtime loader reads from that cache path. That's what registers the server.

Empirical evidence (this session, v2.1.119)

State Result
agent-sh marketplace, only lspServers in marketplace.json Silently skipped. Debug log: Checking plugin zig-lsp appears, no Loaded ... LSP server(s) line follows.
Same plugin replicated under claude-plugins-official marketplace cache Loads. Hardcoded path.
agent-sh marketplace WITH .lsp.json at plugin root → cached in install dir Loads. Loaded 1 LSP server(s) from plugin: zig-lsp, Total LSP servers loaded: 3.

Changes

  • plugins/zig-lsp/.lsp.json — restored, full ZLS config (extensions, initializationOptions, lifecycle).
  • .claude-plugin/marketplace.jsonlspServers block kept (matches official-plugin shape; will be the right metadata target if/when the marketplace-side loader is wired as the docs describe).
  • CLAUDE.md / AGENTS.md / CONTRIBUTING.md non-negotiables updated: both files required, kept byte-equivalent on server config.
  • README.md — repo layout reflects .lsp.json.
  • agent-knowledge/claude-code-lsp-plugin-contribution.md — correction block expanded with the two-path picture + empirical evidence table.
  • CHANGELOG.md[Unreleased] entry rewritten.
  • .gitignore — added .claude/settings.local.json.

Test plan

  • claude plugin validate . passes
  • claude plugin validate plugins/zig-lsp passes
  • agnix --target claude-code passes (0 errors)
  • After installing from this branch + opening a .zig file: claude --debug shows Loaded 1 LSP server(s) from plugin: zig-lsp (verified by pre-staging .lsp.json in the cache directly)
  • Final end-to-end check after merge: uninstall → reinstall → open .zig file → confirm LSP loads from a clean install path

Related Anthropic issues

  • #15521 — LSP servers from plugins not registering (closed as completed in v2.1.76, but .lsp.json empirically still required for third-party plugins on v2.1.119)
  • #31468 — Dead-code analysis of the marketplace-side loader (closed as NOT_PLANNED). Our finding: the .lsp.json runtime path is alive and well; only the marketplace-side lspServers discovery is dead code for non-claude-plugins-official marketplaces.

Note

Medium Risk
Medium risk because it changes how the LSP server is discovered/loaded at runtime by reintroducing a second source of truth (plugins/zig-lsp/.lsp.json) that must stay in sync with marketplace.json.

Overview
Restores plugins/zig-lsp/.lsp.json so Claude Code reliably registers zls for third-party installs, while keeping the same lspServers config inline in .claude-plugin/marketplace.json.

Updates contributor/docs guidance (CLAUDE.md, AGENTS.md, CONTRIBUTING.md, README.md, and the agent-knowledge note) to reflect the dual-path requirement and the rule that .lsp.json and marketplace lspServers must remain byte-equivalent. Also ignores .claude/settings.local.json in git.

Reviewed by Cursor Bugbot for commit e669acd. Configure here.

…gins

The previous round of changes deleted .lsp.json based on the (correct)
observation that official LSP plugins ship only README+LICENSE in their
source. The (incorrect) inference: marketplace.json's lspServers must
be the universal mechanism. Empirical testing on v2.1.119 disproved
this — without .lsp.json in the cached plugin dir, the loader silently
skips the entry.

Two-path picture (verified by adding .lsp.json directly to the cached
install dir at ~/.claude/plugins/cache/agent-sh/zig-lsp/0.1.0/.lsp.json
and confirming `Loaded 1 LSP server(s) from plugin: zig-lsp` in
claude --debug):

- Official LSP plugins (typescript-lsp etc.) — hardcoded path inside
  the binary, gated on marketplace name 'claude-plugins-official'.
  Plugin source ships only README+LICENSE.
- Third-party LSP plugins — must ship .lsp.json at plugin root in the
  source repo, which gets copied to the user's cache on install. The
  runtime loader reads from the cache path; that's what registers the
  server.

Keep lspServers in marketplace.json too — identical to .lsp.json
content. Matches the official-plugin shape and is the right metadata
target if/when Anthropic wires the marketplace-side loader as the
docs describe.

Files:
- plugins/zig-lsp/.lsp.json — restored
- CLAUDE.md / AGENTS.md / CONTRIBUTING.md — non-negotiables updated
  to require both files, kept byte-equivalent on server config
- README.md — layout reflects .lsp.json
- agent-knowledge/claude-code-lsp-plugin-contribution.md — correction
  block expanded with the two-path picture + empirical evidence table
- CHANGELOG.md — Unreleased entry rewritten
@avifenesh
avifenesh merged commit e6e027a into main Apr 26, 2026
4 checks passed
@avifenesh
avifenesh deleted the fix/restore-lsp-json branch April 26, 2026 00:27

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request restores the .lsp.json configuration file at the plugin root and updates documentation across several files to reflect that third-party LSP plugins require both this file and an inline lspServers block in marketplace.json for proper registration. Feedback indicates that the semantic_tokens key in the new .lsp.json file is incorrect for ZLS and should be updated to enable_semantic_tokens to match the expected schema.

Comment thread plugins/zig-lsp/.lsp.json
"enable_argument_placeholders": true,
"enable_build_on_save": true,
"build_on_save_args": [],
"semantic_tokens": "full",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The semantic_tokens key with the value "full" appears to be incorrect for ZLS. According to the ZLS configuration schema, the relevant option is typically enable_semantic_tokens and it expects a boolean value. Note that this change should also be applied to the lspServers block in marketplace.json to adhere to the project's requirement of keeping these configurations byte-equal.

Suggested change
"semantic_tokens": "full",
"enable_semantic_tokens": true,

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.

1 participant