engmem
Personal engineering memory for AI-assisted development, built around two things most memory tools do not do.
A story is the unit, and the store lives outside every repository. One engineering story spans several repos and several sessions — a front end, a back end, a third service, across days. Per-repo memory files cannot hold it, and a pile of context-free facts cannot reconstruct it.
It measures whether remembering actually changed anything. Every session pre-registers
its intent before searching, and closes with a Reuse Log row quoting, verbatim, the prior
document that changed a decision. tools/verify_citations.py checks those quotes against
the documents they cite. The point is not to accumulate documents; it is to find out
whether accumulated documents pay for themselves.
Underneath: markdown files in a local git-tracked store, deterministic search, two runtime dependencies, no database, no server, no network calls.
Anatomy of engmem walks one task end to end — the command
run at each step, the real output it returns, and the call path through the code. It is a
standalone HTML page: open it from a checkout, since GitHub serves .html as source.
The loop
Everything else in this README is plumbing that exists so this loop can run.
1. Pre-register. /engmem <task> writes a two-line naive plan before it searches
anything — obtained from a sub-agent that knows only the task, so the baseline is not
contaminated by what the store already told you. It never asks you for it and never waits
on it.
2. Search, on the record. engmem search is a bounded channel, not a better grep: its
output is capped at 4 KB and every call writes a row to telemetry.jsonl — the query, what
surfaced, hit or miss, bytes of context spent. An agent grepping around freely may well
find the same document; what it cannot do is leave a measurable trace, or promise the
context it pulls in has any ceiling at all.
3. Work.
4. Record what was actually reused. /engmem.save closes the session with a Reuse Log:
one row per prior document that changed a decision, each carrying a verbatim quote from it.
A row without a quote is invalid. If nothing was reused, the section says exactly
Prior docs used: none. — the most useful answer the experiment can get, and the easiest
to quietly avoid writing.
5. Judge. tools/gate1_report.py collects every Reuse Log row into one table and marks
each citation distant or adjacent by the rule pre-registered in ENGMEM-SPEC.md §11.
Whether it genuinely changed a decision is a human column, filled in by hand.
What this is not
- Not a vector database. No embeddings, no index file, no second source of truth.
- Not another memory bank. Those are per-repository and per-agent; a story here spans repositories and outlives the session that wrote it.
- Not a search engine competing with grep. The engine is the sensor: bounded output so the cost is known, logged calls so the retrieval can be audited afterwards.
Install
From a source checkout:
uv tool install --editable . # or: pipx install .
Then wire it into your AI coding agent:
engmem install --agent claude # templates -> ~/.claude/commands/ (Claude Code)
engmem install --agent claude --local # templates -> ./.claude/commands/ (this repo only)
engmem install --agent copilot-ide # templates -> ./.github/prompts/ (Copilot's IDE plugin)
engmem install --agent copilot-cli # skills -> ~/.copilot/skills/ (Copilot CLI)
engmem install --agent claude-desktop # MCP server entry (Claude Desktop)
Pick copilot-ide if you use the Copilot chat panel in VS Code / Visual Studio /
JetBrains; pick copilot-cli if you use the standalone copilot CLI, which reads
skills instead of prompt files. Pick claude-desktop if you use the desktop
app, which cannot run shell commands — it reaches engmem over MCP instead, and the
same commands arrive as prompts. copilot-ide and --local must be run from a repo
root (a directory containing .git) — they refuse to run anywhere else.
install is idempotent — re-running it upgrades templates in place and never duplicates
the trigger rule or touches existing store content.
To remove the wiring again, mirror it with the same --agent:
engmem uninstall --agent claude # or copilot-ide / copilot-cli, plus --local
uninstall deletes the templates it installed and the trigger rule it appended, reports
the counts, and never touches the store — those are your documents, and they stay
readable as plain markdown without the tool. It prints the store path so you can remove
it yourself if you want to. Running it twice is safe.
The store location resolves in this order: --store PATH → $ENGMEM_HOME →
~/Developer/engmem. It holds sessions/*.md (the documents) and telemetry.jsonl
(append-only search log). No config files.
Usage
The daily loop runs through three agent slash commands installed above:
/engmem <task>— start a task: records your intended approach (pre-reg) before searching, creates a draft session document, searches the store for relevant prior work, and reports what it found before proposing any plan./engmem.save— finish a task: drafts the full document metadata from the diff and conversation for one-round approval, fills in decisions, rejected alternatives, lessons learned, and a Reuse Log of which prior documents actually influenced the work./engmem.save.quick— save without the review round: no YAML check, no quote check, no supersede question; a singleokproduces a minimal but valid document.
Direct search from the shell:
engmem search "SomeController"
engmem search "XYZ" --store /path/to/store
Output is a pasteable top-3 (id, path, score, why-matched, cold-start primer excerpt,
related docs, matched section locators) capped at 4 KB, with a footer scoreboard:
docs: N | drafts: N | last doc: Nd ago. No match prints prior context: none found
(exit 0). Ambiguous short queries (e.g. MQ matching both MessageQueue and
MetricsQuery) return one representative per cluster, marked ambiguous.
Ask for one section rather than whole documents:
engmem search "cache eviction" --role decisions # what was decided, and what was rejected
engmem roles # the 19 role names it understands
Word matching cannot answer "what did we reject and why" — those words appear nowhere in the answer. Role addressing does, by resolving section headings across their spelling variants, and it returns the section instead of the document: a few hundred bytes rather than tens of kilobytes.
Two more commands:
engmem backfill --all # propose front matter for documents written before engmem
engmem telemetry # searches run, hit rate, context spent, split by channel
backfill never writes without showing the proposal first, leaves the document body
byte-identical, and is idempotent.
What a document looks like
Plain markdown with a YAML header — readable, and greppable, without this tool:
---
id: 1000001-widget-cache
title: Widget cache eviction
date: 2026-08-24
status: active
tags: [platform, caching]
entities: [WidgetCache, CacheWarmer]
related: [ttl-revalidation-v2]
covers_files: [WidgetCache.java]
---
## Pre-reg
## 1. Executive Summary
...
## 8. Decision Log
## 13. Future LLM Context (cold-start primer)
## 16. Reuse Log
## Search Trace
/engmem.save writes nineteen sections; /engmem.save.quick writes five. Every claim
carries [Verified], [Assumed], or [Open], so the document says what it does not
know instead of staying silent about it.
No field is required. A document with missing or partial front matter still loads, and what is missing is named on stdout — engmem never hides a document from you because its metadata was incomplete.
Development
uv sync --group dev
uv run pytest -q
Python ≥3.11. Runtime dependencies: pyyaml and markdown-it-py, and nothing else
(hard constraint — see ENGMEM-SPEC.md §2). Search correctness is defined by the golden fixture tests in
tests/test_scoring.py / tests/test_cli.py; at any conflict between the scoring
formula and a golden test, the test wins.
What engmem touches on your machine
No network. No telemetry upload, no model calls, no fetching at runtime. Search,
ranking, and storage are entirely local. Two runtime dependencies, pyyaml and
markdown-it-py; neither opens a socket.
Your store is private. engmem reads and writes markdown under a directory you choose. That store commonly holds notes about proprietary code — it lives outside this repository and should stay that way. There is no encryption at rest; protect it the way you protect the source it describes.
Writes stay inside sessions/. The MCP write tools resolve every path first and
compare after, so .. segments, absolute paths, symlinks pointing out of the store, and
ids containing separators or NUL bytes are refused. Writes stage to a temporary file,
re-validate, then os.replace, so a crash mid-write cannot leave half a document.
The cache is JSON, never pickle. Token counts live under ~/.cache/engmem/, which any
process running as you can write to. Unpickling from there would execute whatever it
contained; JSON cannot. A corrupted entry degrades to a cache miss.
Installing touches known paths only. engmem install writes templates into the agent
directory you name and, for claude-desktop, adds one key to that app's config. engmem uninstall removes exactly what it added and never touches the store. The two files engmem
edits but does not own — your instructions file and that config, which holds every other
MCP server you configured — are replaced atomically, through any symlink rather than over
it, so a failed write leaves them exactly as they were.
One thing to know: engmem search prints matched document text to stdout. In a shared
terminal or a logged CI job, that text goes wherever the output goes.
Contributing
The engineering principles this codebase is held to are ENGMEM-SPEC.md §10. The short
version: tests first and never weakened, standard library over dependencies, errors loud
on stdout, and examples in tests and docs invented rather than taken from real work.
License
MIT © Alexander Shakhov
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file engmem-0.1.1.tar.gz.
File metadata
- Download URL: engmem-0.1.1.tar.gz
- Upload date:
- Size: 396.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba875cdb675fb56b81dd64c83c01f0cd628c48da654d973376f2ff965fce4d38
|
|
| MD5 |
e3813e09008adff40e80bcb371bf915f
|
|
| BLAKE2b-256 |
024e52aaa0580eba240093464d42b49ee4274d3484350bc219922d58f5aea755
|
Provenance
The following attestation bundles were made for engmem-0.1.1.tar.gz:
Publisher:
release.yml on AlejandroKolio/engmem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
engmem-0.1.1.tar.gz -
Subject digest:
ba875cdb675fb56b81dd64c83c01f0cd628c48da654d973376f2ff965fce4d38 - Sigstore transparency entry: 2793956058
- Sigstore integration time:
-
Permalink:
AlejandroKolio/engmem@01b60546d33195bb0acd4bba6c272c488b2ec752 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/AlejandroKolio
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@01b60546d33195bb0acd4bba6c272c488b2ec752 -
Trigger Event:
push
-
Statement type:
File details
Details for the file engmem-0.1.1-py3-none-any.whl.
File metadata
- Download URL: engmem-0.1.1-py3-none-any.whl
- Upload date:
- Size: 99.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2fc1aaae1f7ba980f727f687d5a6a4a033b45225d9059b0ef877be0143c55854
|
|
| MD5 |
f029f6f77231d1e07b5b91dac339d321
|
|
| BLAKE2b-256 |
49ea736e52d0e92d76b39d2c4312794a26f2cdde90e721b603425ef0605ab034
|
Provenance
The following attestation bundles were made for engmem-0.1.1-py3-none-any.whl:
Publisher:
release.yml on AlejandroKolio/engmem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
engmem-0.1.1-py3-none-any.whl -
Subject digest:
2fc1aaae1f7ba980f727f687d5a6a4a033b45225d9059b0ef877be0143c55854 - Sigstore transparency entry: 2793956139
- Sigstore integration time:
-
Permalink:
AlejandroKolio/engmem@01b60546d33195bb0acd4bba6c272c488b2ec752 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/AlejandroKolio
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@01b60546d33195bb0acd4bba6c272c488b2ec752 -
Trigger Event:
push
-
Statement type: