Releases: veronchenko/inkwell-memory
Releases · veronchenko/inkwell-memory
Release list
v0.14.0 — Inkwell (formerly Engram)
Breaking: the project is renamed from Engram to Inkwell. "Engram" collides with 10+ unrelated memory-MCP servers on GitHub, so search and AI-recommendation traffic for the name scattered across all of them. Nothing about the storage format or the tool surface changed — entry files, frontmatter, kb:// links and the eight MCP tool names (remember, recall, search, list, tags, forget, rebuild, doctor) are untouched. Everything around them moved, with no compatibility shims:
- env vars
ENGRAM_*→INKWELL_* - default knowledge base
~/.engram/knowledge→~/.inkwell/knowledge - Docker image
foreigndmitryi/engram→foreigndmitryi/inkwell-memory(Docker Hub cannot rename a repository; the old one stays published but is no longer updated) - MCP server id registered by
scripts/install.*engram→inkwell, so agent-facing tool names becomemcp__inkwell__* - plugin
engram-hooks→inkwell-hooks(bumped to 2.0.0 — its hook matchers follow the tool-name change),engram-pi→inkwell-pi, subagentengram-project-onboarder→inkwell-project-onboarder,ENGRAM_SPEC.md/ENGRAM_TEMPLATES.md→INKWELL_SPEC.md/INKWELL_TEMPLATES.md - Python distribution
engram→inkwell-memory, console scriptengram→inkwell - search index filename
<data-path>/index/engram.db→inkwell.db. The index is a rebuildable cache, so an existing deployment simply re-indexes and re-embeds on first start; the old file can be deleted - repository moved to
github.com/veronchenko/inkwell-memory(GitHub redirects the old URL); the docs site moved toveronchenko.github.io/inkwell-memory
To upgrade an existing install: rename the env vars, move ~/.engram/knowledge to ~/.inkwell/knowledge, re-register the MCP server under the new id, and reinstall the plugin.
v0.13.0
- feat: usage-analytics
query_log— everysearch/recall/remembercall is now recorded (session id, tool, query text, returned/top result ids, hit, latency) in a new SQLite table, separate from the existingENGRAM_QUERY_LOGJSONL trace. A newGET /api/analyticsendpoint and dashboard panel surface read/write ratio, hit rate, zero-hit queries (verbatim), click-through rate, searches-per-recall, average recall rank, hit distribution by entry type, dead entries, and sessions touching Engram - feat: client-side cost/token tracking —
engram_cost_tracker.py, a newPostToolUsehook in theengram-hooksplugin, accumulatestotal_cost_usd/usage.input_tokens/usage.output_tokensper session (local-only, not joined againstquery_log, not shown in the statusline) - chore: migrated the MCP server from
mcp.server.fastmcpto the standalonefastmcppackage — the installedmcpSDK'sContexthas nosession_id, needed for the analytics work above; bumpsfastapi/uvicornto versions compatible withfastmcp'sstarletterequirement
v0.12.1
Changelog
0.12.1
- fix:
search'sentry_typefilter is validated against the schema enum (was a plainstr, so an unknown/misspelled type silently matched nothing instead of being rejected client-side, unlikeremember) - docs:
search/remember/listtool descriptions forentry_type/part_ofno longer assume the packaged schema's type names (hub,diagnostic,decision) — a replacedschema.jsonneed not have any of them
0.12.0
- feat:
recallgainshops=2— walk one more level of graph relations in the same direction, tagging hop-2 items withvia(the hop-1 id they were reached through) instead of resolving a title, since a hop-2 item is a navigation breadcrumb, not read content - feat:
searchfuses a third RRF channel —_exact_match_search, an IDF-weighted literal title/tag token match. BM25 and embeddings both dilute a proper noun among lexically-similar distractors on a larger corpus; this channel recovers it by literal substring match, weighted so a rare token counts more than one shared by dozens of entries, and abstains belowMIN_EXACT_DISCRIMINATING_TOKENSmatching tokens rather than let SQL row order decide ties. MRR improved 0.851 → 0.857 and recall@5 improved 0.851 → 0.869, with no regression on any language slice - feat:
searchresults drop the volatileaccess_count/last_accessed/stalenessfields — display-only, drift with wall-clock time on every call — so identical repeated searches stay byte-identical for prompt-cache reuse; still exposed viarecall/doctor - refactor:
ENGRAM_*CLI/env resolution (duplicated betweenserver.pyanddashboard/__main__.py) and tuning constants (write-gate/staleness thresholds, RRF/exact-match knobs, pagination/duplicate-detection defaults — previously scattered acrosssearch_backend.py/database.py, including a cross-import between them just to share two of them) consolidated intosrc/config.py. No behavior change — same env var names, same defaults - docs: README documents the exact-match channel and
hops=2, and adds a comparison against the same content packaged as a conventional Markdown wiki — Engram answers with fewer tool calls, less total context, and less wall time for equivalent fact coverage
0.11.1
- fix: dashboard
/api/graphnow includespart_ofmembership as edges — after thepart_ofmigration (kb:// hub back-links replaced by the structural frontmatter field), members whose only connection was a stripped back-link rendered as isolated nodes.KnowledgeBase.get_graph()adds apart_of/part_of-typed edge per membership, skipping any hub already reachable via a keptkb://link (e.g.patternentries)
0.11.0
- feat: entry taxonomy moves into
schema.json— per-type rules (required frontmatter, template body fields,part_ofmembership, usage-boost/digest behavior) are data, not Python. A generatedentry_typeenum enforces it client-side onremember, and a newdoctorMCP tool audits every entry against it (dangling/supersededkb://links, undeclared types, missing fields, supernodes, tag/type collisions).part_ofadds structural membership from a detail entry to its hub, filterable onsearch/listand grouped in a hub'srecalldigest - feat: BM25 now retries with OR when an implicit-AND match returns nothing; retrieval-ranking quality (hit@k/recall@k/MRR) is now tracked internally, and optional
ENGRAM_QUERY_LOGtracessearch/recallcalls to JSONL to support it - fix: hub entries no longer skew search ranking from their own read count; the schema's
edgeslist is now actually enforced; the write gate checks 20 candidates instead of 4; a tz-naivelast_accessedno longer crashessearch;resourcesurvives an update that omits it; search hits no longer inflateaccess_count(onlyrecalldoes) - Breaking:
rebuild'sschema_warningskinds now come from thedoctorreport (malformed_resourcedropped,missing_type→type_outside_schema)
0.10.0
- feat: web dashboard (
src/dashboard/) — FastAPI REST CRUD +/api/graphover the sameKnowledgeBase/SQLiteBackendthe MCP tools use, served with a single staticindex.html(vanilla JS force-directed canvas graph, no build step/CDN); disabled by default, enabled viaENGRAM_ENABLE_DASHBOARD, runs as a second process alongsideserver.pyin the same container (docker-entrypoint.sh) - feat: bi-temporal entry versioning —
remember(..., supersede=True)creates a new version instead of overwriting in place;search/listhide superseded entries by default (include_superseded=Trueto see history) - feat:
searchgains anentry_typefilter (exact match), also exposed on the dashboard's/api/search - feat:
remembersuggestskb://links — returnssuggested_links(near-duplicate/related entries by embedding similarity) for the caller to cross-reference, never auto-added - feat: Claude Code hooks plugin (
hooks/) —SessionStart/Stop/SessionEndhandlers that nudge the agent to search Engram before starting work and toremembernon-trivial changes before finishing; includes aPreToolUsegate requiring a search/recall beforerememberin the same session - fix: Windows
os.renamefailing when overwriting an existing entry file — replaced with an OS-safe replace - fix: container now exits when either the MCP backend or the dashboard process dies, instead of hanging
- fix: backgrounding the MCP backend behind the dashboard process preserved real stdin so a stdio MCP client's input still reaches it
0.9.0
- feat:
searchis now hybrid — SQLite FTS5 (BM25) fused with cosine similarity over local Model2Vec embeddings (minishlab/potion-multilingual-128M) via Reciprocal Rank Fusion, so queries that share no literal words with an entry can still find it by meaning - Entries store an
embeddingBLOB column (migrated in place on existing indexes); computed onrememberand batch-computed onrebuild - New
--embedding-model/ENGRAM_EMBEDDING_MODELoption (defaultminishlab/potion-multilingual-128M) - Degrades gracefully to keyword-only search if the embedding model can't load (no network on first run)
Dockerfilegains a dedicated build stage so the production image only ships runtime code; also pre-downloads the embedding model so it works with no network access at runtime
0.8.0
- Breaking: removed the pluggable backend abstraction and the Xapian backend — SQLite FTS5 (Porter stemming, BM25 ranking) is now the only search backend
- Breaking: removed
--backend/ENGRAM_BACKENDand--language/ENGRAM_LANGUAGECLI/env options - Breaking: default index path changed from
<data-path>/index/<backend>/to<data-path>/index/engram.db— runrebuildafter upgrading to reindex src/backend/(bothxapian/andsqlite/subpackages plus theSearchBackendABC) replaced by a singlesrc/search_backend.pymodule- Reason: two backends doing the same job (keyword full-text search) didn't justify an
importlib-based plugin system; simplifies the codebase ahead of adding real search-strategy diversity (e.g. a hybrid semantic backend)
0.7.0
- feat: entries support optional
type,resourcefrontmatter fields - feat:
rememberacceptsentry_type,resourceparams to set them - feat:
search/list/recallsurfacetypein results - feat:
typeis filterable in the Xapian backend (type:prefix); indexed as a boolean term in both backends - feat:
rebuildnow returns schema conformance warnings (missing type, malformed resource) - Backward compatible: existing entries without new fields continue to work unchanged
0.6.0
- feat:
rememberdocstring enforces one decision per article with optional justification - feat: structural warnings added — Markdown headers detection, paragraph count > 3
- feat: size thresholds lowered to 512 B (soft warning) / 1 KB (hard warning)
0.5.2
- Docs: reinforced "zero discoverable information" principle in README.md, CLAUDE.md, and
remembertool docstring (server.py) - Docs: stripped technical documentation from CLAUDE.md (9256bd7)
0.5.1
- Added content policy to
remembertool docstring (size limits, article structure guidelines) - Docs: renamed all "KB" references to "Engram" / "knowledge base" across README and CLAUDE.md
0.5.0
recallnow returnssize(bytes) andlast_modified(date) fieldsremembernow returnssize(bytes) and awarningslist when article content exceeds 2 KB (soft) or 4 KB (hard) thresholds- Added 4 usage examples to README (store, search, graph, multi-agent)
- Added "Prompt Your Agent" section to README with system prompt template
0.4.2
- README rewritten for v0.4.0 (Docker-only development, cleaner transport blocks, Custom Backend section with SearchBackend ABC + Whoosh example)
0.4.1
- Removed Whoosh backend (server-side coverage increased, deps simplified)
- Removed
--log-fileoption — logs always go to stderr (docker logs) - Added CI coverage report with 80% minimum threshold
- Fixed tool descriptions: "configurable stemming" instead of "French stemming"
0.4.0
- Pluggable search backends:
xapian(default),sqlite(FTS5),whoosh(pure Python) - Backend loaded dynamically via
importlib— anybackend/<name>/main.pyworks - All CLI options have
ENGRAM_*environment variable fallbacks ENGRAM_*env vars baked into Docker image as defaults- Source code moved to
src/directory
0.3.0
- Metadata cache (
_meta_cache) inKnowledgeBase— powerslist,tags,find_similar - Security: path traversal protection (UUID regex), limit clamping, atomic file writes, non-root Docker user
- Best practice guidance added to
remembertool description - GitHub mirror excludes
ci/andCLAUDE.md
0.2.0
- Renamed project to Engram
- Consolidated tools to 7: remember (upsert), recall, se...
v0.12.0
0.12.0
- feat:
recallgainshops=2— walk one more level of graph relations in the same direction, tagging hop-2 items withvia(the hop-1 id they were reached through) instead of resolving a title, since a hop-2 item is a navigation breadcrumb, not read content - feat:
searchfuses a third RRF channel —_exact_match_search, an IDF-weighted literal title/tag token match. BM25 and embeddings both dilute a proper noun among lexically-similar distractors on a larger corpus; this channel recovers it by literal substring match, weighted so a rare token counts more than one shared by dozens of entries, and abstains belowMIN_EXACT_DISCRIMINATING_TOKENSmatching tokens rather than let SQL row order decide ties. MRR improved 0.851 → 0.857 and recall@5 improved 0.851 → 0.869, with no regression on any language slice - feat:
searchresults drop the volatileaccess_count/last_accessed/stalenessfields — display-only, drift with wall-clock time on every call — so identical repeated searches stay byte-identical for prompt-cache reuse; still exposed viarecall/doctor - refactor:
ENGRAM_*CLI/env resolution (duplicated betweenserver.pyanddashboard/__main__.py) and tuning constants (write-gate/staleness thresholds, RRF/exact-match knobs, pagination/duplicate-detection defaults — previously scattered acrosssearch_backend.py/database.py, including a cross-import between them just to share two of them) consolidated intosrc/config.py. No behavior change — same env var names, same defaults - docs: README documents the exact-match channel and
hops=2, and adds a comparison against the same content packaged as a conventional Markdown wiki — Engram answers with fewer tool calls, less total context, and less wall time for equivalent fact coverage
0.11.1
- fix: dashboard
/api/graphnow includespart_ofmembership as edges — after thepart_ofmigration (kb:// hub back-links replaced by the structural frontmatter field), members whose only connection was a stripped back-link rendered as isolated nodes.KnowledgeBase.get_graph()adds apart_of/part_of-typed edge per membership, skipping any hub already reachable via a keptkb://link (e.g.patternentries)
0.11.0
- feat: entry taxonomy moves into
schema.json— per-type rules (required frontmatter, template body fields,part_ofmembership, usage-boost/digest behavior) are data, not Python. A generatedentry_typeenum enforces it client-side onremember, and a newdoctorMCP tool audits every entry against it (dangling/supersededkb://links, undeclared types, missing fields, supernodes, tag/type collisions).part_ofadds structural membership from a detail entry to its hub, filterable onsearch/listand grouped in a hub'srecalldigest - feat: BM25 now retries with OR when an implicit-AND match returns nothing; retrieval-ranking quality (hit@k/recall@k/MRR) is now tracked internally, and optional
ENGRAM_QUERY_LOGtracessearch/recallcalls to JSONL to support it - fix: hub entries no longer skew search ranking from their own read count; the schema's
edgeslist is now actually enforced; the write gate checks 20 candidates instead of 4; a tz-naivelast_accessedno longer crashessearch;resourcesurvives an update that omits it; search hits no longer inflateaccess_count(onlyrecalldoes) - Breaking:
rebuild'sschema_warningskinds now come from thedoctorreport (malformed_resourcedropped,missing_type→type_outside_schema)
Docker: docker pull foreigndmitryi/engram:0.12.0 (also tagged :latest)
v0.10.0
- feat: web dashboard (
src/dashboard/) — FastAPI REST CRUD +/api/graphover the sameKnowledgeBase/SQLiteBackendthe MCP tools use, served with a single staticindex.html(vanilla JS force-directed canvas graph, no build step/CDN); disabled by default, enabled viaENGRAM_ENABLE_DASHBOARD, runs as a second process alongsideserver.pyin the same container (docker-entrypoint.sh) - feat: bi-temporal entry versioning —
remember(..., supersede=True)creates a new version instead of overwriting in place;search/listhide superseded entries by default (include_superseded=Trueto see history) - feat:
searchgains anentry_typefilter (exact match), also exposed on the dashboard's/api/search - feat:
remembersuggestskb://links — returnssuggested_links(near-duplicate/related entries by embedding similarity) for the caller to cross-reference, never auto-added - feat: Claude Code hooks plugin (
hooks/) —SessionStart/Stop/SessionEndhandlers that nudge the agent to search Engram before starting work and toremembernon-trivial changes before finishing; includes aPreToolUsegate requiring a search/recall beforerememberin the same session - fix: Windows
os.renamefailing when overwriting an existing entry file — replaced with an OS-safe replace - fix: container now exits when either the MCP backend or the dashboard process dies, instead of hanging
- fix: backgrounding the MCP backend behind the dashboard process preserved real stdin so a stdio MCP client's input still reaches it