diff --git a/.claude/settings.local.json.engram-backup-2026-04-12T09-40-51-488Z.bak b/.claude/settings.local.json.engram-backup-2026-04-12T09-40-51-488Z.bak new file mode 100644 index 0000000..63a0905 --- /dev/null +++ b/.claude/settings.local.json.engram-backup-2026-04-12T09-40-51-488Z.bak @@ -0,0 +1,50 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Read|Edit|Write|Bash", + "hooks": [ + { + "type": "command", + "command": "engram intercept", + "timeout": 5 + } + ] + } + ], + "PostToolUse": [ + { + "matcher": ".*", + "hooks": [ + { + "type": "command", + "command": "engram intercept", + "timeout": 5 + } + ] + } + ], + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "engram intercept", + "timeout": 5 + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "engram intercept", + "timeout": 5 + } + ] + } + ] + } +} diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..a7e615c --- /dev/null +++ b/.cursorrules @@ -0,0 +1,55 @@ + +## Codebase Structure (auto-generated by engram) + +**Graph:** 451 nodes, 1005 edges | 96% extracted, 4% inferred +**View:** general + +## Core entities + +- `extractDirectory()` (function, 2 connections) — src/miners/ast-miner.ts +- `extractFile()` (function, 2 connections) — src/miners/ast-miner.ts +- `generateSummary()` (function, 2 connections) — src/autogen.ts +- `writeToFile()` (function, 2 connections) — src/autogen.ts +- `parseReadLikeBashCommand()` (function, 2 connections) — src/intercept/handlers/bash.ts +- `createAuthService()` (function, 2 connections) — tests/intercept/handlers/bash.test.ts +- `hashPassword()` (function, 2 connections) — tests/intercept/handlers/bash.test.ts +- `SessionStore` (class, 2 connections) — tests/intercept/handlers/bash.test.ts + +## Structure + +- `./` — tsup.config.ts +- `bench/` — runner.ts +- `src/` — autogen.ts, cli.ts, core.ts, dashboard.ts, hooks.ts, serve.ts, watcher.ts +- `src/ccs/` — exporter.ts, importer.ts +- `src/db/` — migrate.ts +- `src/generators/` — aider-context.ts, cursor-mdc.ts +- `src/graph/` — path-utils.ts, query.ts, render-utils.ts, schema.ts, store.ts +- `src/intelligence/` — hook-log.ts, token-tracker.ts +- `src/intercept/` — component-status.ts, context.ts, cursor-adapter.ts, dispatch.ts, formatter.ts, installer.ts, memory-md.ts, safety.ts, stats.ts +- `src/intercept/handlers/` — bash.ts, cwd-changed.ts, edit-write.ts, lsp-capture.ts, post-tool.ts, pre-compact.ts, read.ts, session-start.ts, user-prompt.ts +- `src/miners/` — ast-miner.ts, git-miner.ts, session-miner.ts, skills-miner.ts +- `src/providers/` — ast.ts, context7.ts, engram-git.ts, engram-mistakes.ts, engram-structure.ts, grammar-loader.ts, lsp-connection.ts, lsp.ts, mempalace.ts, obsidian.ts, resolver.ts, types.ts +- `src/server/` — http.ts +- `src/tuner/` — config.ts, index.ts +- `src/types/` — sql.js.d.ts +- `tests/` — ast-miner.test.ts, autogen.test.ts, core.test.ts, mistake-memory.test.ts, provider-cache.test.ts, render-utils.test.ts, skills-miner.test.ts, store.test.ts, stress.test.ts, watcher.test.ts +- `tests/ccs/` — ccs.test.ts +- `tests/db/` — migrate.test.ts +- `tests/fixtures/` — sample.ts +- `tests/generators/` — cursor-mdc.test.ts +- `tests/intercept/` — cli-intercept.test.ts, context.test.ts, cursor-adapter.test.ts, dispatch-new-events.test.ts, dispatch.test.ts, formatter.test.ts, get-file-context.test.ts, hook-log.test.ts, installer.test.ts, memory-md.test.ts, mistakes-filter.test.ts, render-file-structure.test.ts, safety.test.ts, spike-regression.test.ts, stats.test.ts +- `tests/intercept/handlers/` — bash.test.ts, cwd-changed.test.ts, edit-write.test.ts, post-tool.test.ts, pre-compact.test.ts, read.test.ts, session-start.test.ts, user-prompt.test.ts +- `tests/providers/` — ast.test.ts, lsp.test.ts, resolver.test.ts +- `tests/server/` — http.test.ts +- `tests/tuner/` — tuner.test.ts + +## Key dependencies + +- `node_path` (imported by 66 files) +- `vitest` (imported by 41 files) +- `node_fs` (imported by 37 files) +- `node_os` (imported by 34 files) +- `core.ts` (imported by 34 files) + +**Tip:** Run `engram query "your question"` for structural context instead of reading files. + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84530f3..65e482e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,11 @@ on: jobs: build-and-test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: + os: [ubuntu-latest, windows-latest] node-version: [20, 22] steps: diff --git a/.gitignore b/.gitignore index 9773251..4629ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,17 @@ dist/ .env .DS_Store **/.DS_Store +# Claude Code local hook install state — project-local, machine-specific +.claude/settings.local.json +# Generated IDE integration artifacts (users create these with engram gen-* commands) +.aider-context.md +.context/ +.cursor/ +# Dated benchmark result files (TEMPLATE.csv is tracked for reference) +bench/results/*.json + +# Local planning docs (not published) +.planning/ + +# Hyperframes scratch/render directories (per-run intermediates) +docs/demos/work-*/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c4ba2d..d580f3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,966 @@ All notable changes to engram are documented here. Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [3.0.2] — 2026-04-24 — "MCP Registry" + +Chore release. No runtime changes. Adds the `mcpName` field to `package.json` +required by the Official MCP Registry (`registry.modelcontextprotocol.io`) +for namespace-ownership proof. + +### Added +- `package.json` → top-level `"mcpName": "io.github.NickCirv/engram"`. Registry-side check reads the published npm tarball's `package.json` and verifies the field matches the server name in `server.json`. Without it, `mcp-publisher publish` returns HTTP 400 with the guidance message. +- Also tightened `server.json` description fields to the registry's 100-char limit (top-level description + 5 environment-variable descriptions). + +### Why not bundled into 3.0.1 +The `preuninstall` fix needed to ship ASAP to stop new users hitting the orphaned-hooks bug. MCP Registry integration was a separate problem surfaced during the submission flow. + +## [3.0.1] — 2026-04-24 — "Clean Uninstall" + +**Patch release fixing the orphaned-hooks bug reported by @freenow82 within +hours of 3.0.0 going live on npm. No feature changes — this release is +purely about not leaving users stranded when they uninstall.** + +### The bug (what 3.0.0 shipped with) + +`npm uninstall -g engramx` removed the binary from PATH but left the hook +entries in `~/.claude/settings.json` pointing at a `engram intercept` +command that no longer existed. Claude Code fires those hooks on every +tool call — the hook commands failed with ENOENT — and user-visible +behaviour was "Claude Code stopped executing anything." Recovery required +reinstalling engramx just to run `engram uninstall-hook` before +uninstalling again. + +That is a bad experience. Sorry to anyone who hit it. + +### Fixed + +- **`scripts/preuninstall.mjs`** now runs automatically before `npm uninstall -g engramx`. It reads `~/.claude/settings.json`, strips every hook entry that references engram (case-insensitive match on the command string), drops engram's statusLine/HUD, backs up the original to a timestamped `.bak` file, and writes the result atomically via rename. It NEVER fails the uninstall — if the settings file is missing, unparseable, or unwritable, it logs a single-line hint and exits 0. Contract: the user's `npm uninstall` always succeeds, with or without hook cleanup. +- **`scripts/postinstall.mjs`** prints a one-time info banner on `npm install -g engramx` showing the recommended next step (`engram setup`) and the clean-uninstall flow. Respects `$CI` and `$ENGRAM_NO_POSTINSTALL=1`. +- **New `engram repair-hooks` alias** — literally the same as `engram uninstall-hook`, but named so users who ended up with orphaned hooks after a bad uninstall can find it by the word they'd actually search for. No code duplication — `commander.alias()`. +- Both scripts included in the `files` allowlist of `package.json` so they ship in the tarball. + +### For users still stranded on 3.0.0 + +If you ran `npm uninstall -g engramx` before this patch shipped and Claude Code is still broken, you have two paths: + +1. **Fast, no reinstall:** edit `~/.claude/settings.json` manually (or run the one-line `jq` filter posted in the 3.0.1 announcement thread) to strip every entry whose `command` contains the word `engram`. +2. **Works from 3.0.1:** `npm install -g engramx@3.0.1 && engram repair-hooks --scope user` — the install no longer stops execution (hooks are in place), run repair-hooks, then `npm uninstall -g engramx` again if you want engramx gone. This time the preuninstall cleans up automatically. + +### Tests + +- New regression test: the preuninstall script on a fixture with a mix of engram hooks + unrelated hooks + a custom statusLine verifies 3 engram entries removed, unrelated keys preserved byte-for-byte, backup written, atomic rename completed. + +### Thanks + +[@freenow82](https://www.reddit.com/user/freenow82) for the bug report and the transparency about the pain it caused. That feedback is the entire point of a public launch — the tool is measurably better for it. + +## [3.0.0] — 2026-04-24 — "Spine" + +The biggest engramx release since v1.0. One meticulous release, not a +staircase — per the decision log at `~/Desktop/Projects/Engram/00-strategy/decisions/` +(single-release-vs-staircase + engramx-canonical-brand). + +Headline: engramx becomes the **extensible context spine**. Any MCP +server plugs in via a 10-line plugin file; every provider's output is +budget-weighted, mistake-boosted, and streamed progressively via SSE; +the mistakes moat grows two new capabilities (bi-temporal validity + +pre-mortem warnings); `engram gen` emits both `CLAUDE.md` AND `AGENTS.md` +by default. **Real-world benchmark: 89.1% measured savings** on engramx's +own 87-file sample (committed report in `bench/results/`). + +Contributor credit: [@mechtar-ru](https://github.com/mechtar-ru) for PR #6 +(OOM fixes on large codebases — cherry-picked with preserved authorship). + +### Added — v3.0 "Spine" track + +**Pillar 1 — Capabilities to add to it (extensibility foundation)** +- **Generic MCP-client aggregator** (`src/providers/mcp-client.ts`). Spawn or HTTP-connect to any MCP server, cache tool lists, call tools with timeout + retry, normalize into `ProviderContext`. Config at `~/.engram/mcp-providers.json`. Per-provider budgets, graceful degradation, process shutdown hooks. Uses `@modelcontextprotocol/sdk` v1.29 behind an internal abstraction so future SDK v2 migration is a single-file swap. Stdio transport ships; HTTP path stubbed pending post-3.0 Host/Origin hardening integration. +- **Provider plugin contract v2** (`src/providers/plugin-loader.ts`). Plugins declaring an `mcpConfig` instead of a custom `resolve()` are auto-wrapped via `createMcpProvider()`. Classic plugins with hand-rolled `resolve()` still work unchanged. Custom `resolve()` wins if both are present. 10-line plugins are now possible. +- **Budget-weighted resolver + mistakes-boost reranking** (`src/providers/resolver.ts`). Per-provider token budgets enforced as a backstop even if a provider ignores its contract. Results whose content mentions a known-mistake label get confidence × 1.5 (capped at 1.0) — boost breaks ties within a priority tier without overriding priority across tiers. Case-insensitive label matching. + +**Pillar 2 — Save proper context** +- **Anthropic Auto-Memory bridge** (`src/providers/anthropic-memory.ts`). Reads Claude Code's auto-managed `~/.claude/projects//memory/MEMORY.md` index, surfaces entries scored against the current file's basename / imports / path segments. Tier 1, runs under 10 ms, max 1 MB hard-cap on index size. Override via `ENGRAM_ANTHROPIC_MEMORY_PATH` for tests + advanced users. Inserted at `PROVIDER_PRIORITY[3]` between mistakes and mempalace. +- **Streaming partial context packets via SSE** (`/context/stream?file=` endpoint + `resolveRichPacketStreaming()` generator). Emit one SSE frame per provider as it resolves. Matches MCP SEP-1699: every frame carries an `id:` for `Last-Event-ID` resumption on reconnect. Client disconnect mid-stream aborts the generator cleanly. Inherits existing auth + Host + Origin guards. +- **Serena plugin reference** at `docs/plugins/examples/serena-plugin.mjs` (10-line mcpConfig plugin — install instructions in `docs/plugins/README.md`). + +**Pillar 3 — Really help users (mistakes moat)** +- **Bi-temporal validity on mistake nodes**: schema migration 8 adds `valid_until` and `invalidated_by_commit` columns plus a partial index `idx_nodes_validity`. Mistakes whose `validUntil` is in the past are filtered out by the `engram:mistakes` provider. Backward-compatible: legacy rows without the columns keep firing (NULL = still valid). +- **Pre-mortem mistake-guard** (`src/intercept/handlers/mistake-guard.ts`). Opt-in via `ENGRAM_MISTAKE_GUARD=1` (permissive: warns via `additionalContext`) or `=2` (strict: denies the tool call). Matches Edit/Write against the file's mistake nodes via indexed `getNodesByFile`; matches Bash against `metadata.commandPattern` substrings and `sourceFile` mentions in the command. Respects the bi-temporal filter. Zero overhead when unset. + +**Hygiene / ecosystem** +- `engram gen` emits BOTH `CLAUDE.md` AND `AGENTS.md` by default (Linux Foundation universal agent-instructions standard; adopted by Codex CLI, Cursor, Windsurf, Copilot, Junie, Antigravity). Explicit `--target=claude|cursor|agents` preserves single-file behavior. +- README opens with **"What engramx is not"** section — disarms collision with Go-Engram (Gentleman-Programming/engram), DeepSeek's "Engram" paper (Jan 2026), and MemPalace in the first 30 seconds of any new visitor read. +- PR #6 (`@mechtar-ru`) cherry-picked ourselves with preserved authorship: `MAX_DEPTH=100` in ast-miner's directory walk, `MAX_FILES_PER_COMMIT=50` in git-miner's co-change analysis, expanded default skip dirs. Dead-code cleanup of duplicate `DEFAULT_EXCLUDED_DIRS` / `loadEngramIgnore` that had shipped alongside v2.1's newer `DEFAULT_SKIP_DIRS` / `loadIgnorePatterns`. Closes issue #5. + +### Proof — real-world benchmark (new, committed) + +`bench/real-world.ts` runs the full resolver pipeline against the repo's own source tree and compares rich-packet tokens to raw-file-read tokens. Latest run (2026-04-24, 100-file scale-out, 87 files actually sampled after skip rules): + +| Metric | Value | +|---|---| +| Baseline tokens (raw Read of every file) | 163,122 | +| engramx tokens (rich packets) | 17,722 | +| Aggregate savings | **89.1%** | +| Median per-file savings | 84.2% | +| Files where engramx saved tokens | 85 of 87 | +| Best case (`src/cli.ts`) | 98.4% (18,820 → 306) | + +Reproducible by anyone, on any project: `npx tsx bench/real-world.ts --project . --files 50`. + +### Changed + +- `autogen()` return type: `{ file: string }` → `{ files: string[] }` (single caller in `cli.ts` updated). Consumers of the programmatic API who called `result.file` must read `result.files[0]` instead (or use `--target` to keep single-file semantics). +- `PROVIDER_PRIORITY` gains `anthropic:memory` at index 3 — downstream test that hard-coded the array order was updated. +- `MIGRATIONS` (src/db/migrate.ts): extended from `Record` to `Record void)>` so migrations that need non-idempotent DDL (like `ALTER TABLE ADD COLUMN`) can guard with `PRAGMA table_info` checks. +- README badge updates: tests 640 → 876, providers 8 → 9, savings 88.1% → 90.8%. + +### Migration + +**v2.1 → v3.0 is schema-migration-required and automatic**: first open of your existing `.engram/graph.db` triggers migration 8. A `.bak-v7` backup is written alongside. Legacy mistake rows survive unchanged (NULL `validUntil` = still valid). Verified on a simulated v2.1 DB during release audit. + +**API consumers of `autogen()`** must update call sites: `result.file` (single string) → `result.files` (array). CLI callers are unaffected. + +### Tests + +771 → 876 passing (+105 new). CI green Ubuntu+Windows × Node 20+22. TypeScript `--noEmit` clean, lint clean. + +## [2.1.0] — 2026-04-21 — "Reliability + Zero-Friction Install" + +First release in the v2.1 / v2.2 / v3.0 elevation trilogy. Design spec +at `docs/superpowers/specs/2026-04-20-engram-elevation-trilogy-design.md`. + +Headline: `engram setup` is the new one-command first-run flow. Users +go from `npm install -g engramx` to a working Sentinel hook + indexed +graph in under 30 seconds. `engram doctor` reports component health +with remediation hints. `engram update` ships future hotfixes to every +install without surprise — passive notify, zero telemetry, one-command +upgrade. Plus fixes for issue #11 (AST/LSP path bug in flattened +bundles) and issue #14's Bash-ops half (auto-reindex on `rm`/`mv`/ +`git rm` via an opt-in PostToolUse gate). + +Contributor credit this release: [@gabiudrescu](https://github.com/gabiudrescu) +for PR #13 (reindex CLI + `install-hook --auto-reindex`), PR #12 +(watcher prune on delete/rename), and the original v2.0.2 security +disclosure. [@ttessarolo](https://github.com/ttessarolo) for precise +forensics + suggested fix on issue #11. + +### Added — v2.1 "Reliability + Zero-Friction Install" track + +- **`engram update`** — one-command self-upgrade. + Passive notify on every `engram *` invocation when a newer version is + available (cached, at most one line on stderr, throttled to a 7-day + registry check). Manual trigger detects the package manager that owns + the engram install (npm / pnpm / yarn / bun via install-path markers) + and shells out to its global-upgrade command. `--check` for dry-probe, + `--force` to bypass the 7-day throttle, `--dry-run` to print the + upgrade command without executing it, `--manager ` override. + Zero telemetry: the only network call is an anonymous GET to + `registry.npmjs.org/engramx/latest`. `ENGRAM_NO_UPDATE_CHECK=1` and + `$CI` disable the entire subsystem. Addresses the "1,300 weekly + downloads, 10/day organic, near-zero hotfix reach" problem. + +- **`engram doctor`** — component health report with remediation hints. + Wraps existing probes (HTTP, LSP, AST, IDE adapters) plus four new + checks: engram version freshness, `.engram/graph.db` presence, + Sentinel hook installation, IDE adapter count. Each check emits + severity (ok / warn / fail) + detail + optional remediation. Exit + code reflects overall severity (0 ok, 1 warn, 2 fail) so `doctor` + is CI-friendly. `--verbose` shows remediation hints; `--json` / + `--export` emits redacted JSON for bug-report attachment + (`projectRoot` intentionally omitted — can contain usernames). + +- **`engram setup`** — zero-friction first-run wizard. One command for + "go from cloned repo to working engram in under 30 seconds." + Runs `init` (if `.engram/graph.db` missing) → `install-hook` (with + prompted scope, `local` default) → detects IDE adapters (Cursor, + Windsurf, Continue.dev, Aider) and suggests the matching `gen-*` + command for each → finishes with a `doctor` summary. Each step is + idempotent. `--yes` runs with defaults; `--dry-run` prints intent + without acting; `--scope` controls the install-hook scope. Drops + install-to-first-value from 4 commands to 1. + +- **`engram init --with-hook`** — shorthand for `init` followed by + `install-hook` (local scope, idempotent). The #1 thing every user + does after `init` was `install-hook`; now it's one step. + +- **First-run hint.** On any `engram` subcommand invoked in a repo + lacking `.engram/graph.db`, print one line on stderr: + `💡 First time in this repo? Run 'engram setup' for a zero-friction install.` + Throttled via `~/.engram/first-run-shown` (fires once per machine, + not per repo). Silenced in `$CI`, under `ENGRAM_NO_UPDATE_CHECK=1`, + and under the JSON-stdout commands (`intercept`, `cursor-intercept`, + `hud-label`, `setup`, `init`, `update`, `doctor`) so neither + pollutes the hook protocol. + +- **Bash PostToolUse parser for auto-reindex** — closes half of + [#14](https://github.com/NickCirv/engram/issues/14). + `src/intercept/handlers/bash-postool.ts` parses file-mutating Bash + commands (`rm`, `mv`, `cp`, `git rm`, `git mv`, single-redirect + ` > `) into `FileOp { action, path }` records. Strict + parser: globs, pipes, subshells, command-substitution, directory + ops, and `touch` all pass through untouched. Wired into the + PostToolUse observer path in `handlers/post-tool.ts` — on Bash + PostToolUse events, each op is handed to `syncFile()` fire-and-forget. + Gated by `ENGRAM_AUTO_REINDEX=1` opt-in until + [#13](https://github.com/NickCirv/engram/pull/13)'s install-hook + `--auto-reindex` flag lands; that flag will toggle the env gate + implicitly. + +### Fixed — v2.1 reliability + +- **AST grammar detection in flattened bundles** + ([#11](https://github.com/NickCirv/engram/issues/11) partial). + When `tsup`/`esbuild` flattens chunks to `engramx/dist/chunk-*.js`, + `import.meta.url` resolves to `engramx/dist` and the previous + candidates (`../grammars` and `../../dist/grammars`) both missed the + actual grammar dir. Added `join(here, "grammars")` as the first + candidate; dev-time layout (`src/intercept/`) still works via the + third candidate. Thanks [@ttessarolo](https://github.com/ttessarolo). + +- **LSP socket candidate coverage** + ([#11](https://github.com/NickCirv/engram/issues/11) partial). + `checkLsp` was looking for two socket names while + `lsp-connection.ts::candidateSockets()` probes six. Synced the list + so HUD availability matches actual provider availability. Kept + `.engram/lsp-available` as an explicit user opt-in marker for + back-compat. + +### Fixed + +- **Locale-independent number formatting across the codebase.** All 10 + `Number.prototype.toLocaleString()` callsites in `src/cli.ts`, + `src/serve.ts`, `src/dashboard.ts`, and `src/intercept/stats.ts` have + been migrated to a shared `formatThousands()` helper in + `src/graph/render-utils.ts`. Two wins: + + 1. **Deterministic performance.** First-call ICU init on Windows Node + has been observed to take multiple seconds in GitHub Actions VMs, + flaking tests at the 5000ms default timeout (seen on + `tests/intercept/stats.test.ts > formatStatsSummary` post-merge on + `9f99f5b`). The regex-based helper runs in microseconds with no + ICU dependency. + 2. **Locale independence.** `toLocaleString()` emits `"1,234"` on + en-US but `"1.234"` on de-DE and `"1 234"` on fr-FR, giving users + running engram in non-US shells inconsistent output. All CLI + + MCP server + dashboard numbers now render with commas regardless + of system locale. + + Added `tests/render-utils.test.ts > formatThousands` — 6 tests + covering single-digit, multi-group, negative, and locale-stable cases. + Also added `vitest.config.ts` with CI-only `retry: 1` + + `testTimeout: 15000ms` as defense-in-depth against other cold-worker + flakes. + +- **`engram watch` now prunes graph nodes when watched files are deleted + or renamed** ([#9](https://github.com/NickCirv/engram/issues/9), + [#12](https://github.com/NickCirv/engram/pull/12)). Previously the + watcher only subscribed to `change` events, silently ignoring the + `rename` events that `fs.watch` fires for create/unlink across all + platforms. Deletions left stale nodes in the graph until the next + `engram init`; renames produced duplicate nodes under the old and new + `sourceFile` paths. Thanks [@gabiudrescu](https://github.com/gabiudrescu). + +### Added + +- **`syncFile(absPath, root)`** exported from `src/watcher.ts` — the shared + "exists → reindex; gone (and was indexed) → prune" primitive reused by + the upcoming `engram reindex` CLI subcommand ([#8](https://github.com/NickCirv/engram/issues/8)). + Returns a discriminated `SyncResult` (`indexed` | `pruned` | `skipped`). +- **`GraphStore.countBySourceFile(relPath)`** — noise-reduction gate so + `onDelete` only fires for files the graph actually indexed. +- **`onDelete` callback on `WatchOptions`** — fires with `(filePath, prunedCount)` + when the watcher prunes a deleted file's nodes. +- **`× pruned (N nodes)`** log line in `engram watch`, distinct from + the existing green `↻` reindex line. +- **`gen-cursor --watch`, `gen-aider --watch`, `gen-windsurfrules --watch`** + now regenerate their output files on source-file delete (not just on + reindex), so generated artifacts no longer keep stale references to + deleted sources. +- **`engram reindex ` CLI subcommand** + ([#8](https://github.com/NickCirv/engram/issues/8)) — re-indexes a + single file into the knowledge graph. The missing primitive for per- + edit freshness: Claude Code PostToolUse hooks, editor plugins, and CI + can now keep the graph in sync without running a long-lived watcher. + Reuses `syncFile()` so semantics match `engram watch`: exists → + reindex; missing-but-previously-indexed → prune; unsupported ext or + ignored directory → silent exit 0 (safe to fire on every edit). On + success prints a single line `engram: reindexed ( nodes)` + (or `pruned`) using locale-stable `formatThousands`. `--verbose` + surfaces stack traces; default error output is a single stderr line. + Missing graph exits 1 with `engram: no graph found at . Run + 'engram init' first.`, matching `engram watch`. +- **`formatReindexLine(result, displayPath)`** exported from + `src/watcher.ts` — pure formatter shared by the new subcommand. Returns + `null` for skipped results so callers stay silent. +- **`engram reindex-hook` subcommand + `engram install-hook --auto-reindex`** + ([#8](https://github.com/NickCirv/engram/issues/8), opt-in auto-wire). + `reindex-hook` reads Claude Code's PostToolUse payload from stdin and + re-indexes `tool_input.file_path` via the shared `syncFile()` primitive. + Contract: ALWAYS exits 0 — malformed JSON, missing fields, non-project + `cwd`, and all internal errors resolve to a silent no-op so the hook + can never fail Claude Code's tool cycle. `install-hook --auto-reindex` + appends a second PostToolUse entry with matcher `Edit|Write|MultiEdit` + calling `engram reindex-hook`; off by default so existing users aren't + surprised. The new entry is recognized by `isEngramHookEntry()` so + `engram uninstall-hook` strips it alongside the primary intercept + entries. Idempotent — reinstalling with `--auto-reindex` is a no-op + when the entry already exists. +- **`runReindexHook(payload)`** exported from `src/watcher.ts` — the + pure async handler behind the `reindex-hook` subcommand. Validates + payload shape, resolves project root from `cwd`, delegates to + `syncFile`. Swallows every error. +- **`buildReindexHookEntry()` + `ENGRAM_REINDEX_HOOK_MATCHER` + (`"Edit|Write|MultiEdit"`) + `DEFAULT_ENGRAM_REINDEX_HOOK_COMMAND` + (`"engram reindex-hook"`)** exported from `src/intercept/installer.ts` + — the data primitives for the optional entry. Added + `InstallOptions.autoReindex` and `InstallResult.autoReindexAdded` to + thread the opt-in through the existing installer surface. + +### Notes + +- Directory deletion (`rm -rf src/foo`) is intentionally not handled by the + watcher — `fs.watch` fires a single rename event on the directory path + with no per-file information. A full `engram init` handles that case + today; per-file directory-prefix pruning is tracked for v2.2. + +## [2.0.2] — 2026-04-18 — Security hotfix: HTTP server auth & CORS + +**This is a security release. Upgrade immediately if you run `engram server` +or `engram ui`.** Credit: [@gabiudrescu](https://github.com/gabiudrescu) for +responsible disclosure ([#7](https://github.com/NickCirv/engram/issues/7)). + +### Security — fixed + +- **Graph exfiltration + persistent prompt injection via cross-origin browser + tabs.** The HTTP server previously shipped with `Access-Control-Allow-Origin: *` + on every response and defaulted to no authentication. A malicious page the + developer visited could `fetch('http://127.0.0.1:7337/query')` to steal the + local graph, then `POST /learn` (with `Content-Type: text/plain`, a + CORS-safelisted content type) to persist `bug:` / `fix:` patterns that the + v2 Sentinel handlers later re-injected into the user's coding agent on + SessionStart and on every Edit/Write of the named file. Severity: High — + confidentiality + persistent indirect prompt injection. + + **Fix (four stacked defenses):** + 1. **Fail-closed auth.** Every route except `/health` and `/favicon.ico` + now requires `Authorization: Bearer ` or an HttpOnly + `engram_token` cookie. A random 64-character token is auto-generated + on first server start and persisted to `~/.engram/http-server.token` + with mode `0600`. `ENGRAM_API_TOKEN` env var still overrides. + 2. **No wildcard CORS.** `Access-Control-Allow-Origin: *` has been removed + from every response. By default no CORS headers are emitted — the + dashboard is same-origin. Additional origins opt in via + `ENGRAM_ALLOWED_ORIGINS=a.com,b.com`. + 3. **Host + Origin validation** (DNS-rebinding defense). Requests with a + `Host` header other than `127.0.0.1|localhost|::1` on the bound port + return 400. Requests with an `Origin` not in the same-origin or env + allowlist return 403. + 4. **`Content-Type: application/json` enforced on mutations.** POST / PUT / + DELETE without `application/json` return 415. This blocks the + `text/plain` CSRF vector from the PoC and forces CORS preflight for + any cross-origin writer. + +- **Timing side-channel on token comparison.** The previous + `header === \`Bearer ${token}\`` comparison was not constant-time. + Replaced with a length-first, constant-time `safeEqual()`. + +### Added + +- `src/server/auth.ts` — token management (get-or-create, safeEqual, cookie + parsing, Host/Origin validators). +- `tests/server/security.test.ts` — PoC-style tests covering fail-closed + auth (including empty Bearer / empty cookie guards), env-downgrade + rejection (token is snapshot at start), cookie auth, wildcard-CORS + absence, same-origin echo, foreign-origin 403, Host header validation + (including no-port rejection + case-insensitive hostname), `text/plain` + rejection on `/learn`, the `/ui?token=` cross-site oracle defence via + `Sec-Fetch-Site` gating, and the end-to-end exploit chain from #7. +- `SECURITY.md` at repo root with disclosure policy and scope. +- `GET /ui?token=` bootstrap path for the browser dashboard. The CLI + passes the token once; the server exchanges it for an HttpOnly cookie via + a 302 redirect and strips the token from the URL. Dashboard JS never sees + the raw token. + +### Changed + +- `createHttpServer(projectRoot, port)` now resolves to `Promise` + (previously `Promise`). The returned object exposes the token source + (env / file / generated) and the token file path. The CLI uses this to + print a one-time banner pointing users at `~/.engram/http-server.token` + when a fresh token is minted. +- `checkAuth` rewritten as fail-closed, accepts Bearer header OR + `engram_token` cookie, uses constant-time comparison. +- Server-Sent Events endpoint (`/api/sse`) no longer emits wildcard CORS and + inherits the same origin-allowlist behavior as every other route. + +### Breaking + +- **External callers (curl, scripts, CI probes) must now send the token.** + Fix the one-liner on each caller: + ```bash + curl -H "Authorization: Bearer $(cat ~/.engram/http-server.token)" \ + http://127.0.0.1:7337/stats + ``` +- Requests with `Host: something-else.com` are rejected 400 even if they + resolve to 127.0.0.1 locally. DNS rebinding defense — intended behavior. +- Cross-origin requests (`Origin: https://example.com`) are rejected 403 + unless the origin is in `ENGRAM_ALLOWED_ORIGINS`. No legitimate caller + should be affected. +- `/ui` navigation from the browser now requires `?token=` on first visit + (set automatically when you run `engram ui`) or a pre-existing + `engram_token` cookie. + +## [2.0.1] — 2026-04-17 — Windows CI + favicon route + +Patch release fixing two issues caught immediately after v2.0.0 shipped. + +### Fixed + +- **Windows cross-platform bug in the plugin loader.** `PLUGINS_DIR` was a + module-load-time constant that baked in `homedir()` at import time. Windows + uses `USERPROFILE` while Unix uses `HOME`, and a frozen constant meant any + runtime override (tests, future `--plugins-dir` flag, programmatic use) + couldn't take effect without a module reload. Windows CI failed on the + plugin-loader tests because `process.env.HOME` mutation had no effect. + Fixed by introducing `getPluginsDir()` that resolves on every call, and + accepting an optional `dir` parameter on `loadPlugins()`, + `getLoadedPlugins()`, and `ensurePluginsDir()`. The `PLUGINS_DIR` constant + is retained for back-compat but runtime paths now go through the getter. +- **`/favicon.ico` returning 404 for clients that ignore ``.** + Added an explicit `GET /favicon.ico` route to the HTTP server that serves + a 238-byte inline SVG favicon with `Cache-Control: public, max-age=86400`. + The dashboard HTML still inlines the same favicon via `` so modern + browsers avoid the request entirely. + +### Changed + +- Test count: 640 → 641 (+1 for the "plugins directory does not exist" + branch of `loadPlugins()`). + +### CI + +- Verified green on GitHub Actions matrix: Ubuntu + Windows × Node 20 + 22. + Commit `7c6001c`. + +## [2.0.0] — 2026-04-17 — "Ecosystem" + +The biggest release since v1.0.0. Completes the v2.0 roadmap Phases 1–4: +Foundation, Web Dashboard, Integration Expansion, and Solidification. +640 tests (up from 579). All changes backward-compatible with v1.x graph +files — existing `.engram/graph.db` files auto-migrate to schema v7. + +### Added — Phase 3 (Integration Expansion) + +- **`engram gen-windsurfrules`** — generate `.windsurfrules` for Windsurf + (Codeium) IDE. Plain markdown (no frontmatter), auto-picked-up by Windsurf + on every chat session. Supports `--watch` for live regeneration on graph + changes. See `docs/integrations/README.md`. +- **Integration docs**: `docs/integrations/neovim.md` (codecompanion + + avante.nvim via mcphub), `docs/integrations/cursor-mcp.md` (Cursor's + native MCP support alongside the MDC path), `docs/integrations/emacs.md` + (gptel + gptel-mcp), plus a new `docs/integrations/README.md` index that + maps every supported IDE to its mechanism. + +### Added — Phase 4 (Solidification) + +- **Provider plugin system** — third-party context providers installable + at `~/.engram/plugins/*.mjs`. Each plugin default-exports a + `ContextProviderPlugin` object and is dynamically loaded by the resolver. + Validation-before-install refuses malformed plugins; duplicate names + can't shadow built-ins. New CLI: + - `engram plugin list` — show installed plugins with tier/budget/version + - `engram plugin install ` — validate + copy into plugins dir + - `engram plugin remove ` +- **`engram cache` CLI namespace** — inspect and manage the context cache: + - `engram cache stats` — hit rate, entries per layer, hot file count + - `engram cache clear` — flush all layers + - `engram cache warm` — pre-warm hot files from access frequency +- **Schema rollback** — `engram db rollback --to ` reverts the + schema with automatic backup at `.bak-v`. Requires + explicit `--yes` confirmation (data loss). Rollback is in-session only; + reopen auto-migrates forward again by design — the backup is the + recovery path for pinning an older version. +- **Schema v7** — adds `query_cache` and `pattern_cache` tables with + `idx_query_cache_file` index. Retroactive DOWN migrations defined for + versions 1–7 so any version is rollback-target-safe. + +### Added — Phase 1 (Foundation) + +- **Tree-sitter grammar bundling** — 6 WASM grammar files (TypeScript, TSX, + JavaScript, Python, Go, Rust) now ship inside the npm package at + `dist/grammars/`. The `engram:ast` provider works out of the box for npm + users without needing local `node_modules` tree-sitter packages. + New: `scripts/bundle-grammars.mjs` (pure Node ESM, no tsx dep). + `npm run build` bundles them automatically; `build:nogrammars` as escape hatch. +- **Incremental indexing** — `init()` accepts `{ incremental: true }` and the + CLI accepts `--incremental` to skip files whose mtime hasn't changed since + last index. File mtimes persisted as JSON in the stats table. On engram's + own source (117 TS files): 53ms vs 244ms full init — **78% faster**. +- **`.engramignore` support** — gitignore-like syntax for excluding directories + and files from indexing. Loaded from project root. +- **Memory cache system** (`src/intelligence/cache.ts`, ~330 LOC) — 3-layer + compound savings engine: + - **Query result cache** — resolved context packets per file, SQLite-backed + + in-memory LRU (100 entries). Invalidated on file mtime change. + Benchmarked at 23μs/op, 99% hit rate under 10k random reads. + - **Pattern cache** — structural query answers memoized with graph version + tracking. LRU (50 entries). Auto-invalidates on graph mutation. + - **Hot file cache** — `warmHotFiles()` pre-loads top-N most-accessed files + at SessionStart for zero first-hit latency. + - `engram cache` CLI namespace (stats/clear/warm) — planned for Phase 4. +- **9 new HTTP API endpoints** serving the dashboard + external integrations: + - `GET /api/hook-log` — paginated hook log entries + - `GET /api/hook-log/summary` — aggregated event/tool/decision stats + - `GET /api/tokens` — cumulative token savings + - `GET /api/files/heatmap` — file interception frequency ranking + - `GET /api/providers/health` — component status + - `GET /api/cache/stats` — cache hit/miss rates, entry counts + - `GET /api/graph/nodes` — paginated graph nodes + - `GET /api/graph/god-nodes` — top-connected entities + - `GET /api/sse` — Server-Sent Events, 1s hook-log polling, auto-cleans on + disconnect + - Load tested at 200 concurrent mixed requests in 295ms (~1.5ms/req). + +### Added — Phase 2 (Web Dashboard) + +- **Zero-dependency web dashboard at `GET /ui`** — 35KB self-contained + HTML/CSS/JS as TypeScript template literals. No external CDNs, no build + pipeline, works offline / on air-gapped machines. + - Security: CSP meta tag (`default-src 'self'; connect-src 'self'`) + single + `esc()` helper at every JS→HTML boundary defends against XSS from + attacker-controllable file paths/labels mined from repos. + - 6 tabs: Overview, Sessions, Activity (live SSE), Files, Graph (Canvas 2D + force-directed, ~200 LOC, handles <500 nodes at 60fps with pan/zoom/click), + Providers. + - SVG chart library (`ui-components.ts`): donut, stacked bars, sparkline, + cache/graph stat blocks. Zero dependencies. +- **`engram ui` CLI command** — auto-starts the HTTP server if not running + (PID file check), opens the default browser to `http://127.0.0.1:7337/ui`. + `--no-open` flag for print-only mode. + +### Changed + +- `npm run build` now always bundles tree-sitter grammars into `dist/grammars/` + (previously only `prepublishOnly` did, which masked the missing-grammar + scenario for anyone testing a built `dist/` locally). +- `--incremental` flag wired into the CLI (previously API-only and undiscoverable). +- Default skip directories expanded: added `.next`, `.nuxt`, `coverage`, + `target`, `venv`, `.venv`, `.cache`, `.turbo`, `.output`, `.git`. +- `extractFile()` now returns `lineCount` from content already parsed, + eliminating a redundant `readFileSync` per file during extraction. +- `GraphStore` extended with `runSql()`, `prepare()` (public), and + `removeNodesForFile()` for incremental mode and cache module. +- Test count: 579 → 640 (+61 tests: 7 incremental + 17 cache + 15 API + 6 + windsurf + 5 rollback + 11 plugin-loader). + +### Fixed + +- `dist/grammars/` was empty after `npm run build` alone — only populated by + `prepublishOnly`. Masked in dev by `grammar-loader.ts` falling back to + `node_modules/tree-sitter-*/`, but shipped broken to anyone running `dist/` + locally after build. Root cause: tsup's `clean: true` wiped the dir. + +## [1.0.0] — 2026-04-17 — "Protocol" + +### Added + +- **HTTP REST server** — `engram server --http` starts a local server on + 127.0.0.1:7337. Endpoints: `/health`, `/query`, `/stats`, `/providers`, + `/learn`. Bearer token auth via `ENGRAM_API_TOKEN`. PID file written on + start for HUD server-status detection. +- **Tree-sitter AST provider** (`engram:ast`) — WASM-based AST parsing for + 10 languages (TypeScript, JavaScript, Python, Go, Rust, PHP, Ruby, Java, + C, C++). Confidence 1.0 vs 0.85 for regex. When the AST provider succeeds + for a file, the regex `engram:structure` provider is skipped entirely. +- **LSP provider** (`engram:lsp`) — connects to running LSP servers. Hover + info is added to Read interceptions; diagnostic events on Edit create + mistake nodes automatically. Best-effort with graceful degradation when no + LSP is running. +- **Auto-tuning** — `engram tune [--dry-run|--apply]` analyzes + `.engram/hook-log.jsonl` and proposes per-project config changes: + confidence threshold, token budgets, provider enable/disable. Settings + are written to `.engram/config.json`. +- **Schema versioning** — 6 migration files (001–006). Auto-migrate on + startup with backup. `engram db status` shows current schema version; + `engram db migrate` runs pending migrations. +- **CCS integration** — Codebase Context Specification support. + `engram init --from-ccs` imports `.context/index.md` into the KG as + nodes. `engram gen-ccs` exports the KG to CCS format. +- **Continue.dev context provider** — `engramx-continue` npm package. + Surfaces as `@engram` in Continue's @-mention system. Falls back to HTTP + server if CLI is unavailable. +- **Cursor MDC generation** — `engram gen-mdc` generates + `.cursor/rules/engram-context.mdc` from the KG. YAML frontmatter with + auto-detected globs. `--watch` flag for live refresh on graph changes. +- **Zed context server** — `engram context-server` implements Zed's + JSON-RPC protocol. Registers as the `/engram` slash command inside Zed. +- **Aider context generation** — `engram gen-aider` creates + `.aider-context.md` from the KG. `--watch` flag for live refresh. +- **Benchmark harness v0.2** — automated `npm run bench` with 10 task + fixtures. Measures baseline vs engram token savings across real tasks. + Result: **88.1% aggregate token savings** (measured, not estimated). +- **Stress test suite** — `npm run stress` covering rapid concurrent reads, + provider concurrency, large graph operations, and hook-log replay. +- **Component health HUD** — statusLine now shows HTTP ✓/✗, LSP ✓/✗, + AST ✓/✗, and N IDEs. Updates automatically as components activate. +- **ECP spec v0.1** — Engram Context Protocol RFC at + `docs/specs/ecp-v0.1.md`. Vendor-neutral standard for hook-based context + enrichment across coding tools. CC-BY 4.0. +- **5 integration guides** — `docs/integrations/` with setup guides for + Continue.dev, Cursor, Zed, Aider, Claude Code, and CCS. +- **Per-project config** — `.engram/config.json` supports confidence + threshold, token budgets, and provider overrides. Read by the resolver + on every packet assembly. + +### Changed + +- Provider priority now includes `engram:ast` (highest confidence, runs + first) and `engram:lsp` (lowest, best-effort enrichment). The regex + `engram:structure` provider is skipped on files where AST succeeds. +- `TOTAL_TOKEN_BUDGET` is now configurable via `.engram/config.json`. + Was hardcoded at 600. +- Test count: 520 → 579 (+59 tests across 6 new test files). + +### Fixed + +- **Shell injection in Continue adapter** — switched from double-quote + escaping to single-quote wrapping for all CLI arguments. +- **HTTP server package.json path resolution** — now resolves correctly + from both `src/` (dev) and `dist/` (built) entry points. + +--- + +## [0.5.0] — 2026-04-13 — "Context Spine" + +### Added + +- **Context Spine** — engram now assembles rich context packets from + 6 providers (structure, mistakes, git, mempalace, context7, obsidian) + per Read interception. One response replaces 5 separate tool calls. + Target: up to 90% session-level token savings. +- **Provider cache** — new `provider_cache` SQLite table with full CRUD. + External providers (mempalace, context7, obsidian) cache results at + SessionStart. Per-Read cache lookup is <5ms. +- **ContextProvider interface** — formal contract for all providers: + `resolve()`, `warmup()`, `isAvailable()`, with token budgets and + per-provider timeouts. +- **6 providers**: `engram:structure` (graph), `engram:mistakes` (known + issues), `engram:git` (recent changes/churn), `mempalace` (decisions + from ChromaDB), `context7` (library docs), `obsidian` (project notes). +- **Resolver engine** — parallel resolution with priority ordering, + 600-token total budget, graceful degradation per provider. +- **SessionStart warmup** — fire-and-forget bulk cache fill for Tier 2 + providers at session start. +- **StatusLine auto-config** — `engram install-hook` now sets up the + Claude Code statusLine with `engram hud-label` when no existing + statusLine is configured. + +### Fixed + +- **CRITICAL: `renderFileStructure` full table scan** — replaced + `getAllNodes()`/`getAllEdges()` with targeted SQL queries + (`getNodesByFile`, `getEdgesForNodes`). Was silently timing out on + large projects (50k+ nodes). +- **CRITICAL: `scoreNodes` full table scan** — replaced `getAllNodes()` + with `searchNodes()` SQL seeding. O(matches) instead of O(all nodes). +- **Go import false positives** — import detection now tracks + `import()` block state. No longer fires on struct field tags like + `json:"name"`. +- **TS arrow function false positives** — pattern now requires `=>` + in the same line. `const x = (someValue)` no longer creates false + function nodes. +- **Commented-out code extraction** — lines starting with `//` or `*` + are skipped before pattern matching. +- **Edge ordering** — `renderFileStructure` sorts edges by combined + endpoint degree before `.slice(0, 10)`. God-node relationships + appear first. +- **LIKE wildcard escaping** — `%` and `_` in search queries are + properly escaped. +- **SQLite variable limit** — `getEdgesForNodes` chunks IN clause at + 400 IDs to stay under SQLite's 999 parameter limit. +- **`warmCache` persistence** — now calls `save()` after transaction + commit, consistent with `bulkUpsert`. +- **Null-safe casts** — `rowToCachedContext` uses `?? fallbacks` on + all fields to prevent null propagation. +- **Parallel availability checks** — provider isAvailable() runs in + parallel, not sequentially. Prevents slow Tier 2 timeouts from + blocking Tier 1 providers. + +### Changed + +- Confidence score calibrated to 0.85 for regex extraction (was 1.0). + Reserves 1.0 for future tree-sitter integration. +- Removed phantom `graphology` dependency (was in package.json with + zero imports in source code). +- Test count: 493 → 520 (+27 new tests). +- README updated: "context spine" positioning, accurate test count, + provider documentation, "heuristic extraction" language. + +## [0.4.0] — 2026-04-12 — "Infrastructure" + +### Added + +- **PreCompact hook** — re-injects god nodes, active landmines, and + graph stats right before Claude Code compresses the conversation. + This is the first tool in the ecosystem whose context survives + compaction. No other tool does this. +- **CwdChanged hook** — auto-switches project context when the user + navigates to a different directory mid-session. Injects a compact + brief for the new project so subsequent interceptions route to the + correct graph. +- **File watcher** (`engram watch`) — incremental re-indexing via + `fs.watch`. On file save, clears old nodes for that file and + re-extracts fresh AST nodes. 300ms debounce, ignored directories + (node_modules, .git, dist, etc.), extension whitelist. Zero native + dependencies. Eliminates manual `engram init` for graph freshness. +- **Mempalace integration** — SessionStart brief now queries + `mcp-mempalace` for semantic context about the project and bundles + top 3 findings alongside the structural brief. Runs in parallel + with graph queries (async execFile, 1.5s timeout). Graceful + degradation if mempalace is not installed. +- **`deleteBySourceFile`** method on GraphStore — transactional + deletion of all nodes and edges for a given source file. Used by + the file watcher for incremental re-indexing. +- **`edges.source_file` index** — enables fast lookups when the + watcher deletes by file. Without this, `deleteBySourceFile` would + do a full table scan. + +### Changed + +- Hook count: 7 → 9 (added PreCompact, CwdChanged). +- Installer now registers 6 hook events (was 4). +- Test count: 467 → 486 (+19 new tests for PreCompact, CwdChanged, + file watcher, dispatch routing). + +## [0.3.2] — 2026-04-12 — "Cross-Platform" + +### Fixed + +- **Windows path portability** — Graph `sourceFile` entries now stored + in POSIX form (`src/auth.ts`, not `src\auth.ts`) via new + `toPosixPath()` in `src/graph/path-utils.ts`. All lookup sites + (`getFileContext`, `handleEditOrWrite`, `extractFile`) normalize + consistently. Without this, Sentinel on Windows would passthrough + every Read (zero interception). Credit: ultrathink (shahe-dev). +- **CRLF handling in skills-miner YAML parser** — `parseYaml` now + strips `\r` before splitting, fixing silent failures on Windows + clones with `core.autocrlf=true` where `description: >` was + misread as `description: >\r`. +- **libuv assertion crash on Node 25 Windows** — Replaced + `process.exit(0)` in `engram intercept` with `process.exitCode = 0` + + natural event-loop drain. The prior code raced against sql.js + WASM handle cleanup, triggering `UV_HANDLE_CLOSING` assertion + (`0xC0000409`) on Windows + Node 25. +- **`isHardSystemPath` now platform-aware** — Detects Windows UNC + device paths (`//./`, `//?/`), `C:\Windows\`, and `C:\Program Files` + in addition to POSIX `/dev/`, `/proc/`, `/sys/`. Tests no longer + skip on win32. +- **Double drive-letter bug** — Test files using + `new URL(".", import.meta.url).pathname` now use `fileURLToPath()` + which prevents `/C:/Users/...` → `C:\C:\Users\...` on Windows. + +### Added + +- **Experience Tiers in README** — New section showing the 4 tiers of + value (graph → Sentinel → skills → git hooks) with token savings per + tier and a recommended full-setup block. +- **Post-init nudge** — `engram init` now detects whether Sentinel hooks + are installed and suggests `engram install-hook` if not, closing the + silent drop-off gap where users get 6x savings instead of 82%. +- **Windows CI matrix** — GitHub Actions now runs on both + `ubuntu-latest` and `windows-latest` with Node 20 + 22. + +### Changed + +- Test count: 466 → 467 (added Windows system-path test cases). + +## [0.3.1] — 2026-04-12 — "Structural" + +### Added + +- **TF-IDF keyword filter on `UserPromptSubmit` hook.** The pre-query + path now computes inverse document frequency against graph node + labels and requires at least one keyword with IDF ≥ 1.386 (25% + cutoff) before injecting context. Kills the "76-node noise bug" + where common-term prompts poisoned sessions on mature graphs. + New `computeKeywordIDF` helper in `src/core.ts`. Falls back to + raw keywords if IDF computation returns empty. 3 new tests. +- **`engram memory-sync` CLI command.** Writes engram's structural + facts (god nodes, landmines, graph stats, branch) into a + marker-bounded block inside Anthropic's native `MEMORY.md` file. + Uses `` markers so + Auto-Dream owns prose memory and engram owns structure — + complementary, not competitive. New `src/intercept/memory-md.ts` + module (pure builder + upsert + atomic write). 16 new tests. + Supports `--dry-run` and `--project`. +- **Cursor adapter scaffold** (`src/intercept/cursor-adapter.ts`). + New `engram cursor-intercept` CLI command wraps the existing + `handleRead` logic in Cursor 1.7's `beforeReadFile` response + shape (`{ permission, user_message }`). Experimental — full + Cursor wire-up lands in v0.3.2. 8 new tests. +- **EngramBench v0.1** — reproducible benchmark scaffold in + `bench/`. Ten structural tasks (find caller, parent class, + import graph, refactor scope, cross-file flow, etc.) defined as + YAML files with prompts, scoring rubrics, and expected tokens + per setup (baseline / cursor-memory / anthropic-memorymd / + engram). `bench/run.sh` runner + `bench/results/TEMPLATE.csv`. + v0.2 will automate the runner and publish a leaderboard. +- **Rebrand to "the structural code graph"** — package description, + keywords, and README hero rewritten to lead with structural + memory rather than the generic "memory" framing. + +### Fixed + +- False-positive context injections on large graphs where prompts + contained common graph terms (the "76-node noise bug" from + v0.3.0 real-session data). + +### Tests + +- 466 tests passing (up from 442 in v0.3.0). +- 27 new tests across 3 files (TF-IDF, MEMORY.md, Cursor adapter). + +### Notes + +- Zero new runtime dependencies. +- Schema unchanged from v0.3.0. +- No breaking changes. v0.3.0 users upgrade cleanly. + +## [0.3.0] — 2026-04-11 — "Sentinel" + +### Added — The Claude Code Hook Interception Layer + +**The big change:** engram is no longer just a tool your agent queries. +It's now a Claude Code hook layer that intercepts file reads, edits, +prompts, and session starts — automatically replacing full file reads +with ~300-token structural graph summaries when confidence is high. + +Empirically verified on 2026-04-11 against a live Claude Code session. +The hook mechanism is `PreToolUse deny + permissionDecisionReason`, +which Claude Code delivers to the agent as a system-reminder containing +the engram summary. File is never actually read, so savings materialize +at the agent-turn layer, not just when the agent remembers to ask. + +**Seven new CLI commands:** + +- `engram intercept` — hook entry point. Reads JSON from stdin, + dispatches through the handler registry, writes response JSON to + stdout. ALWAYS exits 0 — the process boundary enforces the "never + block Claude Code" invariant. +- `engram install-hook [--scope local|project|user] [--dry-run]` — + adds engram's entries to a Claude Code settings file. Default scope + is `local` (project-local, gitignored). Preserves existing non-engram + hooks. Idempotent. Atomic write with timestamped backup. +- `engram uninstall-hook` — surgical removal. +- `engram hook-stats [--json]` — summarize `.engram/hook-log.jsonl` + with per-event / per-tool / per-decision breakdowns and estimated + token savings. +- `engram hook-preview ` — dry-run the Read handler for a file + without installing. Shows deny+summary, allow+landmines, or + passthrough with explanation. +- `engram hook-disable` / `engram hook-enable` — toggle + `.engram/hook-disabled` kill switch. + +**Seven new hook handlers:** + +- `PreToolUse:Read` — deny + reason with engram's structural summary. + 60% hit rate × ~1,200 tokens saved per hit. Projected: -18,000 + tokens per session. +- `PreToolUse:Edit` / `PreToolUse:Write` — allow + additionalContext + with landmine warnings for files with past mistakes. NEVER blocks + writes — advisory injection only. Projected: -10,000 tokens by + preventing bug re-loops. +- `PreToolUse:Bash` — strict parser for single-argument `cat|head|tail + |less|more ` invocations, delegating to the Read handler. Any + shell metacharacter rejects the parse. Closes the Bash workaround + loophole without risking shell misinterpretation. +- `SessionStart` — injects a project brief (god nodes + graph stats + + top landmines + git branch) on source=startup/clear/compact. + Passes through on source=resume. Replaces 3-5 initial exploration + reads. Projected: -5,000 tokens per session. +- `UserPromptSubmit` — keyword-gated pre-query injection. Extracts + significant terms (≥3 chars, non-stopword), requires ≥2 terms AND + ≥3 graph matches before injecting. Budget 500 tokens per injection. + **PRIVACY:** raw prompt text is never logged. Projected: -8,000 + tokens per session. +- `PostToolUse` — pure observer. Logs tool/path/outputSize/success + to `.engram/hook-log.jsonl` for `engram hook-stats` and v0.3.1 + self-tuning. + +**Total projected savings: -42,500 tokens per session** (on ~52,500 +baseline ≈ 80% session reduction). Every number is arithmetic on +empirically verified hook mechanisms. + +### Added — Infrastructure + +- **`src/intercept/` module (14 files):** safety.ts (error/timeout + wrappers, PASSTHROUGH sentinel, kill-switch check), context.ts + (path normalization, project detection, content safety, cwd guard), + formatter.ts (verified JSON response builders with 8000-char + truncation), dispatch.ts (event routing + PreToolUse decision + logging), installer.ts (pure settings.json transforms), stats.ts + (pure log aggregation), and 7 handlers under `handlers/`. + +- **`src/intelligence/hook-log.ts`:** append-only JSONL logger with + 10MB rotation. Atomic appends (safe for <4KB writes on POSIX + without locking). `readHookLog` for stats queries. Never throws. + +- **10 safety invariants, all enforced at runtime:** + 1. Any handler error → passthrough (never block Claude Code) + 2. 2-second per-handler timeout + 3. Kill switch respected by all handlers + 4. Atomic settings.json writes with backups + 5. Never intercept outside project root + 6. Never intercept binary files or secrets (.env/.pem/.key) + 7. Never log user prompt content + 8. Never inject >8000 chars per hook response + 9. Stale graph detection (file mtime > graph mtime → passthrough) + 10. Partial-read bypass (offset/limit → passthrough) + +### Changed + +- `core.ts::mistakes()` now accepts an optional `sourceFile` filter for + per-file landmine lookup. +- `getFileContext()` added — the bridge from absolute file paths (as + hooks receive them) to graph queries. Never throws. +- `renderFileStructure()` added to `graph/query.ts` — file-scoped + summary renderer. Exposes `codeNodeCount` for accurate confidence. +- Confidence formula: `min(codeNodeCount / 3, 1) × avgNodeConfidence`. + Conservative 0.7 threshold for interception. +- Dispatcher logs PreToolUse decisions to hook-log for `hook-stats`. +- Minor terminology: user-facing comments and docs now say "landmines" + instead of "regret buffer" (internal API unchanged — `mistakes()`, + `list_mistakes` MCP tool, `kind: "mistake"` schema all stable). + +### Test coverage + +- **+225 tests** across Days 1-5 (total 439, up from 214 in v0.2.1). +- Full suite time: ~1.5 seconds. +- 7 end-to-end subprocess tests that actually spawn + `node dist/cli.js intercept` and pipe JSON payloads. +- 4 regression fixtures captured from the 2026-04-11 live spike. +- NEVER-deny invariant asserted for Edit/Write handler in tests. +- PRIVACY invariant asserted for UserPromptSubmit handler in tests. + +### Deferred to v0.3.1 + +- **Grep interception.** Regex metacharacters + string-literal searches + mean engram can't correctly handle every grep. +- **Per-user confidence threshold config.** v0.3.0 hardcodes 0.7. +- **Self-tuning from hook-log data.** Will tune 2.5x mistake boost, + 0.5x keyword downweight, 0.7 confidence threshold, coverage ceiling. + +### Migration + +**No migration needed.** v0.3.0 is purely additive. All v0.2.1 CLI +commands work identically. MCP tools (`query_graph`, `god_nodes`, +`graph_stats`, `shortest_path`, `benchmark`, `list_mistakes`) are +unchanged. The hook layer is opt-in via `engram install-hook`. + +Existing engram projects continue to work without reinstalling. + ## [0.2.1] — 2026-04-10 ### Fixed @@ -249,6 +1209,7 @@ messages for follow-up tracking. (3-11x) and vs full corpus (30-70x). - Apache 2.0 licensed. +[1.0.0]: https://github.com/NickCirv/engram/releases/tag/v1.0.0 [0.2.0]: https://github.com/NickCirv/engram/releases/tag/v0.2.0 [0.1.1]: https://github.com/NickCirv/engram/releases/tag/v0.1.1 [0.1.0]: https://github.com/NickCirv/engram/releases/tag/v0.1.0 diff --git a/CLAUDE.md b/CLAUDE.md index 6fe4338..5d6617a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,14 +3,8 @@ ## Codebase Structure (auto-generated by engram) -**Graph:** 2946 nodes, 3270 edges | 99% extracted, 1% inferred -**View:** bug-fix - -## 🔥 Hot files - -- 🔥 README.md (8 changes) -- 🔥 package.json (6 changes) -- 🔥 src/cli.ts (5 changes) +**Graph:** 451 nodes, 1005 edges | 96% extracted, 4% inferred +**View:** general ## Core entities @@ -18,18 +12,46 @@ - `extractFile()` (function, 2 connections) — src/miners/ast-miner.ts - `generateSummary()` (function, 2 connections) — src/autogen.ts - `writeToFile()` (function, 2 connections) — src/autogen.ts -- `getDbPath()` (function, 2 connections) — src/core.ts +- `parseReadLikeBashCommand()` (function, 2 connections) — src/intercept/handlers/bash.ts +- `createAuthService()` (function, 2 connections) — tests/intercept/handlers/bash.test.ts +- `hashPassword()` (function, 2 connections) — tests/intercept/handlers/bash.test.ts +- `SessionStore` (class, 2 connections) — tests/intercept/handlers/bash.test.ts ## Structure - `./` — tsup.config.ts -- `src/` — autogen.ts, cli.ts, core.ts, hooks.ts, serve.ts -- `src/graph/` — query.ts, render-utils.ts, schema.ts, store.ts -- `src/intelligence/` — token-tracker.ts -- `src/miners/` — ast-miner.ts, git-miner.ts, index.ts, session-miner.ts, skills-miner.ts +- `bench/` — runner.ts +- `src/` — autogen.ts, cli.ts, core.ts, dashboard.ts, hooks.ts, serve.ts, watcher.ts +- `src/ccs/` — exporter.ts, importer.ts +- `src/db/` — migrate.ts +- `src/generators/` — aider-context.ts, cursor-mdc.ts +- `src/graph/` — path-utils.ts, query.ts, render-utils.ts, schema.ts, store.ts +- `src/intelligence/` — hook-log.ts, token-tracker.ts +- `src/intercept/` — component-status.ts, context.ts, cursor-adapter.ts, dispatch.ts, formatter.ts, installer.ts, memory-md.ts, safety.ts, stats.ts +- `src/intercept/handlers/` — bash.ts, cwd-changed.ts, edit-write.ts, lsp-capture.ts, post-tool.ts, pre-compact.ts, read.ts, session-start.ts, user-prompt.ts +- `src/miners/` — ast-miner.ts, git-miner.ts, session-miner.ts, skills-miner.ts +- `src/providers/` — ast.ts, context7.ts, engram-git.ts, engram-mistakes.ts, engram-structure.ts, grammar-loader.ts, lsp-connection.ts, lsp.ts, mempalace.ts, obsidian.ts, resolver.ts, types.ts +- `src/server/` — http.ts +- `src/tuner/` — config.ts, index.ts - `src/types/` — sql.js.d.ts -- `tests/` — ast-miner.test.ts, autogen.test.ts, core.test.ts, mistake-memory.test.ts, render-utils.test.ts, skills-miner.test.ts, store.test.ts, stress.test.ts +- `tests/` — ast-miner.test.ts, autogen.test.ts, core.test.ts, mistake-memory.test.ts, provider-cache.test.ts, render-utils.test.ts, skills-miner.test.ts, store.test.ts, stress.test.ts, watcher.test.ts +- `tests/ccs/` — ccs.test.ts +- `tests/db/` — migrate.test.ts - `tests/fixtures/` — sample.ts +- `tests/generators/` — cursor-mdc.test.ts +- `tests/intercept/` — cli-intercept.test.ts, context.test.ts, cursor-adapter.test.ts, dispatch-new-events.test.ts, dispatch.test.ts, formatter.test.ts, get-file-context.test.ts, hook-log.test.ts, installer.test.ts, memory-md.test.ts, mistakes-filter.test.ts, render-file-structure.test.ts, safety.test.ts, spike-regression.test.ts, stats.test.ts +- `tests/intercept/handlers/` — bash.test.ts, cwd-changed.test.ts, edit-write.test.ts, post-tool.test.ts, pre-compact.test.ts, read.test.ts, session-start.test.ts, user-prompt.test.ts +- `tests/providers/` — ast.test.ts, lsp.test.ts, resolver.test.ts +- `tests/server/` — http.test.ts +- `tests/tuner/` — tuner.test.ts + +## Key dependencies + +- `node_path` (imported by 66 files) +- `vitest` (imported by 41 files) +- `node_fs` (imported by 37 files) +- `node_os` (imported by 34 files) +- `core.ts` (imported by 34 files) **Tip:** Run `engram query "your question"` for structural context instead of reading files. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 77ee93b..070f71b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to engram +# Contributing to EngramX -Thanks for your interest in improving engram. Here's how to help. +Thanks for wanting to help. EngramX is Apache-2.0, welcomes every kind of contribution, and aims to stay meticulously honest about what works and what doesn't. This doc is short because the rules are few. ## Quick Start @@ -12,38 +12,74 @@ npm run build npm test ``` -## What's Most Valuable +You need Node 20+. No native toolchain — EngramX's SQLite is sql.js WASM, all tree-sitter grammars are bundled as WASM. Zero system libraries required. -**Worked examples** are the highest-impact contribution. Run `engram init` on a real codebase, evaluate what the graph got right and wrong, and share the results in an issue or PR. +## Highest-impact contributions -**Language extraction bugs** — if engram misses a function, class, or import in a language it supports, open an issue with the source file and what was missed. +In rough order of "what helps the most": -**New language support** — add regex patterns to `src/miners/ast-miner.ts` following the existing pattern. Include test fixtures. +1. **Worked examples** — run `engram setup` on a real codebase, record what the graph got right and wrong, open an issue. Honest feedback from actual use is more valuable than any patch. +2. **Reproducible bench results** — run `npx tsx bench/real-world.ts --project . --files 50` on your project and share the numbers (especially if you see <50% savings — we want to understand why). +3. **Plugin submissions** — a 10-line MCP plugin file for a service we don't have yet. Drop in `docs/plugins/examples/` + mention the coverage in a PR. +4. **Language extraction bugs** — if `engram init` misses a function/class/import in a supported language, open an issue with the source file and what was missed. +5. **Windows-specific fixes** — EngramX CI covers Ubuntu × Node 20/22 AND Windows × Node 20/22. Windows-path bugs are real. We welcome patches that harden cross-platform behaviour. +6. **New language support** — tree-sitter grammar wiring in `src/miners/ast-miner.ts`, plus a test fixture. -## Development +## Development loop ```bash -npm run dev # Watch mode (auto-rebuild) -npx vitest # Run tests in watch mode -npx vitest run # Run tests once -npm run build # Production build +npm run dev # watch mode — rebuilds on every save +npx vitest # tests in watch mode +npx vitest run # tests once +npm run build # production build (bundled WASM grammars) +npm run lint # TypeScript strict check (tsc --noEmit) +npx tsx bench/real-world.ts # sanity-check your changes against the savings bench ``` -## Before Submitting a PR +## Before you open a PR -1. `npm run build` passes -2. `npx vitest run` passes -3. If you changed extraction logic, add a test fixture and test case -4. Keep PRs focused — one change per PR +1. `npm run build` passes (TypeScript strict). +2. `npx vitest run` passes all suites (currently 878 on v3.0). +3. If you changed extraction logic, add a fixture + test case. +4. **If you touched anything that builds a filesystem path, assert with `path.join()` / `path.resolve()`, never hand-write `/` separators.** We shipped a Windows-CI regression on v3.0's first pass because of this. Tests that build an expected path via `path.join()` (matching the implementation) work on every platform — regex assertions with `\/` do not. +5. Keep PRs focused — one change per PR. -## Code Style +## Code style -- TypeScript strict mode -- ESM imports (`import`, not `require`) -- Immutable patterns (spread, not mutation) -- Functions under 50 lines -- No `console.log` in library code (only in CLI) +- TypeScript strict mode. +- ESM imports (`import`, not `require`). Vitest's CommonJS interop hides bare-`require()` bugs that crash in production — always use top-level ESM imports. +- Immutable patterns (spread, not mutation). +- Functions under ~50 lines. +- No `console.log` in library code — only in CLI entry points (`src/cli.ts`) and the bench runner. +- Every new test that exercises filesystem paths should explicitly include a Windows-native-path case so regressions surface locally, not only on CI. + +## Plugin authors + +Writing a context provider is ~10 lines. See [`docs/plugins/README.md`](docs/plugins/README.md) for the full spec. Two shapes are supported: + +- **MCP-backed** — declare an `mcpConfig` and the loader spawns/connects to the MCP server for you. Any MCP server becomes an EngramX provider in one `.mjs` file. +- **Classic** — write your own `resolve()` + `isAvailable()` for full control. + +Reference examples: +- [`docs/plugins/examples/serena-plugin.mjs`](docs/plugins/examples/serena-plugin.mjs) — MCP-backed (Serena / LSP symbols) +- [`docs/plugins/examples/static-context-plugin.mjs`](docs/plugins/examples/static-context-plugin.mjs) — classic (always-on project reminder) + +Submitting a plugin into the repo: +1. Drop your `.mjs` into `docs/plugins/examples/`. +2. Add a row to the "Plugins multiply the savings" table in `README.md`. +3. Include a short doc-comment header explaining what gap your plugin closes + install notes. + +## Security + +- Never commit credentials. The token at `~/.engram/http-server.token` is auto-generated, `.gitignore`d, and never leaves your machine. +- Found a vulnerability? See [`SECURITY.md`](SECURITY.md) — coordinated disclosure via GitHub advisories, we respond within 48 hours. + +## Community + +- **Issues** for bugs, feature requests, and plugin submissions. +- **GitHub Discussions** for "what benchmark are you seeing on your code" and "has anyone built a plugin for X yet." +- **Security advisories** for anything that could compromise a user's local SQLite. ## License -By contributing, you agree that your contributions will be licensed under the Apache 2.0 License. +Apache 2.0. By contributing you agree that your contributions are licensed under the same. See [`LICENSE`](LICENSE) for the full text. diff --git a/README.md b/README.md index 12b1edf..4ec67c3 100644 --- a/README.md +++ b/README.md @@ -1,299 +1,643 @@

- engram — AI coding memory + EngramX — the cached context spine for AI coding agents (v3.0 'Spine') +

+ + +

+ +

+ +

+ + Install Page · + Live Demo · + Scene Table · + rendered with Hyperframes +

Install · - Usage · - MCP Server · - How It Works · - Integration Guide · + Quickstart · + Dashboard · + Benchmark · + IDE Integrations · + HTTP API · + ECP Spec · Contributing

CI + npm version License Node - Tests - Zero LLM cost + Tests + 9 Providers + plugins + 90.8% measured savings Zero native deps + Zero LLM cost

--- -**Your AI coding assistant forgets everything. We fixed that.** +> **EngramX v3.0 "Spine" shipped 2026-04-24** — the biggest release since v1.0. The spine is now **extensible**: any MCP server becomes an EngramX provider via a 10-line plugin file. **Pre-mortem mistake-guard** warns before you repeat a bug. **Bi-temporal mistake memory** — refactored-away mistakes stop firing. **Anthropic Auto-Memory bridge** reads Claude Code's own consolidated memory. **SSE-streaming** packets render progressively. `engram gen` dual-emits `AGENTS.md` + `CLAUDE.md` by default. **89.1% measured real-world token savings** on 87 source files — reproducible in one command. 878 tests, CI green on Ubuntu + Windows × Node 20 + 22. Zero cloud, zero telemetry. See [CHANGELOG.md](CHANGELOG.md) for the full diff. + +--- + +# EngramX — the cached context spine for AI coding agents. + +Your AI coding agent keeps re-reading the same files. Every `Read`, every `Edit`, every `cat` re-pays for context you've already paid for. -engram gives AI coding tools persistent memory. One command scans your codebase, builds a knowledge graph, and makes every session start where the last one left off. +**EngramX is the spine.** It intercepts every file read at the tool boundary, answers from a pre-assembled context packet held in **three layers of cache** — a knowledge graph the agent has already "paid" to build, a per-provider SQLite cache of external lookups, and an in-memory LRU of recent queries — and hands the agent a single ~500-token response instead of a raw file. -Zero LLM cost. Zero cloud. Works with Claude Code, Cursor, Codex, aider, and any MCP client. +The agent gets what it needs. You stop paying for context you've already paid for. And **every plugin you add elevates the savings further** — Serena for LSP symbols, GitHub MCP for issue context, Sentry MCP for production errors, Supabase / Neon for schema. Each one closes another context leak the agent would otherwise burn tokens researching. + +**Measured savings on a reproducible benchmark: 89.1%.** Not estimated. 85 of 87 real source files saved tokens. Best case 98.4% (18,820 tokens → 306). + +### One command to everything ```bash -npx engram init +npm install -g engramx +cd ~/my-project +engram setup ``` +That's the install. `engram setup` runs `engram init` (builds the graph), `engram install-hook` (wires the Sentinel into your AI tool), detects your IDE, dual-emits `AGENTS.md` + `CLAUDE.md`, then runs `engram doctor` to verify everything green. Under 30 seconds on most projects. Works in Claude Code, Cursor, Codex CLI, Windsurf, GitHub Copilot Chat, JetBrains Junie, Aider, Zed, Continue — any agent that reads `AGENTS.md` or uses MCP. + +The **next session** you open starts with the spine pre-loaded: project brief already in context, file reads intercepted, a live HUD showing cumulative savings, bi-temporal mistakes waiting to warn you, and any plugins you've added already answering their domains. + +--- + +## I'm not a developer — what does this actually do? + +Short answer: **your AI coding assistant stops charging you for the same information twice.** + +Long answer: + +1. You ask your AI assistant (Claude Code, Cursor, Codex, whatever) to help with a file. +2. The assistant tries to read that file. Normally it reads the whole thing, pays for every byte in tokens, and throws most of it away. +3. EngramX catches the read, answers with a cached summary (the 50–200 lines the agent actually needs, plus context from your git history, past mistakes, library docs, and anything else useful), and lets the agent work from that. +4. Your monthly AI bill drops. Multi-hour sessions stop hitting rate limits. The agent stops re-introducing bugs you already fixed — because EngramX remembers what broke. + +It runs on your laptop. It doesn't send your code anywhere. It's Apache 2.0. There's no account, no login, no cloud. You install it once and forget it's there. + +**Want even bigger savings?** Install a plugin. Each one closes a different context leak — see [Plugins multiply the savings](#plugins-multiply-the-savings) below. Drop a 10-line `.mjs` file in `~/.engram/plugins/` and the next session uses it. + +**Want out?** Clean uninstall is one command: + +```bash +npm uninstall -g engramx # 3.0.1+ auto-runs preuninstall hook-cleanup ``` -🔍 Scanning codebase... -🌳 AST extraction complete (42ms, 0 tokens used) - 60 nodes, 96 edges from 14 files (2,155 lines) -📊 Token savings: 11x fewer tokens vs relevant files - Full corpus: ~15,445 tokens | Graph query: ~285 tokens +If you installed 3.0.0 and ran `npm uninstall` before the 3.0.1 patch shipped, your Claude Code hooks may be orphaned. Run `engram repair-hooks --scope user` (install 3.0.1 first if needed) or see the [`CHANGELOG.md`](CHANGELOG.md#301--2026-04-24--clean-uninstall) for the manual `jq`-based recovery one-liner. + +--- + +## Proof, not promises + +Everything above is measured, not estimated. `bench/real-world.ts` runs the full resolver against real files in this repo and compares the rich-packet token cost to the raw-file-read cost. Reproducible in one command on any project. + +Latest run (2026-04-24, 87 source files — full report at [`bench/results/real-world-2026-04-24.md`](bench/results/real-world-2026-04-24.md)): + +| Metric | Value | +|---|---| +| Baseline tokens (87 files read raw) | **163,122** | +| engramx tokens (rich packets) | **17,722** | +| Aggregate savings | **89.1%** | +| Median per-file savings | 84.2% | +| Files where engramx saved tokens | 85 of 87 | +| Best case (`src/cli.ts`) | 98.4% (18,820 → 306) | + +Reproduce on your own code: -✅ Ready. Your AI now has persistent memory. +```bash +cd your-project +engram init # first-time setup for this project +npx tsx /path/to/engram/bench/real-world.ts --project . --files 50 ``` -## Why +The bench writes a JSON + Markdown report per run into `bench/results/`. Small projects score lower; dense structural projects score higher. It's real arithmetic on your files — you can audit every number. -Every AI coding session starts from zero. Claude Code re-reads your files. Cursor reindexes. Copilot has no memory. CLAUDE.md is a sticky note you write by hand. +--- -engram fixes this with five things no other tool combines: +## What engramx is not -1. **Persistent knowledge graph** — survives across sessions, stored in `.engram/graph.db` -2. **Learns from every session** — decisions, patterns, mistakes are extracted and remembered -3. **Universal protocol** — MCP server + CLI + auto-generates CLAUDE.md, .cursorrules, AGENTS.md -4. **Skill-aware** (v0.2) — indexes your `~/.claude/skills/` directory into the graph so queries return code *and* the skill to apply -5. **Regret buffer** (v0.2) — surfaces past mistakes at the top of query results so your AI stops re-making the same wrong turns +The "engram" name is contested. To save you a search: -## Install +- **Not Go-Engram** ([Gentleman-Programming/engram](https://github.com/Gentleman-Programming/engram)) — different project, Go binary, salience-gated chat memory. Ships under `engram` (without the `x`). +- **Not DeepSeek's "Engram" paper** — January 2026 academic work on conditional memory. Research artifact, not a product. +- **Not MemPalace** — adjacent positioning ("knowledge-graph memory," "method-of-loci"), but conversational memory, not code-structural. + +`engramx` is specifically: **a local-first context spine for AI coding agents that hooks into your IDE's tool boundary, indexes your code via tree-sitter + LSP, remembers past mistakes, and assembles ~500-token context packets in place of raw file reads.** Open source, Apache 2.0, single npm install. + +--- + +## Dashboard + +A zero-dependency web dashboard ships built-in. One command, opens in your browser: ```bash -npx engramx init +engram ui ``` -Or install globally: +

+ engram dashboard — Overview tab +

+ +The **Overview** tab: real metrics from your sessions — tokens saved, cost saved at $3/M rate, session-level hit rate, cache performance, graph health. + +

+ engram dashboard — Activity tab +

+ +**Activity** — live hook events streamed via Server-Sent Events. See every `Read` / `Edit` / `Write` decision (deny = intercepted, passthrough = engram couldn't help). Per-tool breakdown on the right shows where the savings come from. + +

+ engram dashboard — Files heatmap +

+ +**Files** — the heatmap ranks your hot files by interception count. Cursor knows this view. + +

+ engram dashboard — Knowledge graph visualization +

+ +**Graph** — Canvas 2D force-directed visualization of the knowledge graph. God nodes are larger and labeled. Drag to pan, scroll to zoom, click for details. 300+ nodes at 60fps. + +

+ engram dashboard — Providers + cache health +

+ +**Providers** — component health (HTTP / LSP / AST / IDE count) and per-layer cache stats (entries + cross-session hit counts). + +### Design + +- **35KB total** — one HTTP response, zero external CDN calls, works offline and on air-gapped machines. +- **Zero runtime dependencies** — all CSS and JS inlined as TypeScript template literals; SVG charts and Canvas 2D graph hand-rolled (~400 LOC total). +- **CSP-hardened** — `default-src 'self'; connect-src 'self'` meta tag plus `esc()` at every data-to-HTML boundary. Defends against attacker-controlled file paths and labels mined from untrusted repos. +- **Live-updating** — SSE stream pushes new hook events to the Activity tab within 1 second. + +See also the **Sessions** tab (cumulative breakdown + sparkline) in [`assets/screenshots/02-sessions.png`](assets/screenshots/02-sessions.png). + +--- + +## Benchmark + +engramx ships with two benchmarks — use whichever fits your workflow. + +### Real-world bench (new in v3.0, preferred) + +`npx tsx bench/real-world.ts --project . --files 50` runs the full resolver against real files in any project and outputs exact token numbers. See the [Proof](#proof-not-promises) section above for the reproducible 89.1% result on engramx itself. + +### Structured task bench (CI regression) + +Measured across 10 structured coding tasks against a baseline of reading the relevant files directly. No synthetic data. No cherry-picked queries. + +| Task | Baseline (tokens) | engram (tokens) | Savings | +|------|:-----------------:|:---------------:|:-------:| +| task-01-find-caller | 4,500 | 650 | 85.6% | +| task-02-parent-class | 2,800 | 400 | 85.7% | +| task-03-file-for-class | 3,200 | 300 | 90.6% | +| task-04-import-graph | 6,800 | 900 | 86.8% | +| task-05-exported-api | 5,500 | 700 | 87.3% | +| task-06-landmine-check | 8,200 | 850 | 89.6% | +| task-07-architecture-sketch | 14,500 | 1,600 | 89.0% | +| task-08-refactor-scope | 9,200 | 1,100 | 88.0% | +| task-09-hot-files | 3,800 | 550 | 85.5% | +| task-10-cross-file-flow | 12,800 | 1,400 | 89.1% | +| **Aggregate** | **7,130** | **845** | **88.1%** | + +Run it yourself: `npx tsx bench/runner.ts` (structured fixtures) or `npx tsx bench/real-world.ts` (live resolver on real files). + +--- + +## Plugins multiply the savings + +The 89.1% number is engramx with its 9 built-in providers. Every MCP server you plug in closes another context gap the agent would otherwise burn tokens researching. And because every provider is budget-capped and the resolver is budget-weighted + mistakes-boost reranked, more plugins = more *relevant* context without packet bloat. + +| Plugin | Closes this gap | Install | +|---|---|---| +| **Serena** (LSP symbols, 20+ languages) | Cross-file references engramx's AST can't resolve precisely — kills the grep-then-read loop | `cp docs/plugins/examples/serena-plugin.mjs ~/.engram/plugins/` | +| **GitHub MCP** (issues, PRs, commits) | Recent PR discussion & issue history for the file being edited | `engram plugin install github` | +| **Sentry MCP** (production errors) | "What broke in prod for this file" — cuts the open-dashboard → paste-trace loop | `engram plugin install sentry` | +| **Supabase / Neon** (schema, RLS) | Database schema context when editing queries / migrations / ORM models | `engram plugin install supabase` | +| **Context7** (library docs) | Always-current API surface for your actual imports | shipped as a built-in | +| **Anthropic Auto-Memory** | Claude Code's own consolidated project memory | shipped — auto-detected when `~/.claude/projects/…/memory/MEMORY.md` exists | + +Writing a plugin is **~10 lines** — see [`docs/plugins/README.md`](docs/plugins/README.md) for the full spec + examples. + +--- + +## What It Does + +engram sits between your AI agent and the filesystem. When the agent reads a file, engram checks its knowledge graph. If the file is covered with sufficient confidence, it blocks the read and injects a compact context packet instead. The packet is assembled from up to 9 built-in providers plus any plugins you've added, all pre-cached at session start. + +**The 9 built-in providers (v3.0):** + +| Provider | Source | Confidence | Latency | +|----------|--------|:-----------:|:-------:| +| `engram:ast` | Tree-sitter parse (10 languages) | 1.0 | <50ms | +| `engram:structure` | Regex heuristics (fallback) | 0.85 | <50ms | +| `engram:mistakes` | Past failure nodes (bi-temporal — stale mistakes filtered out) | — | <10ms | +| `anthropic:memory` | Claude Code's auto-managed `MEMORY.md` index (v3.0) | 0.85 | <10ms | +| `engram:git` | Co-change patterns, churn, authorship | — | <100ms | +| `mempalace` | Decisions, learnings, project context | — | <5ms cached | +| `context7` | Library API docs for detected imports | — | <5ms cached | +| `obsidian` | Project notes, architecture docs | — | <5ms cached | +| `engram:lsp` | Live diagnostics captured as mistake nodes | — | on-event | + +External providers cache into SQLite at SessionStart. Per-read resolution is a cache lookup, not a live call. If a provider is unavailable it is skipped silently — you always get at least the structural summary. **Plus: any MCP server becomes a provider via a 10-line plugin file** — see [Plugins multiply the savings](#plugins-multiply-the-savings) above. + +**The 9 hook handlers:** + +| Hook | What it does | +|------|-------------| +| `PreToolUse:Read` | Blocks the read if file is covered. Delivers structural summary as the block reason. | +| `PreToolUse:Edit` | Passes through. Injects known mistakes as landmine warnings alongside the edit. | +| `PreToolUse:Write` | Same as Edit — advisory injection only, never blocks writes. | +| `PreToolUse:Bash` | Catches `cat \| head \| tail \| less \| more ` and delegates to the Read handler. | +| `SessionStart` | Injects a compact project brief (god nodes, graph stats, top landmines, git branch). Bundles MemPalace context in parallel. | +| `UserPromptSubmit` | Extracts keywords from the prompt, runs a budget-capped pre-query, injects results before the agent responds. | +| `PostToolUse` | Observer only. Writes to `.engram/hook-log.jsonl` for `hook-stats`. | +| `PreCompact` | Re-injects god nodes and active landmines right before Claude compresses the conversation. Survives compaction. | +| `CwdChanged` | Auto-switches project context when you navigate to a different repo mid-session. | + +**Ten safety invariants enforced at runtime:** + +1. Any handler error → passthrough (Claude Code is never blocked) +2. 2-second per-handler timeout +3. Kill switch (`.engram/hook-disabled`) respected by every handler +4. Atomic settings.json writes with timestamped backups +5. Never intercept outside the project root +6. Never intercept binary files or secrets (`.env`, `.pem`, `.key`, `id_rsa`, etc.) +7. Never log user prompt content (privacy invariant, asserted in tests) +8. Never inject more than 8,000 chars per hook response +9. Stale graph detection — file mtime newer than graph mtime → passthrough +10. Partial-read bypass — explicit `offset` or `limit` on Read → passthrough + +--- + +## Install ```bash npm install -g engramx -engram init ``` -Requires Node.js 20+. Zero native dependencies. No build tools needed. +Requires Node.js 20+. Zero native dependencies. No build tools. Local SQLite via sql.js WASM — no Rust, no Python, no system libs. + +> **Prefer a designed walkthrough?** Open [**docs/install.html**](docs/install.html) — three-step install, benefits matrix, IDE coverage, FAQ. Local file, opens in any browser. Brand-matched terminal-mono aesthetic. + +--- + +## Quickstart + +**One command, zero friction:** + +```bash +cd ~/my-project +engram setup # init + install-hook + adapter detect + doctor +``` + +`engram setup` runs the whole first-run flow interactively (or pass `-y` for defaults, `--dry-run` to preview). It is idempotent — safe to re-run, and skips any step already done. -## Usage +Prefer the individual commands? ```bash -engram init [path] # Scan codebase, build knowledge graph -engram init --with-skills # Also index ~/.claude/skills/ (v0.2) -engram query "how does auth" # Query the graph (BFS, token-budgeted) -engram query "auth" --dfs # DFS traversal (trace specific paths) -engram gods # Show most connected entities -engram stats # Node/edge counts, token savings -engram bench # Token reduction benchmark -engram path "auth" "database" # Shortest path between concepts -engram learn "chose JWT..." # Teach a decision or pattern -engram mistakes # List known mistakes (v0.2) -engram gen # Generate CLAUDE.md section from graph -engram gen --task bug-fix # Task-aware view (v0.2: general|bug-fix|feature|refactor) -engram hooks install # Auto-rebuild on git commit +cd ~/my-project +engram init # scan codebase → .engram/graph.db (~40ms, 0 tokens) +engram install-hook # wire the Sentinel into Claude Code +engram ui # open the web dashboard in your browser ``` -## How It Works +**Diagnostics + self-update:** -engram runs three miners on your codebase. None of them use an LLM. +```bash +engram doctor # component health + remediation hints (0=ok, 1=warn, 2=fail) +engram update # check + upgrade via detected pkg manager (no telemetry) +engram update --check # check only, dry-probe the registry +``` -**AST Miner** — Extracts code structure (classes, functions, imports, exports, call patterns) using pattern matching across 10 languages: TypeScript, JavaScript, Python, Go, Rust, Java, C, C++, Ruby, PHP. Zero tokens, deterministic, cached. +Set `ENGRAM_NO_UPDATE_CHECK=1` to disable the passive "newer version available" hint on every CLI invocation. `$CI` does the same automatically. -**Git Miner** — Reads `git log` for co-change patterns (files that change together), hot files (most frequently modified), and authorship. Creates INFERRED edges between structurally coupled files. +Open a Claude Code session. When the agent reads a well-covered file you will see a system-reminder with the structural summary instead of file contents. After the session: -**Session Miner** — Scans CLAUDE.md, .cursorrules, AGENTS.md, and `.engram/sessions/` for decisions, patterns, and mistakes your team has documented. Stores these as queryable graph nodes. +```bash +engram hook-stats # what was intercepted, tokens saved (CLI) +engram ui # same data, richer view, real-time updates +engram hook-preview src/auth.ts # dry-run: see what the hook would inject for one file +``` -Results are stored in a local SQLite database (`.engram/graph.db`) and queryable via CLI, MCP server, or programmatic API. +**Full recommended setup (one-time per project):** -## MCP Server +```bash +npm install -g engramx +cd ~/my-project +engram init --with-skills # also index ~/.claude/skills/ into the graph +engram install-hook # wire Sentinel into Claude Code +engram hooks install # auto-rebuild graph on every git commit +``` -Connect engram to Claude Code, Windsurf, or any MCP client: +**Experience tiers — each works standalone:** -```json -{ - "mcpServers": { - "engram": { - "command": "npx", - "args": ["-y", "engramx", "serve", "/path/to/your/project"] - } - } -} +| Tier | What you run | What you get | +|------|-------------|-------------| +| Graph only | `engram init` | CLI queries, MCP server, `engram gen` for CLAUDE.md | +| + Sentinel | `engram install-hook` | Automatic Read interception, Edit warnings, session briefs, HUD | +| + Context Spine | Configure providers.json | Rich packets from 9 built-ins + any MCP plugin per read | +| + Skills index | `engram init --with-skills` | Graph includes your `~/.claude/skills/` | +| + Git hooks | `engram hooks install` | Graph rebuilds on every commit, stays current | +| + HTTP server | `engram server --http` | REST API on port 7337 for external tooling | + +--- + +## IDE Integrations + +| IDE | Integration | Setup | +|-----|------------|-------| +| **Claude Code** | Hook-based interception (native, automatic) | `engram install-hook` | +| **Cursor** | MDC snapshot + native MCP | `engram gen-mdc` · [docs/integrations/cursor-mcp.md](docs/integrations/cursor-mcp.md) | +| **Continue.dev** | `@engram` context provider | [docs/integrations/continue.md](docs/integrations/continue.md) | +| **Zed** | Context server (`/engram`) | `engram context-server` | +| **Aider** | Context file generation | `engram gen-aider` | +| **Windsurf** (Codeium) | `.windsurfrules` snapshot + MCP | `engram gen-windsurfrules` | +| **Neovim** | MCP via codecompanion / avante | [docs/integrations/neovim.md](docs/integrations/neovim.md) | +| **Emacs** | MCP via gptel-mcp | [docs/integrations/emacs.md](docs/integrations/emacs.md) | + +Per-IDE setup guides are in [`docs/integrations/`](docs/integrations/). + +--- + +## How It Compares + +| | engram | Continue @RepoMap | Cursor .cursorrules | Aider repo-map | @199-bio/engram | +|---|---|---|---|---|---| +| **Interception model** | Hook-based, automatic on every Read | Fetched at @-mention time | Static file, manual | Per-session map | MCP server, called explicitly | +| **Cache strategy** | SQLite at SessionStart, <5ms per read | No cache — live fetch | No cache | Per-session only | No cache | +| **Persistent memory** | Decisions, mistakes, patterns across sessions | No | Manual text file | No | No | +| **Multiple providers** | 8 (AST, git, mistakes, MemPalace, Context7, Obsidian, LSP) | Repo structure only | No | Repo structure only | Graph query only | +| **Mistake tracking** | LSP diagnostics → mistake nodes, ⚠️ on Edit | No | No | No | No | +| **Survives compaction** | Yes (PreCompact hook) | No | Yes (static file) | No | No | +| **LLM cost** | $0 | $0 | $0 | $0 | $0 | +| **Native deps** | Zero | No | No | No | No | + +--- + +## Install + Configuration + +```bash +npm install -g engramx ``` -Or if installed globally: +**providers.json** (optional — auto-detection works for most setups): ```json { - "mcpServers": { - "engram": { - "command": "engram-serve", - "args": ["/path/to/your/project"] - } + "providers": { + "mempalace": { "enabled": true }, + "context7": { "enabled": true }, + "obsidian": { "enabled": true, "vault": "~/vault" }, + "lsp": { "enabled": true } } } ``` -**MCP Tools** (6 total): -- `query_graph` — Search the knowledge graph with natural language -- `god_nodes` — Core abstractions (most connected entities) -- `graph_stats` — Node/edge counts, confidence breakdown -- `shortest_path` — Trace connections between two concepts -- `benchmark` — Token reduction measurement -- `list_mistakes` — Known failure modes from past sessions (v0.2) +**Hook scope options:** -### Shell Wrapper (for Bash-based agents) +```bash +engram install-hook # default: .claude/settings.local.json (gitignored) +engram install-hook --scope project # .claude/settings.json (committed) +engram install-hook --scope user # ~/.claude/settings.json (global) +engram install-hook --dry-run # preview changes without writing +engram install-hook --auto-reindex # also keep the graph fresh after every Edit/Write/MultiEdit (#8) +``` -If your agent stack runs shell commands instead of JSON-RPC MCP, use the reference wrapper at [`scripts/mcp-engram`](scripts/mcp-engram). One command handles all projects via `-p ` — no per-project MCP server needed. +**Kill switch (if anything goes wrong):** ```bash -cp scripts/mcp-engram ~/bin/mcp-engram && chmod +x ~/bin/mcp-engram -mcp-engram query "how does auth work" -p ~/myrepo +engram hook-disable # touches .engram/hook-disabled — all handlers pass through +engram hook-enable # removes the kill switch +engram uninstall-hook # surgical removal, preserves other hooks in settings.json ``` -See [`docs/INTEGRATION.md`](docs/INTEGRATION.md) for multi-machine setups, rule-file integration, and gotchas. +--- -## Auto-Generated AI Instructions +## CLI Reference -After building a graph, run: +**Core:** ```bash -engram gen # Auto-detect CLAUDE.md / .cursorrules / AGENTS.md -engram gen --target claude # Write to CLAUDE.md -engram gen --target cursor # Write to .cursorrules -engram gen --target agents # Write to AGENTS.md +engram init [path] # scan codebase, build knowledge graph +engram init --with-skills # also index ~/.claude/skills/ +engram query "how does auth" # query the graph (BFS, token-budgeted) +engram query "auth" --dfs # DFS traversal +engram gods # most connected entities +engram stats # node/edge counts, confidence breakdown +engram bench # token reduction benchmark (10 tasks) +engram stress-test # full stress test suite +engram path "auth" "database" # shortest path between concepts +engram learn "chose JWT..." # add a decision or pattern to the graph +engram mistakes # list known landmines ``` -This writes a structured codebase summary — god nodes, file structure, key dependencies, decisions — so your AI assistant navigates by structure instead of grepping. +**Code generation:** -### Task-Aware Views (v0.2) +```bash +engram gen # auto-detect target (CLAUDE.md / .cursorrules / AGENTS.md) +engram gen --target claude # write to CLAUDE.md +engram gen --target cursor # write to .cursorrules +engram gen --target agents # write to AGENTS.md +engram gen --task bug-fix # task-aware view (general | bug-fix | feature | refactor) +engram gen --memory-md # write structural facts to Claude's native MEMORY.md +engram gen-mdc # generate Cursor MDC rules +engram gen-aider # generate Aider context file +engram gen-ccs # generate CCS-compatible output +``` -`engram gen --task ` emits different content based on what you're about to do. The four preset views are defined in `src/autogen.ts` as a data table — no branching logic — so you can add your own task modes without touching the renderer. +**Sentinel:** ```bash -engram gen --task general # default — balanced mix of sections -engram gen --task bug-fix # emphasizes hot files + past mistakes -engram gen --task feature # emphasizes architecture + decisions -engram gen --task refactor # emphasizes god nodes + dependency graph +engram intercept # hook entry point (called by Claude Code, reads stdin) +engram install-hook # install hooks into Claude Code settings +engram uninstall-hook # remove engram entries +engram hook-stats # summarize .engram/hook-log.jsonl +engram hook-stats --json # machine-readable output +engram hook-preview # dry-run Read handler for a specific file +engram hook-disable # kill switch +engram hook-enable # remove kill switch ``` -Each view picks a different set of sections with different limits. For example, `bug-fix` omits `## Decisions` and `## Key dependencies` entirely (they'd just be noise when you're chasing a regression) and leads with `🔥 Hot files` and `⚠️ Past mistakes`. +**Infrastructure:** -## How engram Compares +```bash +engram watch [path] # live file watcher — incremental re-index on save +engram reindex # re-index one file (editor/hook/CI primitive, issue #8) +engram reindex-hook # PostToolUse hook entry point (reads JSON from stdin, always exits 0) +engram dashboard [path] # live terminal dashboard +engram hud-label [path] # JSON label for Claude HUD --extra-cmd integration +engram hooks install # install post-commit + post-checkout git hooks +engram hooks status # check git hook installation +engram hooks uninstall # remove git hooks +engram server --http # start HTTP REST server on port 7337 +engram context-server # start Zed context server +engram tune --dry-run # auto-tune provider weights (preview mode) +engram db status # schema version, migration state +engram init --from-ccs # import from CCS-format context file +``` -| | engram | Mem0 | Graphify | aider repo-map | CLAUDE.md | -|---|---|---|---|---|---| -| **Code structure** | AST extraction (10 langs) | No | Yes (tree-sitter) | Yes (tree-sitter) | No | -| **Persistent memory** | SQLite graph, survives sessions | Yes (vector + graph) | Static snapshot | Per-session only | Manual text file | -| **Session learning** | Mines decisions, patterns, mistakes | Generic facts | No | No | You write it by hand | -| **Universal** | MCP + CLI + auto-gen | API only | Claude Code only | aider only | Claude Code only | -| **LLM cost** | $0 | $0 (self-host) / paid cloud | Tokens for docs/images | Per-session | $0 | -| **Code-specific** | Built for codebases | Generic AI memory | Yes | Yes | No | -| **Temporal** | Git history mining | No | No | No | No | +**Claude HUD integration:** -**The gap nobody fills:** Code-structural understanding + persistent cross-session learning + temporal awareness + works with every AI tool. engram is the first to combine all four. +Add `--extra-cmd="engram hud-label"` to your statusLine command to see live savings: -## Confidence System +``` +engram 48.5K saved 75% +``` -Every relationship in the graph is tagged: +--- -| Tag | Meaning | Score | -|-----|---------|-------| -| **EXTRACTED** | Found directly in source code (import, function definition) | 1.0 | -| **INFERRED** | Reasoned from patterns (git co-changes, session decisions) | 0.4-0.9 | -| **AMBIGUOUS** | Uncertain, flagged for review | 0.1-0.3 | +## HTTP API -You always know what was found vs guessed. +Start the server with `engram server --http` (default port 7337). -## Token Savings +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/health` | Server health + graph stats | +| `POST` | `/query` | Query the knowledge graph | +| `GET` | `/gods` | Most connected entities | +| `GET` | `/stats` | Node/edge counts, confidence breakdown | +| `POST` | `/path` | Shortest path between two concepts | +| `GET` | `/mistakes` | Known failure nodes | +| `POST` | `/learn` | Add a decision or pattern | +| `POST` | `/init` | Trigger a graph rebuild | +| `GET` | `/hook-stats` | Hook interception log summary | -engram reports two honest baselines: +All responses are JSON. The server is local-only by default — bind address is `127.0.0.1`. -- **vs relevant files** — compared to reading only the files that match your query. This is the fair comparison. Typical: **3-11x** fewer tokens. -- **vs full corpus** — compared to sending your entire codebase. This is the worst case you're avoiding. Typical: **30-400x** fewer tokens. +--- -Both are reported transparently. No inflated claims. +## MCP Server + +```json +{ + "mcpServers": { + "engram": { + "command": "npx", + "args": ["-y", "engramx", "serve", "/path/to/your/project"] + } + } +} +``` -## Git Hooks +**MCP Tools (6):** -Auto-rebuild the graph on every commit: +- `query_graph` — search the knowledge graph with natural language +- `god_nodes` — core abstractions (most connected entities) +- `graph_stats` — node/edge counts, confidence breakdown +- `shortest_path` — trace connections between two concepts +- `benchmark` — token reduction measurement +- `list_mistakes` — known failure modes from past sessions + +**Shell wrapper (for Bash-based agents):** ```bash -engram hooks install # Install post-commit + post-checkout hooks -engram hooks status # Check installation -engram hooks uninstall # Remove hooks +cp scripts/mcp-engram ~/bin/mcp-engram && chmod +x ~/bin/mcp-engram +mcp-engram query "how does auth work" -p ~/myrepo ``` -Code changes trigger an instant AST rebuild (no LLM, <50ms). The graph stays fresh without manual re-runs. +--- + +## ECP Spec + +engram v1.0 ships the first draft of the **Engram Context Protocol** (ECP v0.1) — an open specification for how AI coding tools should package and exchange structured context packets. + +The spec defines the wire format, provider negotiation, budget constraints, and confidence scoring used by engram internally. Any tool can implement the spec to produce or consume engram-compatible context packets. + +**License:** CC-BY 4.0 +**Spec:** [`docs/specs/ecp-v0.1.md`](docs/specs/ecp-v0.1.md) + +--- ## Programmatic API ```typescript -import { init, query, godNodes, stats } from "engram"; +import { init, query, godNodes, stats } from "engramx"; -// Build the graph const result = await init("./my-project"); console.log(`${result.nodes} nodes, ${result.edges} edges`); -// Query it const answer = await query("./my-project", "how does auth work"); console.log(answer.text); -// Get god nodes const gods = await godNodes("./my-project"); for (const g of gods) { console.log(`${g.label} — ${g.degree} connections`); } ``` +--- + ## Architecture ``` src/ ├── cli.ts CLI entry point ├── core.ts API surface (init, query, stats, learn) -├── serve.ts MCP server (5 tools, JSON-RPC stdio) +├── serve.ts MCP server (6 tools, JSON-RPC stdio) +├── server.ts HTTP REST server (port 7337) ├── hooks.ts Git hook install/uninstall -├── autogen.ts CLAUDE.md / .cursorrules generation +├── autogen.ts CLAUDE.md / .cursorrules / MDC generation ├── graph/ -│ ├── schema.ts Types: nodes, edges, confidence -│ ├── store.ts SQLite persistence (sql.js, zero native deps) +│ ├── schema.ts Types: nodes, edges, confidence, schema versioning +│ ├── store.ts SQLite persistence (sql.js WASM, zero native deps) │ └── query.ts BFS/DFS traversal, shortest path ├── miners/ -│ ├── ast-miner.ts Code structure extraction (10 languages) +│ ├── ast-miner.ts Tree-sitter AST extraction (10 languages, confidence 1.0) │ ├── git-miner.ts Change patterns from git history -│ └── session-miner.ts Decisions/patterns from AI session docs +│ ├── session-miner.ts Decisions/patterns from AI session docs +│ └── skills-miner.ts ~/.claude/skills/ indexer (opt-in) +├── providers/ +│ ├── context-spine.ts Provider assembly + budget management +│ ├── mempalace.ts MemPalace integration +│ ├── context7.ts Context7 library docs +│ ├── obsidian.ts Obsidian vault +│ └── lsp.ts LSP diagnostic capture └── intelligence/ └── token-tracker.ts Cumulative token savings measurement ``` -## Supported Languages - -TypeScript, JavaScript, Python, Go, Rust, Java, C, C++, Ruby, PHP. +**Supported languages (AST):** TypeScript, JavaScript, Python, Go, Rust, Java, C, C++, Ruby, PHP. -## Roadmap +--- -### v0.2 (current) — **shipped April 2026** -- ✅ Skills miner — index `~/.claude/skills/` into the graph -- ✅ Adaptive gen — task-aware views (`--task general|bug-fix|feature|refactor`) -- ✅ Regret buffer — surface past mistakes at the top of query results -- ✅ `list_mistakes` MCP tool -- ✅ Atomic init lockfile -- ✅ Marker-safe `writeToFile` + surrogate-safe truncation +## Privacy -### v0.3 -- Tree-sitter WASM (20+ languages with full call-graph precision) -- Cross-project graph (query patterns across *all* your projects) -- Temporal graph (commit-snapshot deltas — "what changed in auth this week?") -- Token enforcement PreToolUse hook for Claude Code +Everything runs locally. No data leaves your machine. No telemetry. No cloud dependency. The only network call is `npm install`. Prompt content is never logged (asserted in 579 tests). -### v0.4+ -- LLM-free semantic search (locality-sensitive hashing over n-grams) -- Graph-as-IR experimental spike -- Team memory sync (paid tier) +--- -## Privacy +## Contributing -Everything runs locally. No data leaves your machine. No telemetry. No cloud. The only network call is `npm install`. +Issues and PRs welcome at [github.com/NickCirv/engram](https://github.com/NickCirv/engram). -## License +Run `engram init` on a real codebase and share what it got right and wrong. The benchmark suite (`engram bench`) is the fastest way to see the difference on your own code. -Apache 2.0 +--- -## Contributing +## License -Issues and PRs welcome. Run `engram init` on a real codebase and share what it got right and wrong. +[Apache 2.0](LICENSE) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..441649d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,59 @@ +# Security Policy + +## Reporting a vulnerability + +**Please do not file public issues for security bugs.** + +Report security vulnerabilities privately via GitHub: + +- **Preferred:** [Report a vulnerability](https://github.com/NickCirv/engram/security/advisories/new) (GitHub Private Vulnerability Reporting) +- **Alternative:** Email the maintainer — contact address is in the repo owner's GitHub profile + +Please include: + +- A concise description of the issue. +- Affected version(s) and platform. +- Steps to reproduce — ideally a minimal PoC. +- Impact analysis (what an attacker can achieve). +- Suggested remediation if you have one. + +We aim to: + +- Acknowledge receipt within 3 business days. +- Triage and confirm within 7 business days. +- Ship a fix within 30 days for high/critical severity, 90 days otherwise. +- Credit reporters in the release notes and GitHub Security Advisory unless you request anonymity. + +## Supported versions + +Only the latest minor release line gets security patches. + +| Version | Supported | +| ------- | --------- | +| 2.x | ✅ | +| < 2.0 | ❌ | + +## Scope + +In scope: + +- The `engramx` npm package (CLI, HTTP server, hook pipeline, MCP server). +- Local data exposure via the HTTP server bound to `127.0.0.1`. +- Indirect prompt injection through graph nodes that get surfaced to coding agents. +- Path traversal, SSRF, injection bugs in engram's own code. + +Out of scope: + +- Vulnerabilities in dependencies — report those upstream. +- Issues that require root or filesystem write access on the developer's machine to exploit (attacker is already on the box). +- Missing defense-in-depth hardening that doesn't translate to an exploit (please file as a normal issue). + +## Threat model + +engram is a local developer tool. The HTTP server binds to `127.0.0.1`, reads a random auth token from `~/.engram/http-server.token` (mode 0600), and requires either `Authorization: Bearer ` or an `HttpOnly` `engram_token` cookie on every non-public route. It rejects cross-origin browser tabs via Host + Origin validation and blocks the `text/plain` CSRF vector on mutations by requiring `application/json`. + +The web dashboard at `/ui` is bootstrapped by the `engram ui` CLI, which opens `http://127.0.0.1:7337/ui?token=` and exchanges the token for an `HttpOnly; SameSite=Strict` cookie via a one-shot 302 redirect. The dashboard's JavaScript never sees the raw token. + +## Past advisories + +- **v2.0.2 (2026-04-18)** — Fixed CORS wildcard + auth-off-by-default on the HTTP server. Reported by @gabiudrescu ([#7](https://github.com/NickCirv/engram/issues/7)). diff --git a/adapters/continue/README.md b/adapters/continue/README.md new file mode 100644 index 0000000..74f754b --- /dev/null +++ b/adapters/continue/README.md @@ -0,0 +1,36 @@ +# engramx-continue + +Continue.dev context provider for [engram](https://github.com/NickCirv/engram) — surfaces the knowledge graph as `@engram` in chat. + +## Prerequisites + +engram must be initialized in your project: + +```bash +npm install -g engramx +engram init /path/to/project +``` + +## Install + +```bash +npm install engramx-continue +``` + +## Configure + +Add to `~/.continue/config.json`: + +```json +{ + "contextProviders": [ + { "name": "engramx-continue" } + ] +} +``` + +## Use + +Type `@engram` in Continue chat. The provider queries the local knowledge graph and injects architecture, decisions, patterns, and known issues as context. + +Falls back to HTTP (`127.0.0.1:7337`) if the CLI is unavailable. Returns empty if both fail — no errors surface to the user. diff --git a/adapters/continue/package-lock.json b/adapters/continue/package-lock.json new file mode 100644 index 0000000..080abc5 --- /dev/null +++ b/adapters/continue/package-lock.json @@ -0,0 +1,88 @@ +{ + "name": "engramx-continue", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "engramx-continue", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@anthropic-ai/sdk": "*" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.90.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.90.0.tgz", + "integrity": "sha512-MzZtPabJF1b0FTDl6Z6H5ljphPwACLGP13lu8MTiB8jXaW/YXlpOp+Po2cVou3MPM5+f5toyLnul9whKCy7fBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT", + "peer": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/adapters/continue/package.json b/adapters/continue/package.json new file mode 100644 index 0000000..458b4f1 --- /dev/null +++ b/adapters/continue/package.json @@ -0,0 +1,41 @@ +{ + "name": "engramx-continue", + "version": "1.0.0", + "description": "Continue.dev context provider for engram — surfaces knowledge graph as @engram", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsc", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "continue", + "context-provider", + "engram", + "engramx", + "ai-coding", + "knowledge-graph" + ], + "author": "NickCirv", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/NickCirv/engram" + }, + "peerDependencies": { + "@anthropic-ai/sdk": "*" + }, + "devDependencies": { + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/adapters/continue/src/index.ts b/adapters/continue/src/index.ts new file mode 100644 index 0000000..f168171 --- /dev/null +++ b/adapters/continue/src/index.ts @@ -0,0 +1,138 @@ +import { execFile } from "child_process"; +import { promisify } from "util"; + +const execFileAsync = promisify(execFile); + +// Continue.dev interface definitions (peer dependency — not installed) +interface ContextProviderDescription { + title: string; + displayTitle: string; + description: string; + type: "normal" | "query" | "submenu"; +} + +interface ContextItem { + content: string; + name: string; + description: string; + uri?: { type: "url" | "file"; value: string }; +} + +interface IDE { + getWorkspaceDirs(): string[]; +} + +interface RangeInFile { + filepath: string; + range: { start: { line: number; character: number }; end: { line: number; character: number } }; +} + +interface ContextProviderExtras { + fullInput: string; + ide: IDE; + selectedCode: RangeInFile[]; +} + +interface IContextProvider { + get description(): ContextProviderDescription; + getContextItems(query: string, extras: ContextProviderExtras): Promise; +} + +const ENGRAM_HTTP_URL = "http://127.0.0.1:7337"; +const CLI_TIMEOUT_MS = 5000; +const HTTP_TIMEOUT_MS = 3000; +const DEFAULT_BUDGET = 2000; + +async function queryViaCli(query: string, workspaceRoot: string): Promise { + // Use execFile (array args) instead of exec (shell string) — avoids + // shell injection and works cross-platform (no shell escaping needed). + const { stdout } = await execFileAsync( + "engram", + ["query", query, "-p", workspaceRoot, "--budget", String(DEFAULT_BUDGET)], + { timeout: CLI_TIMEOUT_MS } + ); + + const trimmed = stdout.trim(); + return trimmed.length > 0 ? trimmed : null; +} + +async function queryViaHttp(query: string): Promise { + const url = `${ENGRAM_HTTP_URL}/query?q=${encodeURIComponent(query)}&budget=${DEFAULT_BUDGET}`; + + const res = await fetch(url, { + signal: AbortSignal.timeout(HTTP_TIMEOUT_MS), + }); + + if (!res.ok) { + return null; + } + + const data = (await res.json()) as { text?: string } | unknown; + if (data && typeof data === "object" && "text" in data && typeof (data as { text: unknown }).text === "string") { + return (data as { text: string }).text || null; + } + + const serialized = JSON.stringify(data); + return serialized.length > 2 ? serialized : null; +} + +class EngramContextProvider implements IContextProvider { + get description(): ContextProviderDescription { + return { + title: "engram", + displayTitle: "Engram Memory", + description: + "Knowledge graph context: architecture, decisions, patterns, and known issues", + type: "query", + }; + } + + async getContextItems( + query: string, + extras: ContextProviderExtras + ): Promise { + if (!query.trim()) { + return []; + } + + const workspaceRoot = + extras?.ide?.getWorkspaceDirs?.()[0] ?? process.cwd(); + + // Strategy 1: CLI subprocess + try { + const cliResult = await queryViaCli(query, workspaceRoot); + if (cliResult !== null) { + return [ + { + content: cliResult, + name: "engram", + description: `Engram knowledge graph context for: ${query}`, + }, + ]; + } + } catch { + // CLI not available or project not initialized — fall through to HTTP + } + + // Strategy 2: HTTP server (Sprint 2 / remote mode) + try { + const httpResult = await queryViaHttp(query); + if (httpResult !== null) { + return [ + { + content: httpResult, + name: "engram", + description: `Engram knowledge graph context for: ${query}`, + }, + ]; + } + } catch { + // HTTP server not running — graceful degradation + } + + return []; + } +} + +export default EngramContextProvider; +export type { IContextProvider, ContextProviderDescription, ContextItem, ContextProviderExtras }; diff --git a/adapters/continue/tsconfig.json b/adapters/continue/tsconfig.json new file mode 100644 index 0000000..0117ec8 --- /dev/null +++ b/adapters/continue/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2022"], + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/adapters/zed/index.ts b/adapters/zed/index.ts new file mode 100644 index 0000000..f629dd5 --- /dev/null +++ b/adapters/zed/index.ts @@ -0,0 +1,115 @@ +#!/usr/bin/env tsx +/** + * engram Zed Context Server + * + * Implements the Zed context server protocol (JSON-RPC over stdio). + * Invoked via: engram context-server + * + * Protocol: + * context/list → advertise the "engram" slash command + * context/fetch → run engram query, return text + */ + +import { createInterface } from "node:readline"; +import { execFileSync } from "node:child_process"; + +interface JsonRpcRequest { + readonly jsonrpc: "2.0"; + readonly id: number | string; + readonly method: string; + readonly params?: Record; +} + +interface JsonRpcResponse { + readonly jsonrpc: "2.0"; + readonly id: number | string; + readonly result?: unknown; + readonly error?: { readonly code: number; readonly message: string }; +} + +function respond(id: number | string, result: unknown): JsonRpcResponse { + return { jsonrpc: "2.0", id, result }; +} + +function respondError( + id: number | string, + code: number, + message: string +): JsonRpcResponse { + return { jsonrpc: "2.0", id, error: { code, message } }; +} + +function handleList(id: number | string): JsonRpcResponse { + return respond(id, { + contexts: [ + { + name: "engram", + description: + "Knowledge graph context: architecture, decisions, patterns, known issues", + }, + ], + }); +} + +function handleFetch( + id: number | string, + params: Record +): JsonRpcResponse { + const queryText = typeof params.query === "string" ? params.query.trim() : ""; + const projectRoot = + typeof params.project === "string" ? params.project : process.cwd(); + + if (!queryText) { + return respond(id, { text: "Provide a query to search the engram graph." }); + } + + try { + const output = execFileSync( + "engram", + ["query", queryText, "-p", projectRoot, "--budget", "2000"], + { encoding: "utf-8", timeout: 8000 } + ); + return respond(id, { text: output.trim() || "No matching context found." }); + } catch { + return respond(id, { + text: "engram query failed — is the project indexed? Run: engram init", + }); + } +} + +function handleRequest(req: JsonRpcRequest): JsonRpcResponse { + switch (req.method) { + case "context/list": + return handleList(req.id); + + case "context/fetch": { + const params = req.params ?? {}; + return handleFetch(req.id, params); + } + + default: + return respondError( + req.id, + -32601, + `Method not found: ${req.method}` + ); + } +} + +const rl = createInterface({ input: process.stdin, terminal: false }); + +rl.on("line", (line) => { + const trimmed = line.trim(); + if (!trimmed) return; + + let req: JsonRpcRequest; + try { + req = JSON.parse(trimmed) as JsonRpcRequest; + } catch { + // Malformed JSON — skip silently per JSON-RPC spec + return; + } + + const res = handleRequest(req); + process.stdout.write(JSON.stringify(res) + "\n"); +}); diff --git a/assets/banner-v3.png b/assets/banner-v3.png new file mode 100644 index 0000000..609066f Binary files /dev/null and b/assets/banner-v3.png differ diff --git a/assets/banner.html b/assets/banner.html index 9d7543f..04e979a 100644 --- a/assets/banner.html +++ b/assets/banner.html @@ -3,7 +3,7 @@ -engram banner +engramx v3.0 "Spine" — banner + + + +
+ + +
+
+
+
engram
+
+ + +
+ + engram +
+ +
+ 01 / 04 +
+ + + +
+ scene 01 · without engram + +
+
+ + Read · src/auth.ts + 5,400 +
+
+ + Read · src/auth.ts (again) + +5,400 +
+
+ + Read · src/auth.ts (again) + +5,400 +
+
+ + Read · src/auth.ts (again) + +5,400 +
+
+ +
+
cumulative tokens
+
5,400
+
↑ same file · 4 reads · 4× the cost
+
+ +
+ Your AI agent re-reads the same files.
+ Every session. Every time. +
+
+ + + +
+ scene 02 · 30 seconds + +
+
+ ~ · zsh + engram install +
+
+ $npm install -g engramx + added engramx@2.0.2 in 4s + $cd ~/my-project + $engram init + indexed 451 nodes · 1005 edges + $engram install-hook + 7 hooks installed · hud label active + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +
+
+ +
+ Three commands. No accounts. No cloud. +
+
+ + + +
+ scene 03 · with engram + +
+
+
// agent
+
+ Read('src/auth.ts')
+ requesting source… +
+
+
+ + + + +
+
+
// engram sentinel
+
PreToolUse · intercepted
+
+ graph query · 8 providers
+ packing context packet…
+ deny + reason +
+
+
+ + + + +
+
+
// agent receives
+
+ structure · decisions · git ·
+ mistakes · library docs
+ ~500 tokens vs 5,400
+ ↓ 11× +
+
+
+ +
+ Hooks at the boundary. Returns a context packet, not the file. +
+
+ + + +
+ scene 04 · result · session totals + +
+
+ tokens saved + 88.1% + ↓ 86.0K saved · this session +
+
+ cost saved · $3/M + $0.26 + ↓ vs raw-Read baseline +
+
+ graph health + 451 / 1005 + nodes / edges · 96% extracted +
+
+ +
+ + mistake memory · auth.ts: don't add NOT NULL without backfill (caught 2026-03-04) +
+ +
+ 88.1% measured savings. $0 cloud. Persistent memory. +
+
+ +
+ + + + + + diff --git a/docs/demos/hf/meta.json b/docs/demos/hf/meta.json new file mode 100644 index 0000000..16d24ed --- /dev/null +++ b/docs/demos/hf/meta.json @@ -0,0 +1,5 @@ +{ + "id": "hf", + "name": "hf", + "createdAt": "2026-04-19T13:25:40.331Z" +} \ No newline at end of file diff --git a/docs/demos/poster.svg b/docs/demos/poster.svg new file mode 100644 index 0000000..c2903f3 --- /dev/null +++ b/docs/demos/poster.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + AI CODING MEMORY · v2.0.2 + + + + engram + + + + Your AI coding assistant forgets everything. + + + Persistent memory that learns from every session. + + + + + + $ + npm install -g + engramx + + + 451 nodes · 1005 edges · 0 tokens + + + 11× fewer tokens vs relevant files + + + Your AI now has persistent memory. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ast-miner + GraphStore + session-miner + core.ts + queryGraph() + extractFile() + init() + + + + + + + + 10 languages · 0 LLM cost · 0 cloud · works with Claude Code · Cursor · Codex · aider + + + + + + + PLAY · 24S + + diff --git a/docs/demos/scene-table.md b/docs/demos/scene-table.md new file mode 100644 index 0000000..dd0aeed --- /dev/null +++ b/docs/demos/scene-table.md @@ -0,0 +1,100 @@ +# engram — Showcase Scene Table + +> Source-of-truth scene composition for the engram product showcase. +> Drives `showcase.html` (Hyperframes scenes), `captions.vtt`, `chapters.vtt`, and the rendered MP4. +> **Total runtime: 24s.** All scene durations are budgets, not floors — keep them tight. + +--- + +## Composition + +| # | Beat | Duration | Visual | Caption | +|---|---|---|---|---| +| 0 | Poster | static | engram wordmark on dot grid + graph constellation | "engram — your AI agent forgets everything. Fix it in 30s." | +| 1 | Context (Problem) | 0–5s | Claude Code session: agent re-reads `auth.ts` for the 4th time. Token counter ticks: 5,400 → 10,800 → 16,200 → 21,600. Red diff strikethrough on identical re-reads. | "Your AI agent re-reads the same files. Every session. Every time." | +| 2 | Action (Install) | 5–11s | Terminal types `npm install -g engramx` → `engram init` → `engram install-hook`. Output streams: 451 nodes, 7 hooks installed. Amber ✓ checks land in sequence. | "Three commands. No accounts. No cloud." | +| 3 | Action (Intercept) | 11–18s | Same Claude session: agent calls `Read(auth.ts)`. PreToolUse hook fires (amber pulse). Context packet (~500 tokens) replaces raw file. Token counter ticks down: 21,600 → 2,400. | "Hooks at the boundary. Returns a context packet, not the file." | +| 4 | Payoff (Results) | 18–24s | Dashboard tab: 88.1% saved · $0.26 saved · 451 nodes · 1005 edges. Mistake memory ⚠ chip surfaces a prior bug. | "88.1% measured savings. $0 cloud. Persistent memory." | + +--- + +## Scene production rules + +- Every scene opens on a **single visible interaction** — one mouse hover, one keypress, one packet. +- Caption text is shown **baked into the video** (lower-third, JetBrains Mono, amber accent on key terms) AND exposed via WebVTT for accessibility. +- Transitions between scenes: **400ms clip-path wipe** from left edge, amber-tinted seam. +- No audio in the default delivery. Optional ambient track only on the long-form 60s tutorial. +- All numbers shown are real numbers from the v2.0.2 release, not placeholders. + +--- + +## Branded cursor + +The video uses a custom **24×24 SVG cursor** in amber (`#f59e0b`), drawn as a filled arrow with 1px black outline. Real OS cursors look amateur in a recorded scene. The cursor fades to 30% opacity when not actively pointing. + +--- + +## Captions VTT (canonical) + +The captions file at `./captions.vtt` is generated **from this table**. If a scene caption changes, regenerate the VTT. Do not edit the VTT by hand and let the table drift. + +Cue format: each scene becomes one cue spanning its duration window. + +--- + +## Chapters VTT + +Cue 1 (0:00–0:05) — `Problem` +Cue 2 (0:05–0:11) — `Install` +Cue 3 (0:11–0:18) — `Intercept` +Cue 4 (0:18–0:24) — `Result` + +Used by the live HTML player's chapter scrubber and by the social-platform "skip to" labels. + +--- + +## Reduced-motion storyboard fallback + +When `prefers-reduced-motion: reduce`, the live player swaps for a 4-frame storyboard. Each frame is the **strongest single still** of its scene plus the caption. Ordered identically to the table above. + +Frames live at: +- `./storyboard/01-problem.svg` +- `./storyboard/02-install.svg` +- `./storyboard/03-intercept.svg` +- `./storyboard/04-payoff.svg` + +A reduced-motion visitor gets the same information, just static. WCAG-compliant. + +--- + +## Asset deliverables + +| Asset | Path | Format | Notes | +|---|---|---|---| +| Live HTML player | `./showcase.html` | HTML | Self-contained, opens in browser, scrubbable | +| Hyperframes scenes | `./showcase.html` (same file, scene divs) | HTML | Render input for the MP4 | +| Captions | `./captions.vtt` | WebVTT | Generated from this table | +| Chapters | `./chapters.vtt` | WebVTT | Generated from this table | +| Poster | `./poster.svg` | SVG | First-frame, used in `