Configures and orchestrates Language Server Protocol (LSP) clients, builds semantic code indexes, and enables code intelligence features like go-to-definition, find references, hover documentation, and auto-complete. Use when you need to set up or debug language servers (e.g., typescript-language-server, intelephense, pyright, gopls, rust-analyzer), implement code navigation in an editor or toolchain, build a unified symbol graph across multiple languages, configure LSP server connections and capability negotiation, or create real-time semantic indexes (LSIF, nav.index.jsonl) for large codebases.
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
You orchestrate Language Server Protocol clients and build unified code intelligence systems — transforming heterogeneous language servers into a cohesive semantic graph that powers code navigation and visualization.
nav.index.jsonl with symbol definitions, references, and hover documentation; support LSIF import/export| Endpoint / Event | Budget |
|---|---|
GET /graph (<10k nodes) | ≤ 100 ms |
GET /nav/:symId cached | ≤ 20 ms |
GET /nav/:symId uncached | ≤ 60 ms |
| WebSocket event latency | < 50 ms |
| Memory (typical project) | < 500 MB |
ServerCapabilities before invoking any feature — never assume supportinitialize → initialized → shutdown → exit// Use these as canonical schema definitions for graphd
interface GraphNode {
id: string; // "file:src/foo.ts" or "sym:foo#method"
kind: 'file' | 'module' | 'class' | 'function' | 'variable' | 'type';
file?: string; // Parent file path
range?: Range; // LSP Range for symbol location
detail?: string; // Type signature or brief description
}
interface GraphEdge {
id: string; // "edge:uuid"
source: string; // Node ID
target: string; // Node ID
type: 'contains' | 'imports' | 'extends' | 'implements' | 'calls' | 'references';
weight?: number; // For importance/frequency
}# Install language servers
npm install -g typescript-language-server typescript
npm install -g intelephense # PHP
npm install -g gopls # Go
npm install -g rust-analyzer # Rust
npm install -g pyright # Python
# Verify a server starts and responds (TypeScript example)
echo '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"capabilities":{},"rootUri":null,"processId":null}}' \
| typescript-language-server --stdio✅ Validation checkpoint: Confirm the initialize response contains a capabilities object. If the response is empty or errors, check PATH, node version, and that --stdio is supported by the installed version.
class LSPOrchestrator {
private clients = new Map<string, LanguageClient>();
private capabilities = new Map<string, ServerCapabilities>();
async initialize(projectRoot: string): Promise<void> {
const servers = [
{ lang: 'typescript', command: 'typescript-language-server', args: ['--stdio'] },
{ lang: 'php', command: 'intelephense', args: ['--stdio'] },
];
await Promise.all(servers.map(({ lang, command, args }) =>
this.initializeClient(lang, new LanguageClient(lang, { command, args, rootPath: projectRoot }))
));
}
private async initializeClient(lang: string, client: LanguageClient): Promise<void> {
const result = await client.sendRequest('initialize', {
processId: process.pid,
rootUri: `file://${client.rootPath}`,
capabilities: {},
});
// ✅ Validation: store capabilities before any further requests
this.capabilities.set(lang, result.capabilities);
this.clients.set(lang, client);
await client.sendNotification('initialized', {});
}
async getDefinition(uri: string, position: Position): Promise<Location[]> {
const lang = this.detectLanguage(uri);
const cap = this.capabilities.get(lang);
if (!cap?.definitionProvider) return []; // capability check before request
return this.clients.get(lang)!.sendRequest('textDocument/definition', {
textDocument: { uri },
position,
});
}
}✅ Validation checkpoint: After initialization, log capabilities for each server. Confirm definitionProvider, referencesProvider, and hoverProvider are present for expected languages before proceeding.
class GraphBuilder {
async buildFromProject(root: string): Promise<Graph> {
const graph = new Graph();
// Phase 1 & 2: Collect files and create file nodes
const files = await glob('**/*.{ts,tsx,js,jsx,php}', { cwd: root });
for (const file of files) {
graph.addNode({ id: `file:${file}`, kind: 'file', path: file });
}
// ✅ Validation: all file nodes must exist before symbol nodes are added
// Phase 3: Extract symbols via LSP (parallel)
await Promise.all(files.map(async (file) => {
const symbols = await this.extractSymbols(file); // calls textDocument/documentSymbol
for (const sym of symbols) {
graph.addNode({ id: `sym:${sym.name}`, kind: sym.kind, file, range: sym.range });
graph.addEdge({ source: `file:${file}`, target: `sym:${sym.name}`, type: 'contains' });
}
}));
// ✅ Validation: assert every symbol node's `file` references a known file node
// Phase 4: Resolve cross-file references and call edges
await this.resolveReferences(graph); // calls textDocument/references per symbol
// ✅ Validation: assert all edge source/target IDs exist in graph.nodes
return graph;
}
}✅ Validation checkpoint: After each phase, run a consistency check:
function assertGraphConsistency(graph: Graph): void {
for (const edge of graph.edges.values()) {
if (!graph.nodes.has(edge.source)) throw new Error(`Missing source node: ${edge.source}`);
if (!graph.nodes.has(edge.target)) throw new Error(`Missing target node: ${edge.target}`);
}
}GET /graph — return full graph snapshot (≤100ms for <10k nodes)GET /nav/:symId — symbol definition + references lookupGET /stats — node/edge counts, LSP client healthGraphDiff events on file change✅ Validation checkpoint: After wiring the watcher, save a test file and confirm a GraphDiff event arrives on the WebSocket within 500ms.
--prof (Node.js) or perf to find bottlenecks before optimizingtextDocument/references requests to minimize round-trip overheadtextDocument/didChange notificationsEach symbol's data is written as separate JSONL lines:
{"symId":"sym:AppController","def":{"uri":"file:///src/controllers/app.php","l":10,"c":6}}
{"symId":"sym:AppController","refs":[{"uri":"file:///src/routes.php","l":5,"c":10},{"uri":"file:///tests/app.test.php","l":15,"c":20}]}
{"symId":"sym:AppController","hover":{"contents":{"kind":"markdown","value":"```php\nclass AppController extends BaseController\n```\nMain application controller"}}}
{"symId":"sym:useState","def":{"uri":"file:///node_modules/react/index.d.ts","l":1234,"c":17}}
{"symId":"sym:useState","refs":[{"uri":"file:///src/App.tsx","l":3,"c":10},{"uri":"file:///src/components/Header.tsx","l":2,"c":10}]}010799b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.