OpenLore

Local code graph that gives coding agents task context and checks changes before they land

By Clay Good (individual) TypeScript Local · stdio Developer toolsKnowledge and memory

67 popularity score ★ 358 ↓ 3.0k/wk

Connect your client

Local (npm)

Add in one click

Opens the app, which asks before it adds the server.

Or add it by command or config

FirstTerminal
npm install -g openlore
cd <PROJECT_DIR> && openlore analyze
Claude CodeTerminal
claude mcp add openlore -- openlore mcp
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "openlore": {
      "command": "openlore",
      "args": [
        "mcp"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "openlore": {
      "command": "openlore",
      "args": [
        "mcp"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "openlore": {
      "type": "stdio",
      "command": "openlore",
      "args": [
        "mcp"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.openlore]
command = "openlore"
args = ["mcp"]
Gemini CLITerminal
gemini mcp add --scope user openlore openlore -- mcp
Local (from source)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

FirstTerminal
git clone https://github.com/clay-good/openlore
cd openlore && npm install && npm run build
Claude CodeTerminal
claude mcp add openlore -- node '<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js' mcp
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "openlore": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js",
        "mcp"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "openlore": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js",
        "mcp"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "openlore": {
      "type": "stdio",
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js",
        "mcp"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.openlore]
command = "node"
args = ["<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js", "mcp"]
Gemini CLITerminal
gemini mcp add --scope user openlore node -- '<ABSOLUTE_PATH_TO_CLONE>/dist/cli/index.js' mcp

Settings 6

Set together: remote embeddings
EMBED_BASE_URL Optional: Base URL of an OpenAI-compatible embeddings API. Does nothing without EMBED_MODEL. For semantic search.
EMBED_MODEL Optional: Model name for the remote embeddings API, needed together with EMBED_BASE_URL. For semantic search.
EMBED_API_KEY secret Optional: Key for the remote embeddings API, when it asks for one. For semantic search.
ANTHROPIC_API_KEY secret Optional: Picked first for the optional LLM features when no provider is configured. GEMINI_API_KEY, OPENAI_COMPAT_API_KEY or OPENAI_API_KEY also work. For spec generation, decision consolidation.
OPENLORE_TELEMETRY Optional: Set to 1 to log tool calls locally in .openlore/telemetry/. Nothing is uploaded.
OPENLORE_LLM_LOGS Optional: Set to 1 to keep redacted LLM prompts and responses in .openlore/logs/.

What it does

OpenLore indexes a repository with static analysis (tree-sitter parsing into a local SQLite graph) and serves that graph to a coding agent over MCP. Asked about a task, it answers with the functions involved, who calls them, the matching specs and tests, and where new code would fit, so the agent can skip much of the file-by-file exploring. The same graph holds Infrastructure-as-Code resources and recorded architectural decisions. It covers 18 programming languages and 12 IaC formats, Terraform and Kubernetes among them.

The second half is change checking. Tools report the blast radius of the current diff and which tests reach it, classify each changed export as breaking or not, flag a diff that opens a new route into a boundary you have declared, and settle claims like "this function is dead" with a cited verdict. Notes and decisions are tied to symbols, so they follow renames and expire when the code under them changes. No language model is called to answer queries, and the core features need no API key.

The README talks about 80 tools, and the v3.5.0 registry in src/cli/commands/mcp.ts does hold 80. A plain `openlore mcp` shows only 15 of them, though: the `substrate` preset, where every tool is annotated read-only. You get `remember`, `record_decision` and the other writing tools by starting it with `--preset memory`, `--preset minimal` or `--preset full` (`--all-tools`). Other presets exist for navigation only, claim checking, multi-repo federation and parallel-work coordination. Any single tool result is truncated at 256 KB (`MCP_TOOL_MAX_BYTES` in src/constants.ts). Beside the server the package ships a CLI (`openlore install`, `analyze`, `review`, `prove`, `doctor`) and a GitHub Action.

What it needs

RuntimeNode.js 22.19+
Runs onmacOS, Windows, Linux

Install with `npm install -g openlore`, then run `openlore install` or `openlore analyze` in the repository to build the index under `.openlore/` (the `analyze_codebase` tool can also build it). Analysis, navigation and the checking tools need no account or key. Spec generation, LLM-backed verification and decision consolidation need ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_COMPAT_API_KEY or OPENAI_API_KEY.

Limits

  • Not covered Static analysis only: reflective calls with a non-literal target, eval, and DI or plugin registries with no visible binding are absent from the graph
  • Not covered Search is BM25 keyword matching by default. Semantic search needs `openlore embed --local` (about 23 MB, CPU) or EMBED_BASE_URL plus EMBED_MODEL
  • Limit The first index of a large monorepo takes minutes, after which packages can be re-analyzed one at a time with `--shard`
  • Limit A save that touches more than 40 dependent files leaves the rest marked stale until a later re-index (INCREMENTAL_CLOSURE_BUDGET in src/constants.ts)
  • Size cap Each tool result is truncated at 256 KB
  • Not covered The default `substrate` preset exposes 15 of the 80 tools. Others need `--preset <name>` or `--all-tools`
  • Limit Spec prose written by an LLM varies in quality and needs review, by the maker's own account
  • Not covered It never edits source code. Renames and moves across files are left to LSP tooling
  • Limit The README on main already counts 83 tools and builds local vectors in the background (opt out with "embedding": {"provider": "none"}). Both are unreleased, so 3.5.0 has neither
  • Limit declare_footprint, get_handoff_briefing and certify_service_contract are registered on main but not in the published package yet

Static analysis only. Reflective calls with non-literal targets, computed dispatch, eval, DI or plugin registries with no visible binding, and cross-language bridges are missing from the graph. Search defaults to BM25 keywords with no stemming, so abbreviated names can be missed. Semantic search needs `openlore embed --local` (about 23 MB, CPU) or a remote EMBED_BASE_URL. The first index of a large monorepo takes minutes. When one save touches more than 40 dependent files (the default budget), the watcher marks the rest stale until it re-indexes. The maker's own benchmark shows it adds cost on small, familiar repos with shallow questions. It never edits source code.

Who it suits

It suits developers using Claude Code, Cursor, Cline or similar agents on large, private or polyglot codebases (including the IaC that deploys them) who want structural context and pre-commit checks without sending code to a hosted service. Everything runs on your machine, and the default tool set only reads. On a small repo the agent already handles well, the maker's measurements show the agent's built-in search is often cheaper. If you need an agent to perform renames or moves across files, look elsewhere. OpenLore locates and checks code but does not edit it, and its README points to LSP toolkits for that work.

Tools 60 of 80

50 only read, 8 change things, 2 can delete or overwrite. A ? marks an optional parameter.

orient
Takes a task description and returns the functions, callers, specs, tests and insertion points it touchesdirectory?: stringtask: stringlimit?: numbertokenBudget?: numberlean?: booleanrankBy?: enum
analyze_codebase changes
Runs or refreshes the full static analysis of a repository and writes the local indexdirectory?: stringforce?: boolean
get_architecture_overview
Cluster-level map of the codebase with each cluster's role and linksdirectory?: string
prepare_spec_generation
Gathers the read-only context needed to draft specs for a part of the codedirectory?: stringdomain: stringcursor?: stringmaxItems?: numbermaxResponseBytes?: number
prepare_spec_repair
Gathers the read-only context needed to fix specs that have drifted from codedirectory?: stringdomain: stringbaseRef?: stringcursor?: stringmaxItems?: numbermaxResponseBytes?: number
get_refactor_report
Ranks functions with structural problems such as unreachable code or overloaded hubsdirectory?: string
get_call_graph
Lists hub functions, entry points and layer violations from the call graphdirectory?: string
get_duplicate_report
Reports groups of exact, renamed and near-duplicate codedirectory?: stringresponseFormat?: enum
get_signatures
Short function and class signatures per file, filterable by pathdirectory?: stringfilePattern?: string
get_subgraph
Call-graph neighbourhood of one function, upstream or downstream, to a set depthdirectory?: stringfunctionName: stringdirection?: enummaxDepth?: numberformat?: enumdirectResolvedOnly?: boolean
trace_execution_path
Finds call paths between two functionsdirectory?: stringentryFunction: stringtargetFunction: stringmaxDepth?: numbermaxPaths?: numberdirectResolvedOnly?: booleanvalueLevel?: booleanvalueParam?: string
get_mapping
Shows which code is mapped to which spec requirementsdirectory?: stringdomain?: stringorphansOnly?: boolean
check_spec_drift
Compares git changes with spec mappings and reports gaps or stale specsdirectory?: stringbase?: stringfiles?: arraydomains?: arrayfailOn?: enummaxFiles?: integer
analyze_impact
Risk, callers, callees and governing decisions for changing one functiondirectory?: stringsymbol: stringdepth?: numberdirectResolvedOnly?: booleanvalueLevel?: booleanvalueParam?: string
select_tests
Picks the tests that reach a change, with the path and reason for eachdirectory?: stringchangedSymbols?: arraydiffRef?: stringmaxDepth?: numberdirectResolvedOnly?: boolean
blast_radius
Briefing on the current diff: affected callers and layers, tests to run, specs that driftdirectory?: stringbaseRef?: stringdepth?: numbermaxSymbols?: number
find_dead_code
Reachability sweep for code nothing calls, tagged by confidencedirectory?: stringifDeleted?: stringmaxResults?: numberfilePattern?: stringdirectResolvedOnly?: boolean
verify_claim
Checks a structural or decision claim and answers confirmed, refuted or unverifiable with a citationdirectory?: stringkind: enumsubject: stringobject?: string
structural_diff
Graph-level diff between two states: functions, edges and signatures added, removed or changeddirectory?: stringbaseRef?: stringheadRef?: stringmaxResults?: numberfiles?: arraydeclaredFootprint?: objectpeerFootprints?: array
get_change_coupling
Files that change together, mined from git historydirectory?: stringfile?: stringlimit?: number
check_architecture
Checks the code against layer, dependency and cycle rules declared in .openlore/architecture.jsondirectory?: stringfrom?: stringto?: string
get_critical_hubs
Most depended-on functions with a stability scoredirectory?: stringlimit?: numberminFanIn?: number
get_function_skeleton
A source file with logs and inline comments stripped, keeping signatures and structuredirectory?: stringfilePath: string
get_god_functions
Functions with very high fan-out, in the project or one filedirectory?: stringfilePath?: stringfanOutThreshold?: number
suggest_insertion_points
Existing functions best suited to extend for a new featuredirectory?: stringdescription: stringlimit?: numberlanguage?: string
search_code
Searches indexed functions by keywords, or by meaning once embeddings are ondirectory?: stringquery: stringlimit?: numberlanguage?: stringminFanIn?: numbertokenBudget?: numbermode?: enumquestionKind?: enum
search_unified
Searches code and spec requirements togetherdirectory?: stringquery: stringlimit?: numberlanguage?: stringdomain?: stringsection?: string
get_function_body
Source code of a named functiondirectory?: stringfilePath: stringfunctionName: stringfocus?: stringfocusKind?: enum
get_file_dependencies
Imports of a file and the files importing itdirectory?: stringfilePath: stringdirection?: enum
generate_change_proposal deletes
Creates an OpenSpec change proposal from a story or feature descriptiondirectory?: stringdescription: stringslug: stringstoryContent?: string
annotate_story deletes
Fills the risk_context section of a BMAD story file from structural analysisdirectory?: stringstoryFilePath: stringdescription: string
get_route_inventory
Detected HTTP routes with method, path, handler and frameworkdirectory?: string
get_middleware_inventory
Detected middleware by type and frameworkdirectory?: string
get_schema_inventory
ORM tables and fields found in the codedirectory?: string
get_ui_component_inventory
Detected UI components with their props and filesdirectory?: string
get_env_vars
Environment variables the code reads, with required and default flagsdirectory?: string
get_external_packages
Direct dependencies from the project's package manifestsdirectory?: string
generate_tests changes
Writes test files from OpenSpec scenarios for several test frameworksdirectory?: stringdomains?: arrayframework?: enumuseLlm?: booleandryRun?: boolean
get_minimal_context
Signature, body, direct callers and callees needed to change one functiondirectory?: stringfunctionName: stringfilePath?: stringrankBy?: enumtokenBudget?: number
get_landmarks
Key landmark functions to anchor navigation in the codebasedirectory?: stringlimit?: numberlabel?: string
get_map
Compact map of the codebasedirectory?: stringcommunityId?: string
find_path
Finds a path between two symbols in the graphdirectory?: stringfrom: stringto: stringuseCallDistance?: booleandirectResolvedOnly?: boolean
federation_status changes
Status of linked sibling repositories; adopts newly indexed ones into the federation manifestdirectory?: string
change_impact_certificate changes
Says whether a diff opens a new path into a declared sensitive boundary; can save the certificatedirectory?: stringbaseRef?: stringchange?: stringpersist?: boolean
plan_parallel_work
Orders a list of tasks into waves that can run in parallel without conflictsdirectory?: stringtasks: array
map_in_flight_conflicts
Finds collisions between branches, pull requests and tasks already in progressdirectory?: stringbaseRef?: stringincludeBranches?: booleanbranches?: arrayincludePullRequests?: booleantasks?: arraymaxChanges?: number
report_coverage_gaps
Important code that no test reaches, ranked by significancedirectory?: stringmaxResults?: numberfilePattern?: stringchangedSymbols?: arraydiffRef?: stringdirectResolvedOnly?: boolean
certify_public_surface
Exported API of a package, or a breaking-change verdict per export for a diffdirectory?: stringbaseRef?: stringmaxResults?: number
briefing_since
Changed symbols since a base ref, ranked for catching updirectory?: stringbaseRef?: stringfilePattern?: stringmaxResults?: number
find_clones
Finds existing copies of one function or code snippetdirectory?: stringsymbol?: stringsnippet?: stringminSimilarity?: numbermaxResults?: number
locate_symbol_span
Exact line and byte span of a known symbol, with a staleness checkdirectory?: stringsymbol: string
analyze_error_propagation
How errors and exceptions flow through the codedirectory?: stringsymbol: stringmaxDepth?: number
analyze_env_impact
What reads an environment variable and what would break if it were removeddirectory?: stringname: stringmaxDepth?: number
detect_changes
Recently changed functions ranked by blast radiusdirectory?: stringbase?: string
get_health_map
Dashboard of hubs, god functions, layer violations and volatile filesdirectory?: stringlimit?: number
record_decision changes
Records a draft architectural decisiondirectory?: stringtitle: stringrationale: stringconsequences?: stringaffectedFiles?: arraysupersedes?: stringscope?: enumconstraints?: object
approve_decision changes
Approves a pending decision; its description asks for explicit human sign-off firstdirectory?: stringid: stringnote?: string
sync_decisions changes
Appends approved decisions to their spec.md filesdirectory?: stringdryRun?: booleanid?: string
remember changes
Saves a note anchored to a symbol or file, invalidated when that code changesdirectory?: stringcontent: stringanchors?: arraytags?: arraytype?: enumsupersedes?: stringtrigger?: objectpinned?: booleanclaims?: array
recall
Returns stored notes for the code at hand with a freshness verdictdirectory?: stringtask?: stringlimit?: numbertokenBudget?: numberasOf?: stringchangedSince?: stringtype?: string

Similar servers