pi-lsp
Declarative Pi extension for LSP diagnostics and language-server navigation tools.
Package details
$ pi install npm:pi-lsp- Package
pi-lsp- Version
0.1.7- Published
- May 11, 2026
- Downloads
- 14/mo · 14/wk
- Author
- conte777
- License
- MIT
- Types
- extension
- Size
- 58 KB
- Dependencies
- 2 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"extensions/pi-lsp/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-lsp
Declarative Pi extension for LSP diagnostics and language-server navigation tools.
Why
pi-lsp lets users configure language servers with JSON instead of installing a separate Pi plugin for every language.
It is intentionally separate from pi-code-quality: LSP servers are long-lived JSON-RPC processes, while formatters/linters are short-lived command-line tools.
Install
pi install npm:pi-lsp
For local development:
pi install /absolute/path/to/pi-lsp
Configuration
Global config, trusted automatically:
~/.pi/agent/lsp.json
Project-local config, requires trust:
.pi/lsp.json
Project entries override global entries with the same id. A project entry with "enabled": false disables the global entry with that id.
Trust and security
Project-local config can auto-run binaries on your machine. For that reason:
- project-local config content is hashed;
- unknown hashes prompt for
Trust once,Trust always, orReject; - the prompt shows every configured LSP binary;
Trust alwaysstores the hash in~/.pi/agent/trust/lsp.json;- changing the config changes the hash and asks again;
- non-interactive mode rejects project-local config by default;
- servers are spawned as
bin+args[], never as shell strings.
Global config is considered trusted because it is user-owned agent configuration.
Example config
{
"version": 1,
"servers": [
{
"id": "gopls",
"enabled": true,
"include": ["**/*.go"],
"rootMarkers": ["go.mod"],
"bin": "gopls",
"args": [],
"cwd": "{root}",
"languageIdByExtension": { ".go": "go" },
"startupTimeoutMs": 45000,
"diagnosticsWaitMs": 1500,
"initializationOptions": {},
"settings": {}
},
{
"id": "pyright",
"enabled": true,
"include": ["**/*.py", "**/*.pyi"],
"rootMarkers": ["pyproject.toml", "setup.py", "requirements.txt"],
"bin": "pyright-langserver",
"args": ["--stdio"],
"cwd": "{root}",
"languageIdByExtension": { ".py": "python", ".pyi": "python" },
"startupTimeoutMs": 45000,
"diagnosticsWaitMs": 2000,
"initializationOptions": {},
"settings": {}
},
{
"id": "clangd",
"enabled": true,
"include": ["**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/*.cc", "**/*.cxx"],
"rootMarkers": ["compile_commands.json", ".clangd"],
"bin": "clangd",
"args": ["--background-index"],
"cwd": "{root}",
"languageIdByExtension": {
".c": "c",
".h": "c",
".cpp": "cpp",
".hpp": "cpp",
".cc": "cpp",
".cxx": "cpp"
},
"startupTimeoutMs": 45000,
"diagnosticsWaitMs": 2000,
"initializationOptions": {},
"settings": {}
}
]
}
Behavior
After a successful write or edit:
- finds servers matching
include/exclude; - finds
{root}usingrootMarkers; - starts or reuses one LSP process per
(server id, root); - reads the current file content;
- sends
textDocument/didOpenortextDocument/didChange; - sends
textDocument/didSavewhen the server supports save; - waits
diagnosticsWaitMs; - appends the latest diagnostics to the original tool result.
Diagnostics do not make write / edit fail. They are extra context for the model. Summaries that contain issues are also sent as a user-visible, tool-styled diagnostic notice.
On session_shutdown, the extension sends shutdown, then exit, then kills the process as fallback.
LLM tools
pi-lsp registers tools for the model, not slash commands:
lsp_diagnostics({ path })lsp_hover({ path, line, character })lsp_definition({ path, line, character })lsp_references({ path, line, character, includeDeclaration })lsp_symbols({ path })
Relative paths and placeholders
Path resolution:
- absolute paths are used as-is;
- relative
bin,config, andcwdvalues with/are resolved relative to{root}; - bare binary names are resolved through
PATH.
Placeholders:
{workspace}— Pi working directory or directory containing project.piconfig{root}— nearest directory containing one ofrootMarkers{file}— absolute file path{relFile}— file path relative to{root}{dir}— absolute file directory{relDir}— file directory relative to{root}{config}— resolved server config path{configDir}— directory containing{config}
Output example
LSP diagnostics:
✅ gopls: no diagnostics
LSP diagnostics:
⚠️ pyright:
src/app.py:12:8 - error: Argument of type "str" cannot be assigned to parameter "int"
Disable a server
{
"version": 1,
"servers": [{ "id": "gopls", "enabled": false }]
}
Development
npm install
npm run verify
npm pack --dry-run