Open-source code + knowledge graph memory engine, fusing SAGE self-evolving graph memory with CodeGraph structural code understanding.
License: MIT · Runtime: Node.js ≥ 22 · Graph DB: Kuzu (embedded, Cypher) · No LLM required (deterministic)
EngramGraph is a general-purpose engine. The defaults ("single repo + generic markdown + git signals") work out of the box for any project; project-specific behaviour is supplied through pluggable adapters.
Vector search ("find me similar memories") and graph traversal ("find me structurally related nodes") are complementary. EngramGraph adds the graph half:
"I want to change
execute()→ the engine walks: callers → related specs → the decisions behind them."
npm install -g engramgraphThis puts the egr CLI on your PATH so the Quickstart commands below work from
any directory. Or run the CLI without a global install:
npx engramgraph index ./srcegr also ships an MCP server, so an assistant can query the graph — and update
it — without you running anything by hand. This is not registered
automatically, and deliberately so: a package that writes itself into your
assistant's tool configuration during npm install has granted itself tool
access without being asked.
One command for Claude Code:
claude mcp add egr -- npx egr-mcpConfirm it took — the install is not the evidence, this is:
claude mcp list # egr … ✓ ConnectedFor a project everyone on the team should get, use --scope project instead;
that writes a .mcp.json you can commit, and each person is prompted to approve
it once. Keep the entry portable — an absolute path to one machine's Node
install is the usual reason a checked-in .mcp.json silently does nothing on
someone else's laptop. ENGRAM_DB defaults to ./.engram/graph.db, so it can
usually be omitted.
Codex / Cursor / Windsurf, all 8 tools, and an example flow: docs/MCP.md.
Indexing from the assistant has one limit worth knowing. The
index_codetool takes file contents, not a directory — it does not walk the filesystem. That makes it a good fit for updating the files an assistant just edited, and a poor one for indexing a whole repository. For that, runegr index ./src.
EngramGraph has two independent native dependencies, and they fail in different ways. Knowing which one you hit tells you whether the install is broken or merely missing one language:
| Package(s) | Required? | If no prebuilt binary exists for your platform | |
|---|---|---|---|
| Graph database | ryugraph |
Yes | Built from source via cmake-js. If that fails you have no working egr at all. |
| Language grammars | tree-sitter + 12 grammar packages |
Per language | Built from source via node-gyp. If that fails, only that language is unavailable — egr installs and indexes everything else. |
Prebuilt coverage as of engramgraph@0.9.1:
| Platform | Graph DB | Grammars | What you get |
|---|---|---|---|
| Linux x64, glibc ≥ 2.38 (Ubuntu 24.04+, Debian 13+) | ✅ prebuilt | ✅ all 13 prebuilt | Everything, no compiler needed |
| macOS ARM64 (Apple Silicon) | ✅ prebuilt | Everything if you have a C/C++ toolchain; otherwise all languages except Dart | |
| macOS x64 (Intel) | ✅ prebuilt | Same as above | |
| Windows x64 | ✅ prebuilt | Same as above — see Windows for the two traps that make this harder than it sounds | |
| Windows ARM64 | ❌ no prebuilt | Needs a toolchain even for the graph database; untested | |
| Linux ARM64 (any glibc) | ❌ broken upstream | Upstream ships the x86-64 binary under the arm64 filename — predictable-labs/ryugraph#48 | |
| Linux x64, glibc < 2.38 (Ubuntu 22.04 LTS, Debian 12) | ❌ broken upstream | ✅ all 13 prebuilt | ryugraph's binary needs a newer glibc than these still-common LTS distros ship |
Linux x64 is the only platform that installs with no compiler at all. Everywhere
else, npm install compiles at least the Dart grammar
(@vokturz/tree-sitter-dart
publishes a prebuilt binary for linux-x64 only). That grammar is an
optional dependency: if the build fails, npm continues, the install succeeds, and
egr tells you Dart is unavailable when you index. An install-time notice says so up
front, before the compiler output scrolls past.
Why Dart specifically. Every other grammar in this project ships binaries for all six platform/arch pairs. Dart is the exception because it is the only npm Dart grammar that is ABI-compatible with this project's pinned
tree-sittercore — the two alternatives that do ship full prebuilds load cleanly and then throw insideParser.setLanguage.src/code-graph/grammars.d.tsrecords the four-candidate comparison. It is a known-bad trade, kept because the alternatives are worse, and worth revisiting if a better-maintained package appears.
The Linux ARM64 row affects Docker Desktop on Apple Silicon Macs (defaults to
linux/arm64) and AWS Graviton / other ARM64 Linux hosts — if egr fails there
it is very likely #48, not
your setup. Forcing --platform linux/amd64 works around it (at the cost of emulation)
until upstream is fixed.
Also note: npm ≥ 11 gates native install scripts (including ryugraph's) behind an
approval prompt by default. If npm install prints npm warn allow-scripts, run
npm approve-scripts --all and reinstall — otherwise the native binary is never
copied into place.
How these rows were checked. The
ryugraphfindings come from direct investigation on 2026-07-10; the Windows x64 row from a real install on Windows 11 on 2026-08-04; the grammar coverage from reading the published packages' shippedprebuilds/directories, re-asserted on every test run bytest/language-support.test.ts. Earlier revisions of this table citedrelease-compat-check.ymlas an automated release gate — that citation was wrong: the workflow raced the publish job and gave up before the package reached npm, so its matrix never once executed and no release has actually been gate-verified. Repairing that gate is tracked separately; until it runs, treat this table as manually checked, because that is what it is.
Installing the C++ toolchain on Windows has two traps that produce the same error
message, gyp ERR! find VS - missing any VC++ toolset:
node-gyp11.x does not recognise Visual Studio 2026 (v18) — and 11.x is what npm 11 bundles, so this is the common case. Its Visual Studio finder hard-codes version 15/16/17 → 2017/2019/2022 and discards anything else, reporting a machine with a complete VS 2026 MSVC install asunknown version "undefined". NeitherVCINSTALLDIRnormsvs_versiongets around it on that version. Two ways out: install the C++ workload into Build Tools 2022 (works regardless of node-gyp version), or upgrade node-gyp — 12.x does recognise VS 2026 (verified in CI: it reportschecking VS2026 (18.8.x)and offers2026as a validmsvs_version). The exact 11.x→12.x version where support landed is unverified; check your own withnpx node-gyp --version.- Adding the
VCToolsworkload does not install a compiler. Inside that workload,Microsoft.VisualStudio.Component.VC.Tools.x86.x64is Recommended, not Required — so a machine can report "Visual Studio C++ core features" while having no compiler at all. Select it (and a Windows SDK) explicitly.
Via the Visual Studio Installer: pick Visual Studio Build Tools 2022 → Modify → check Desktop development with C++ → confirm MSVC v143 … build tools and a Windows 11 SDK are checked on the right. Or from an elevated shell, not run from the installer's own directory:
& "C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe" modify `
--installPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" `
--channelId VisualStudio.17.Release `
--productId Microsoft.VisualStudio.Product.BuildTools `
--add Microsoft.VisualStudio.Workload.VCTools `
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
--add Microsoft.VisualStudio.Component.Windows11SDK.26100 `
--passive --norestartVerify by what node-gyp prints, not by the installer's exit code. The installer
returning 0 does not mean the compiler landed — that is exactly the state trap 2
produces. Re-run the install and look for this line:
gyp verb find VS - found VC++ toolset: v143
Its presence is the whole signal. Its absence is the failure, whichever trap caused it.
Why macOS Intel isn't in the automated release gate. (This is about the gate's design; separately, the gate has not been executing at all — see the note above.) Excluding Intel Mac isn't an oversight, it's a deliberate call. Two independent facts point the same direction:
- GitHub's own Intel Mac (
macos-13) hosted runners currently have severe queue capacity constraints. A real test run on 2026-07-10 sat inqueuedfor ~50 minutes without ever starting. GitHub Actions'timeout-minutescannot bound this — it only starts counting once a job actually begins executing, not while queued — so there is no reliable way to cap how long a release could be stuck waiting on this runner. - Apple's own support lifecycle is winding down. macOS 26 "Tahoe" is the last major release with Intel Mac support; macOS 27 "Golden Gate" (expected September 2026) drops Intel entirely, with only security-only updates continuing on macOS 26 until roughly 2029. Intel Mac is a sunsetting platform on both Apple's and GitHub's side.
Given that, blocking every release on a runner that may never become available — for a
platform winding down anyway — didn't make sense. Instead, macos-x64-intel-manual in
release-compat-check.yml runs Intel Mac
verification as a best-effort, non-blocking job: triggerable manually via
workflow_dispatch whenever someone wants to check it, continue-on-error: true so it
never fails a release, and excluded from the release: published trigger so a real
release is never left waiting on it. If you specifically need Intel Mac support
confirmed, trigger that job manually and check its result — but the release process
itself doesn't depend on it.
Native binary loading failures on Linux surface through Node's dlopen, whose error
text doesn't always describe the real cause:
| Error you see | What it usually means |
|---|---|
ryujs.node: cannot open shared object file: No such file or directory (file does exist per ls) |
Wrong CPU architecture — the binary at that path is for a different platform/arch than the one you're running on |
.../libc.so.6: version 'GLIBC_2.38' not found |
Your distro's glibc is older than what the prebuilt binary requires (see matrix above) |
npm warn allow-scripts ... not yet covered by allowScripts |
npm ≥ 11 blocked the install script that copies the native binary — run npm approve-scripts --all then reinstall/rebuild |
gyp ERR! find VS - missing any VC++ toolset (Windows) |
No usable MSVC compiler. Two different causes produce this identical line — see Windows: enabling the Dart grammar. Note this is not fatal: it only costs you Dart |
gyp ERR! find VS unknown version "undefined" found at ...\18\BuildTools |
node-gyp 11.x doesn't recognise Visual Studio 2026. Install the C++ workload into Build Tools 2022, or upgrade node-gyp to 12.x |
A wall of node-gyp output ending in npm error code 1, on Windows/macOS |
The Dart grammar failed to compile. Expected without a C/C++ toolchain, and survivable — every other language still works |
Dart support is not enabled in this installation (at index time) |
The above, seen from the other end. egr is working; the Dart grammar isn't built here |
IO exception: Failed to download extension: algo |
god-nodes, communities and related need ryugraph's ALGO extension, which INSTALL ALGO fetches from extension.ryugraph.io on first use. This is the only part of egr that reaches the network — every other command works offline. The error now prints the offline build steps; see also docs/CLI.md |
If you hit something not covered here, please check
predictable-labs/ryugraph's issues
before assuming it's an EngramGraph bug — most native-loading failures originate in the
ryugraph dependency, not this package.
A plain npm install — global, npx, or as a project dependency — currently prints
warnings like this:
npm warn deprecated npmlog@6.0.2: This package is no longer supported.
npm warn deprecated are-we-there-yet@3.0.1: This package is no longer supported.
npm warn deprecated gauge@4.0.4: This package is no longer supported.
npm warn deprecated tar@6.2.1: ...widely publicized security vulnerabilities...
4 vulnerabilities (3 high, 1 critical)
The exact count moves as advisories are published against the same pinned versions — it
was four high when this section was written, and a consumer install on 2026-08-08
reported one critical and three high, carrying twelve advisories on tar alone. The
release gate (npm run audit:ship) audits a packed tarball installed into an empty
directory, so this is measured against what you get rather than what this repo pins;
security/accepted-advisories.json records the acknowledgement and the date it expires.
All of them trace back to a single chain: ryugraph (this package's embedded graph-DB
engine) pins cmake-js@^7.3.0, which depends on tar@^6.2.0 (several high-severity
path-traversal CVEs, fixed in tar@7.5.11+) and the now-deprecated npmlog/gauge/
are-we-there-yet stack. cmake-js@8.0.0 already dropped npmlog and bumped tar to
^7.5.6 — the fix exists upstream, ryugraph just hasn't picked it up yet. Tracked at
predictable-labs/ryugraph#49.
Actual exposure is narrower than the warning count suggests. ryugraph's own
install.js only invokes cmake-js (and therefore tar) when no prebuilt native binary
exists for your platform — see the platform support matrix above. On every platform
listed there as ✅ Works, the prebuilt binary is copied directly and cmake-js/tar
are fetched into node_modules but never executed. The declared vulnerability is real
(and shows up in npm audit/SBOM tooling regardless), but the live exploitation window is
effectively limited to build-from-source paths (unsupported platforms, or
NPM_CONFIG_BUILD_FROM_SOURCE set explicitly).
If you consume engramgraph as a dependency inside your own project (not a global
install), you can clear this yourself today — add the same override to your own
package.json:
"overrides": {
"cmake-js": "^8.0.0"
}(npm-only syntax shown; pnpm/Yarn have equivalent pnpm.overrides / resolutions
fields.) This works because npm's overrides field only takes effect at the root of
whichever project runs npm install — it does not propagate from a dependency's own
package.json to yours, which is exactly why engramgraph's own overrides entry (added
in an earlier fix) doesn't help you: it only cleans npm audit inside this repo's own
source checkout, not for anyone installing the published package. For a global install or
npx engramgraph there is no project root to attach an override to, so that path has no
workaround available yet — it depends on the linked upstream issue landing.
# 1. Index a repo into the graph (code + optional docs)
egr index ./src --docs
# 2. "What breaks if I change this function?"
egr callers myFunction --depth 2
# 3. "Which decisions sit behind this spec?"
egr impact SPEC-001The graph DB lives at ENGRAM_DB (default ./.engram/graph.db).
Full command reference: docs/CLI.md.
Library use (Embedded / REST below) needs a local dependency, not the global CLI — install with
npm install engramgraph(no-g) soimport ... from "engramgraph"resolves.
import { EmbeddedClient } from "engramgraph";
const client = new EmbeddedClient(); // SingleRepoIsolation by default
await client.init(); // opens graph.db + ensures schema
const rows = await client.query("MATCH (f:Function) RETURN f.name AS name");
await client.close();import { createServer, GraphConnection } from "engramgraph";
const conn = GraphConnection.open("./.engram/graph.db");
const app = createServer({ connection: conn }); // Hono app; routes under /graph/*
// GET /health → { status: "ok" }Or just egr serve --port 3000. API reference: docs/API.md.
| Mode | Entry | Use case |
|---|---|---|
| Embedded | EmbeddedClient |
Same-process, zero HTTP overhead (e.g. same-process integration) |
| REST | createServer() (Hono) / egr serve |
Standalone graph service; routes under /graph/* |
| MCP | egr-mcp (stdio) / egr mcp |
Plug-and-play for coding assistants (Claude Code, Codex, Cursor, ...) |
EngramGraph ships an MCP server (stdio) exposing 8 tools — index_code,
index_docs, call_chain, impact_analysis, ingest_feedback, implementers,
implemented_specs, related — so any MCP-capable assistant can use it as a
code + knowledge graph. Zero LLM, deterministic, no Docker.
# Claude Code, from an installed package:
claude mcp add egr -- npx egr-mcpFull setup (Claude Code / Codex / Cursor / Windsurf), all 8 tools, and an example flow: docs/MCP.md.
| Layer | Contents | External usability |
|---|---|---|
| Generic Core | CodeGraph (tree-sitter → graph), SAGE evolution, Kuzu abstraction, REST/MCP/Embedded modes, node-sdk | Zero project-specific dependency |
| Pluggable Adapters (interfaces) | (1) knowledge source (2) isolation model (3) SAGE signal source | Core ships interface + a generic default |
- Knowledge source —
KnowledgeSource → { nodes, edges }. Default:MarkdownKnowledgeSourceparses any front-matter markdown (id/title/status+[[ref]]links) into genericDocnodes. - Isolation model —
IsolationModel.dbPath(ctx) → string. Default:SingleRepoIsolation(onegraph.db, no org concept). Opt-in:OrgProjectIsolation(org-{orgId}/project-{projectId}/graph.db). - SAGE signal source —
SignalSource → FeedbackEvent[]. Defaults:GitHistorySignalSource,TestExitCodeSignalSource.
6 node tables — Function, Class, Module, Spec, Decision, Doc.
8 relationship tables — CALLS, IMPORTS, DEFINES, IMPLEMENTS, IMPACTS,
SUPERSEDES, RELATES, REFERENCES. See docs/API.md for the
full DDL and the front-matter schema that drives knowledge ingestion.
The graph is a derived artifact. rm -rf .engram/graph.db && egr index must
rebuild it losslessly — that is the line. Anything whose only copy would live
inside the graph does not belong there.
So EngramGraph does not store personal experience, environment or machine state, or facts about people. There is no free-form note field and there will not be one. Those things are real and worth keeping — they just belong in the notes you write by hand, which EngramGraph is meant to sit alongside rather than replace.
What it does store is what a parser can rederive from your repository: code structure, and the spec/decision documents your repository already contains.
- Phase 1 — scaffold (MIT, Node 22, ESM+CJS, tsup, vitest), Kuzu
abstraction + idempotent schema (6 NODE / 7 REL tables), three adapter
interfaces + generic defaults, Hono
GET /health,EmbeddedClient - Phase 2 — CodeGraph: tree-sitter extractor/indexer, cross-file
CALLSresolution, scope-qualified function ids - Phase 3 — KnowledgeGraph: front-matter markdown →
Spec/Decision+IMPACTS/SUPERSEDESedges - Phase 4 — SAGE evolution layer: confidence feedback (
STEP0.25, floor 0.1),topByConfidence,rankedImpact - Phase 5 — REST routes (
/graph/call-chain,/graph/impact-analysis,/graph/ingest), MCP server (5 tools), standaloneegrCLI
See CONTRIBUTING.md for dev setup, the build/test/health loop, and the kuzu + tree-sitter teardown caveat. Changes are tracked in CHANGELOG.md.
MIT — see LICENSE.