by clay-good
openlore provides persistent architectural memory for AI coding agents by turning codebases into queryable knowledge graphs featuring static analysis, living specs, automated drift detection, and graph-native MCP tools to eliminate context decay and drastically slash orientation token costs.
# Add to your Claude Code skills
git clone https://github.com/clay-good/OpenLore[!NOTE]
spec-genhas been renamed toOpenLore. The npm package is nowopenloreand the CLI command isopenlore. Existing projects: rename your.spec-gen/directory to.openlore/and reinstall (npm i -g openlore). See docs/RENAME-TO-OPENLORE.md for the full migration checklist.
Persistent architectural memory and structural cognition for AI coding agents.
openlore turns any evolving codebase into a navigable knowledge graph backed by OpenSpec living specifications. It maintains persistent architectural context across agent sessions: graph structure, specs, decisions, drift state, and semantic retrieval — so agents start each task already oriented instead of re-discovering the system from file reads.
AI agents are powerful but amnesiac. On every new task:
openlore closes this loop. Run a full analysis once, then keep the graph incrementally updated as the codebase evolves. Even greenfield projects become cognitively "brownfield" after only a few agent sessions — architectural context fragments, decisions disappear, and agents repeatedly reconstruct the same understanding from scratch.
No comments yet. Be the first to share your thoughts!
openlore persists that context continuously: structure, specs, decisions, drift state, and graph relationships remain queryable across sessions.
Three layers, each usable independently:
| Layer | What it does | API key? |
|-------|-------------|----------|
| 1. Static Analysis | Call graph, clusters, McCabe CC, external deps → CODEBASE.md digest | No |
| 2. Spec Layer | LLM-generated living specs, ADRs, drift detection, decision gates | For generation |
| 3. Agent Runtime | 45 MCP tools — orient(), semantic search, graph expansion | No |
You can use layer 1 alone to give agents structural context. Add layer 2 for semantic intent and architectural governance through OpenSpec-compatible living specifications. Layer 3 keeps that context continuously accessible through graph-native MCP tools once openlore mcp is running.
| | Cursor / Claude Code | Sourcegraph | openlore | |---|---|---|---| | Graph-aware MCP context | ❌ file-based reads | Partial | ✓ call graph + clusters | | Spec drift detection | ❌ | ❌ | ✓ milliseconds, no API | | Architectural decision gates | ❌ | ❌ | ✓ pre-commit hook | | Offline structural analysis | ❌ | ❌ | ✓ | | Token-efficient orient() | ❌ | ❌ | ✓ ~1–3k vs 15–50k tokens | | Living spec generation | ❌ | ❌ | ✓ | | Persistent cross-session architectural memory | ❌ | Partial | ✓ | | Long-session confidence decay (Epistemic Lease) | ❌ | ❌ | ✓ |
Traditional coding agents reconstruct architecture from repeated file reads every session. openlore persists it as a queryable graph.
Minimum to see value — no API key needed:
npm install -g openlore
cd /path/to/your-project
openlore analyze # build call graph, clusters, CODEBASE.md
openlore mcp # start MCP server
Then ask your agent: orient("add a new payment method")
That single call returns the relevant functions, their call neighbours, matching spec sections, and insertion-point candidates — preserving architectural continuity across sessions instead of forcing the agent to repeatedly reconstruct context from raw file reads. In practice, this often reduces orientation cost from ~30,000 exploratory tokens to ~1,000 targeted tokens.
Full pipeline (specs + decisions — optional and additive):
openlore generate # generate living specs (requires API key)
openlore drift # detect spec/code drift
openlore decisions # manage architectural decisions
git clone https://github.com/clay-good/openlore
cd openlore
npm install && npm run build && npm link
nix run github:clay-good/openlore -- analyze
nix shell github:clay-good/openlore
System flake:
environment.systemPackages = [ openlore.packages.x86_64-linux.default ];
{
"functions": [
{
"name": "processPayment",
"file": "src/payments/processor.ts",
"risk": "medium",
"fanIn": 4,
"callers": ["handleCheckout", "retryFailedCharge"],
"callType": "direct"
},
{
"name": "validateCard",
"file": "src/payments/validator.ts",
"risk": "low",
"fanIn": 1,
"testedBy": [{ "name": "validateCard.test.ts", "confidence": "called" }]
}
],
"specDomains": ["payments — §CardValidation, §PaymentFlow"],
"insertionPoints": [
"src/payments/processor.ts:87 — after existing charge logic"
],
"callPath": "POST /charge → handleCheckout → processPayment → validateCard → stripeClient.charge"
}
One graph query replaces most exploratory file reads. The agent knows exactly where to look and what risks to consider.
Analyze (no API key)
Continuously maintains a structural representation of your codebase using pure static analysis. Builds a full call graph persisted to SQLite, runs label-propagation community detection to cluster tightly coupled functions, computes McCabe cyclomatic complexity for every function, and extracts DB schemas, HTTP routes, UI components, middleware chains, and environment variables. Outputs .openlore/analysis/CODEBASE.md — a ~600-token structural digest that compresses the equivalent of tens of thousands of exploratory tokens into a small, queryable summary.
With --watch-auto, the call graph updates incrementally on every file save: changed file and its direct callers are re-parsed and the graph is atomically swapped. Orient and BFS queries remain live between full analyze runs.
Generate (API key required)
Sends the analysis to an LLM in 6 structured stages: project survey → entity extraction → service analysis → API extraction → architecture synthesis → ADR enrichment. Produces openspec/specs/ living specifications in RFC 2119 format with Given/When/Then scenarios.
Drift (no API key)
Compares git changes against spec mappings in milliseconds. Detects: Gap (code changed, spec not updated), Uncovered (new file, no spec), Stale (spec references deleted files), ADR gap (code changed in an ADR-referenced domain). Installs as a pre-commit hook.
MCP (no API key)
45 graph-native tools exposed over stdio. Together they act as a persistent architectural runtime for coding agents: orientation, graph traversal, semantic retrieval, drift awareness, decision context, and structural risk analysis.
orient() is the main entry point — one call replaces 10+ file reads. detect_changes risk-scores changed functions using call graph centrality × change type multiplier. See docs/mcp-tools.md.
orient() runs in ~430µs p50 against a 15k-node codebase (TypeScript compiler, ~79k edges). Full benchmark results: scripts/BENCHMARKS.md.
Epistemic Lease (no API key)
Core principle: EpistemicLease models architectural drift as a behavioral navigation phenomenon rather than a semantic understanding problem. Context decay is driven by where the agent goes (cross-module trajectory), not what it knows.
As a session grows longer, agents naturally shift from authoritative graph retrieval toward internally cached reasoning. This is useful for fluency but dangerous for architectural correctness — cross-module assumptions go stale, dependency hallucinations accumulate, and delegation prompts embed incorrect repository understanding that cannot easily be corrected downstream.
The Epistemic Lease models this decay explicitly. Every MCP tool response carries a freshness signal when the agent's architectural context has degraded or expired. Decay is triggered by any of: time elapsed since orient(), git hash divergence from the orient baseline, weighted cognitive load accumulation (heavier tools count more), or cross-module file access breadth.
The signal escalates through three levels to resist warning blindness:
| Level | Trigger | Signal style |
|---|---|---|
| Degraded | load ≥ 30, age ≥ 15min, or cross-module density ≥ 0.15 | Advisory signal appended |
| Stale | load ≥ 60, age ≥ 30min, git hash divergence, or density ≥ 0.30 | Procedural block prepended: what NOT to do |
| Stale [Elevated] | load ≥ 85 or age ≥ 45min | Risk-framing: names downstream consequences |
| Stale [Critical] | load ≥ 110 or age ≥ 60min | Imperative: STOP. Call orient(). — minimal, hardest to skim |
Cross-module density is computed as a sliding-window trajectory model: switches_in_last_15_calls / 15. The fixed denominator prevents false positives during session warmup. Each module switch adds +5 cognitive debt; a high-density window adds +15; a burst (density ≥ 0.60) adds +20. A 5s dampening window prevents back-and-forth from double-counting.
An oscillation coefficient (repeated_bigram_transitions / total_transitions) separately distinguishes confusion loops (A→B→A→B scores 1.0) from genuine exploration (A→B→C→D scores 0.0). When already stale, a heavy architectural tool (weight ≥ 8) or density