stacklok / stacklok/mecatl

Design exercise: LSP support via existing extension points (à la Claude Code's lspServers plugins)

Open
#424 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

Claude Code ships native LSP support and it's worth studying as a design exercise: could mecatl get the same capability purely through its existing extension points — no changes to the core harness kit?

What Claude Code does (read from the shipped binary, 2.1.224)

  • The harness embeds a real LSP client. It speaks the protocol directly to a language server: textDocument/didOpen|didChange|didSave, publishDiagnostics, definition, references, implementation, hover, documentSymbol, call hierarchy, semantic tokens.

  • Servers are declared, not implemented, by plugins. A plugin manifest carries an lspServers field — inline config or a path to a .lsp.json. The official gopls-lsp plugin is nothing but this (source):

    "lspServers": {
      "gopls": {
        "command": "gopls",
        "extensionToLanguage": { ".go": "go" }
      }
    }
    

    The plugin bundles no binary — gopls must be on PATH. The harness spawns it lazily when a matching file is touched.

  • The payoff is zero prompt-context cost: no tool schemas injected. Diagnostics come back attached to edit results; semantic navigation is available without the model asking. Contrast with gopls mcp (the headless MCP server gopls also ships), which exposes explicit tools (go_symbol_references, go_package_api, …) at a per-session context tax.

The design exercise

How close can mecatl get without touching the core?

  • Diagnostics after edits looks like a PostToolUse hook on Edit/Write: run gopls check <file> (or a persistent server behind a small shim) and emit findings back into the transcript. Does our hook output channel carry enough to make this useful, or does it only allow/block?
  • Navigation/references as tools looks like MCP territory (gopls mcp exists today) — but that reintroduces the context tax the native design avoids. Is there a middle path, e.g. ToolSearch-style progressive disclosure over an LSP-backed toolset?
  • Lifecycle is the hard part: a long-lived stateful subprocess per session, lazy spawn on first matching file, didOpen/didChange synchronization with the file tools' writes, workspace-root scoping (our os.Root containment), shutdown on session end. Which of our seams (CommandRunner? hooks? something new) can own a process with that lifecycle?
  • If the answer is "none, cleanly" — that's the finding: LSP may be a genuine core capability (a new port, like the provider port), and the exercise tells us where the extension-point boundary actually sits.

Worth noting Claude Code treats it as core too (--bare disables it alongside hooks and plugin sync), while keeping per-language config in plugin space. That split — protocol client in core, server registry in extensions — may be the interesting part to emulate.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the existing PostToolUse hooks around Edit/Write and the CommandRunner, then inspect how os.Root containment and session shutdown are handled. Evaluate whether these extension points can support LSP diagnostics, navigation, and a stateful subprocess lifecycle without core changes. Done means documenting a viable design or clearly identifying where a new core capability is required.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.