{"slug": "show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents", "title": "Show HN: Lain, a structural code graph and agent coordinator for coding agents", "summary": "LAIN, a new structural code intelligence and coordination engine for AI coding agents, launched on Hacker News' Show HN, indexing codebases into an in-memory typed property graph via Tree-sitter, language servers, and Git commit history. LAIN exposes deterministic tools over the Model Context Protocol (MCP) — including get_blast_radius, get_call_chain, trace_dependency, and get_coupling_radar — to agents such as Claude Code, Cursor, Copilot, Codex, Agy, Cline, and Windsurf, and serves them over stdio or HTTP on port 9999 using JSON-RPC and SSE. The engine persists its graph to .lain/graph.bin with UUID v5 identifiers and tracks agent sessions and file claims through advisory presence registries to prevent overlapping edits.", "body_md": "**Structural Code Intelligence & Multi-Agent Coordination for AI Assistants.**\nGive your coding agents an in-memory graph brain instead of making them guess from flat text.\n\n**LAIN** is a persistent, high-performance code intelligence and coordination engine built specifically for AI coding agents (Claude Code, Cursor, Copilot, Codex, Agy, Cline, Windsurf, etc.) over the **Model Context Protocol (MCP)**.\n\nInstead of treating code as unstructured flat text or relying on fuzzy keyword searches, LAIN indexes your codebase into an in-memory, typed structural property graph (using Tree-sitter, language servers, and Git commit history). It then exposes a rich suite of deterministic MCP tools that allow AI agents to navigate, reason about, and modify complex codebases without hallucinations, blind edits, or context-window waste.\n\n- **Instant Answers** : Federation overview, repo health, and call graphs answered in milliseconds.\n- **Hot Reload** : Edit`repos.yaml` or`workspaces.yaml` ; the server updates live without dropping a single active MCP session.\n- **Interactive Tool Console** : Exercise any MCP tool directly from the web browser;*Copy as cURL* gives agents and operators instant reproducibility.\n\nNote\n\nThe demo is kept as a single GIF so it plays inline without storing duplicate video encodings in the repository.\n\n```\nflowchart TB\n    subgraph Clients[\"AI Agents & Developers\"]\n        A[\"AI Coding Agent<br/>(Claude Code / Cursor / Agy / Codex)\"]\n        B[\"Developer / Operator<br/>(Browser Command Center)\"]\n    end\n\n    subgraph Transports[\"MCP & Web Transports\"]\n        S[\"stdio (single-repo)\"]\n        H[\"HTTP :9999 (JSON-RPC & SSE)\"]\n    end\n\n    subgraph Core[\"LAIN Core Engine\"]\n        EX[\"Unified MCP Tool Dispatcher\"]\n        G[\"In-Memory Graph Engine<br/>(Petgraph · UUID v5)\"]\n        PRES[\"Presence & Claim Registry<br/>(Advisory Leases & Locks)\"]\n        FED[\"Federation Engine<br/>(N Repositories)\"]\n    end\n\n    subgraph Sources[\"Code Analysis & Storage\"]\n        TS[\"Tree-sitter AST Parser\"]\n        LSP[\"Language Servers (rust-analyzer, pylsp...)\"]\n        GIT[\"Git Commit History (Co-change radar)\"]\n        BIN[\".lain/graph.bin (Persistent Cache)\"]\n    end\n\n    A -->|MCP JSON-RPC| S\n    A -->|MCP HTTP| H\n    B -->|GET /| H\n    S --> EX\n    H --> EX\n    EX --> G\n    EX --> PRES\n    EX --> FED\n    G <--> BIN\n    G --> TS\n    G --> LSP\n    G --> GIT\n```\n\n1. **Indexing & Parsing** : LAIN scans your code using Tree-sitter and language servers (LSPs), extracting functions, classes, imports, and references into a property graph.\n2. **Persistent Graph Store** : The graph is serialized into`.lain/graph.bin` using deterministically derived UUID v5 identifiers for instant reloads.\n3. **Temporal Mining** : LAIN analyzes git commit logs to build a*co-change coupling radar* (identifying modules that evolve together even without explicit imports).\n4. **Advisory Presence** : In-memory and on-disk occupancy registries track agent sessions and file claims, preventing overlapping edits in real time.\n5. **Universal MCP Delivery** : Exposes standardized tools over stdio or HTTP so any MCP-compatible agent can query the graph directly.\n\nLAIN provides specialized MCP tools categorized by capability:\n\n- **`get_blast_radius`** — Downstream impact analysis: every function, type, and file affected by changing a symbol.\n- **`get_call_chain`** — Shortest path between two functions in the call graph.\n- **`trace_dependency`** — All upstream dependencies (callees, imports, types) of a target symbol.\n- **`get_coupling_radar`** — Files that frequently change together based on Git commit co-occurrence.\n\n- **`find_anchors`** — Identifies the core architectural pillars (most-called, most-stable symbols).\n- **`list_entry_points`** — Discovers` main()` , HTTP routes, and event handlers.\n- **`get_context_depth`** — Measures abstraction distance from public entry points.\n- **`explore_architecture`** — High-level hierarchical module and package tree.\n\n- **`register_agent` / `heartbeat`** — Registers an agent session and keeps advisory leases fresh.\n- **`claim_files` / `release_files`** — Claims or releases files and symbol ranges before editing.\n- **`detect_overlap`** — Analyzes overlapping symbol changes between git branches or concurrent sessions.\n- **`list_active_agents` / `who_am_i`** — Discovers other active agents and reports session identity.\n\n- **`semantic_search`***(requires ONNX model — see [Setting Up Semantic Search](#setting-up-semantic-search-optional))* — Concept-based code search using local ONNX embeddings with hybrid BM25/stemmed ranking.\n- **`query_graph`** — Composable JSON ops pipeline (` find` ,`connect` ,`filter` ,`semantic_filter` ,`sort` ,`limit` ).\n- **`explain_symbol`** — Complete structural dossier for a symbol (signature, callers, docstring, location).\n\n- **`list_repos` / `get_repo_info`** — Status, health, and size of all repos registered in` repos.yaml` .\n- **`get_federation_health`** — Aggregate health counts, total node/edge counts, and a rough memory estimate across the federation.\n- **`get_cross_repo_blast_radius`** — Cross-repository impact analysis when modifying a shared symbol.\n- **`get_cross_repo_blast_radius_for_repo`** — Same as` get_cross_repo_blast_radius` , but the caller disambiguates the target repo by`repo_id` instead of by symbol resolution.\n- **`search_org`** — Organization-wide symbol and code search across all registered repositories.\n\n- **`find_dead_code`** — Detects unreachable functions and unused symbols (excluding traits and tests).\n- **`suggest_refactor_targets`** — Identifies brittle code (high-coupling, low-stability candidates).\n- **`get_agent_strategy`** — Retrieves operational guidelines and strategic instructions for agents.\n- **`get_world_state`** — Summarizes active sessions, file claims, and graph freshness in a single compact call.\n\n```\n# Install (interactive — adds `lain` to PATH)\ncurl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | bash\n\n# Reload your shell, then verify\nsource ~/.zshrc   # or ~/.bashrc\nlain --version\n```\n\nSee [QUICKSTART.md](https://github.com/spuentesp/lain/blob/main/docs/QUICKSTART.md) for Homebrew, manual builds, non-interactive flags, and ONNX model setups.\n\n```\nclaude mcp add lain -- lain mcp\nlain setup --agent cursor\n```\n\nWrites `~/.cursor/mcp.json` (the file Cursor reads directly).\nWindsurf shares the same config schema, so this command works\nfor Windsurf too.\n\n```\nlain setup --agent vscode\n```\n\nWrites `.vscode/mcp.json` if it exists (project-scoped) or\n`mcp.json` in your user-config dir otherwise. Details in\n`docs/COOKBOOK.md`.\n\n```\nlain setup --agent codex     # uses `codex mcp add` when the CLI is on PATH\nlain setup --agent continue  # writes ~/.continue/config.json\nlain setup --agent generic\n```\n\nWrites `.mcp.json` at the workspace root. See `docs/COOKBOOK.md`\nfor the exact schema.\n\nRun LAIN as a shared service across multiple repositories:\n\n```\nlain server --config ./repos.yaml --transport http --port 9999\n```\n\nAccess the **Command Center UI** in your browser at `http://localhost:9999`.\n\nWhen `lain server` runs with `--transport http`, it serves the Command Center dashboard at `GET /`. It is a self-contained single-page application (SPA) that talks back to the running server over the same MCP JSON-RPC protocol.\n\n- **Overview** — Real-time node/edge stats, memory footprint, and federation health.\n- **Graph** — Interactive D3 force-directed visualizer of workspaces and symbol dependencies.\n- **Repos** — Repository table showing health, path, and node/edge statistics.\n- **Query** — Interactive query runner for`query_graph` traversals.\n- **Tools** — Form-based MCP tool runner with auto-generated*Copy as cURL* snippets for quick testing.\n\nLAIN exposes the following CLI commands:\n\n| Command | Purpose | \n|---|---|\n| `lain server` | Start the MCP server (the headline). Reads `repos.yaml` , serves MCP tools + the Command Center dashboard. Hot-reloads the config when it changes. | \n| `lain mcp` | Single-repo MCP server on stdio. Walks up from cwd for `.git` — the stable \"drop in a clone and run\" entrypoint. No`repos.yaml` required. | \n| `lain setup` | Guided onboarding: detects the repository and languages, optionally installs the semantic model, configures one MCP client ( `--agent claude-code` shells to`claude mcp add` ;`--agent generic` writes`.mcp.json` ), and verifies the result with a real MCP round trip.`--dry-run` and`--print-config` change nothing. | \n| `lain workspaces` | Manage `workspaces.yaml` . Create, list, show, activate (`use` ), forget named groups of repos. | \n| `lain repos` | Manage `repos.yaml` . Add, list, remove a repo entry. | \n| `lain query` | Run a `query_graph` ops-array against the project's persisted graph. | \n| `lain oneshot` | One-shot MCP query: boots a transient `lain mcp` server, sends a single`tools/call` , prints the result as a table, and exits. For \"just grep the symbols without keeping a server alive\". | \n| `lain init` | Scaffold a `repos.yaml` for the current directory. Walks up for`.git` , then writes a minimal config pointing at the discovered workspace. | \n| `lain ask` | Single-user LLM-assisted query (uses `semantic_search` when an embedding model is loaded; falls back to lexical heuristics via`explain_symbol` ). | \n| `lain hooks` | Agent pre-edit hook entry point: `claim` /`release` files,`overlap-check` for commit-time symbol overlap,`lock` /`unlock` for the zero-daemon filesystem-fallback layer. | \n| `lain doctor` | Read-only repository diagnosis. Reports binary identity, persisted graph freshness, structural and optional semantic capability states, installation paths, and an MCP initialize/tools-list probe. Use `--json` for the versioned machine-readable report and`--workspace PATH` outside the target clone. Exit codes are 0 ready, 1 usable but degraded, and 2 unusable. | \n| `lain capabilities` | Print the four canonical capability states and repository freshness. Add `--json` for agent-readable output. | \n| `lain status` | Print aggregate repository, index, and MCP readiness. Add `--json` for the versioned status object. | \n| `lain schema` | Emit the canonical tool-surface schema dump ( `dump [--out PATH]` defaults to`./docs/tool-schema.json` ). Pair with`make schema && git diff --exit-code docs/tool-schema.json` in CI to fail on schema drift. | \n| `scripts/demo.sh` | Capability demonstration and benchmark. Boots a real server against a synthetic repo whose call graph is known by construction, checks lain's answers against that ground truth (not merely that it answered), then benchmarks the same tools against this repo at ~3.5k nodes. `--quick` skips the build and benchmark phases;`--json FILE` writes machine-readable results;`--force-build` overrides`--quick` /`--no-build` ;`--allow-stale` skips the binary-freshness check. Exits non-zero if any check fails (or if the binary is older than any source file and`--allow-stale` was not passed). | \n\n`lain server` monitors `repos.yaml` and `workspaces.yaml` and automatically updates its federation state when they change—without restarting the process or dropping active agent connections. Both manual file edits and CLI commands (`lain repos add ...`) communicate over a local Unix socket (`~/.local/lain/run/<repos-stem>.sock`) to rebuild the index diff atomically.\n\nSee [`docs/hot-reload.md`](https://github.com/spuentesp/lain/blob/main/docs/hot-reload.md) for full operational details.\n\n| Doc | What's in it | \n|---|---|\n| **[`docs/QUICKSTART.md`](https://github.com/spuentesp/lain/blob/main/docs/QUICKSTART.md)** | Step-by-step 5-minute setup and quickstart | \n| **[`docs/USER_MANUAL.md`](https://github.com/spuentesp/lain/blob/main/docs/USER_MANUAL.md)** | Comprehensive operator and agent manual | \n| **[`docs/ARCHITECTURE.md`](https://github.com/spuentesp/lain/blob/main/docs/ARCHITECTURE.md)** | System design, graph layering, and technical rationale | \n| **[`docs/TECHNICAL.md`](https://github.com/spuentesp/lain/blob/main/docs/TECHNICAL.md)** | Deep dive into internal modules and data structures | \n| **[`docs/FEDERATION.md`](https://github.com/spuentesp/lain/blob/main/docs/FEDERATION.md)** | Multi-repo setup, org search, and cross-repo intelligence | \n| **[`docs/REPOS_YAML.md`](https://github.com/spuentesp/lain/blob/main/docs/REPOS_YAML.md)** | Schema and options for `repos.yaml` | \n| **[`docs/multiplayer.md`](https://github.com/spuentesp/lain/blob/main/docs/multiplayer.md)** | Multi-agent coordination, claims, and advisory locks | \n| **[`docs/hooks.md`](https://github.com/spuentesp/lain/blob/main/docs/hooks.md)** | Git and editor pre-edit hook configuration | \n| **[`docs/query-language.md`](https://github.com/spuentesp/lain/blob/main/docs/query-language.md)** | Syntax and operations reference for `query_graph` | \n| **[`docs/quickstart-tools.md`](https://github.com/spuentesp/lain/blob/main/docs/quickstart-tools.md)** | Complete reference guide for all MCP tools | \n| **[`docs/command-center.md`](https://github.com/spuentesp/lain/blob/main/docs/command-center.md)** | Features and usage of the web Command Center | \n| **[`docs/INDEX.md`](https://github.com/spuentesp/lain/blob/main/docs/INDEX.md)** | Full documentation sitemap | \n\n| Requirement | Details | \n|---|---|\n| **Rust** (build only) | 1.75 or newer | \n| **Git** | Required for co-change coupling analysis | \n| **ONNX Model** | Optional — required only for `semantic_search` | \n\nFor `semantic_search`, download an ONNX embedding model (or run `install.sh --download-model`):\n\n```\nmkdir -p .lain/models\n\n# BAAI/bge-small-en-v1.5 (recommended — 384d, ~120MB)\ncurl -L https://huggingface.co/BAAI/bge-small-en-v1.5/resolve/main/onnx/model.onnx \\\n  -o .lain/models/model.onnx\ncurl -L https://huggingface.co/BAAI/bge-small-en-v1.5/resolve/main/tokenizer.json \\\n  -o .lain/models/tokenizer.json\n\nexport LAIN_EMBEDDING_MODEL=$PWD/.lain/models/model.onnx\n```\n\nFor BGE-style asymmetric retrieval (optimized for short natural-language queries), configure the prefix in `.lain/tuning.toml`:\n\n```\nquery_prefix = \"Represent this sentence for searching relevant passages: \"\n```\n\n*Note: If no embedding model is configured, `semantic_search` is filtered out of `tools/list` automatically so agents are never presented with an unusable tool. All graph, blast radius, navigation, and coordination tools function without an ONNX model.*\n\n| Mode | Command | Use Case | \n|---|---|---|\n| `stdio` | `lain mcp` or`lain server --transport stdio` | Claude Code, Cursor, MCP clients | \n| `http` | `lain server --transport http --port 9999` | Command Center dashboard + curl-driven JSON-RPC | \n\n- **First-time setup issues?** See[QUICKSTART.md § First aid](https://github.com/spuentesp/lain/blob/main/docs/QUICKSTART.md#first-aid) .\n- **Run diagnostics** :`lain doctor` reports repository and MCP readiness without changing files;`lain doctor --json` emits the same result for scripts and agents.\n- **Hand-edit not picked up?** The hot-reload watcher is non-recursive and uses atomic rename. Editing the file in place (`vim repos.yaml` ) triggers a notify event within ~1 s. If you moved the file across directories, save it back into the project directory.\n- **Repo stuck in `indexing` / `degraded` / `unavailable`?** The Command Center Overview tab displays these metrics live.\n\n```\ncurl -s -X POST http://localhost:9999/mcp \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"get_federation_health\",\"arguments\":{}},\"id\":1}'\n```\n\n- **`run_build` / `run_tests` fail with \"not found\"?** Editor-launched MCP servers inherit environments that lack version-manager shims (rustup, nvm, pyenv, volta, asdf). LAIN searches known install locations automatically; to configure custom managers, see[`toolchains/README.md`](https://github.com/spuentesp/lain/blob/main/toolchains/README.md) .\n- **Answers look stale, or a symbol \"doesn't exist\" that clearly does?** Check`get_health` :\n  - `Build:` shows the binary version and git SHA. MCP stdio processes are spawned once by the client and outlive source rebuilds; restart your editor/client to pick up a newly built binary.\n  - `Status: Degraded ⚠` indicates indexing timed out. Set`LAIN_REINDEX_TIMEOUT=600` (defaults to 300s outer, 60s per-repo) to accommodate large working trees on cold cache.\n- **Two agents not seeing each other?** Verify they share the same workspace. State is persisted under`~/.local/lain/state/` , and`list_active_agents` confirms shared visibility.\n- **Force re-indexing** : Call`request_reload` via MCP or touch`repos.yaml` .\n\nThe hero demo recording in `docs/screenshots/` can be re-recorded after UI changes:\n\n```\nmake record-demo\n```\n\nOr run `npm run record-demo --prefix tests/js` for the Playwright driver (and `scripts/record-spa-demo.sh` for ffmpeg encoding). For offline fixture testing, run `make record-demo-small`.\n\n[MIT](https://github.com/spuentesp/lain/blob/main/LICENSE) — Copyright (c) 2026 spuentesp", "url": "https://wpnews.pro/news/show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents", "canonical_source": "https://github.com/spuentesp/lain", "published_at": "2026-09-21 00:15:55+00:00", "updated_at": "2026-09-21 00:23:11.854039+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "ai-tools"], "entities": ["LAIN", "Model Context Protocol", "Claude Code", "Cursor", "GitHub Copilot", "Codex", "Cline", "Windsurf"], "alternates": {"html": "https://wpnews.pro/news/show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents", "markdown": "https://wpnews.pro/news/show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents.md", "text": "https://wpnews.pro/news/show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents.txt", "jsonld": "https://wpnews.pro/news/show-hn-lain-a-structural-code-graph-and-agent-coordinator-for-coding-agents.jsonld"}}