Local-first memory for AI agents: SQLite FTS5, deterministic recall, no vector DB, no cloud.
SaferSkills independently audited Memory Kernel (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<img width="1024" height="1024" alt="image" src="https://github.com/user-attachments/assets/f13a8ef3-23bb-4801-a5a4-05eeaa4f0041" />
<!-- mcp-name: io.github.Artem362/memory-kernel -->
Memory Kernel is a small local memory layer for AI agents.
It helps you save useful things such as decisions, constraints, tasks, facts, and notes in a local SQLite database, then pull back only the few memories that matter for the current task.
Published package name on PyPI: amormorri-memory-kernel CLI command after install: memory-kernel
Practical guide in Ukrainian: docs/OPERATING_GUIDE_UK.md
Release notes: CHANGELOG.md
remember, ingestsearch, context, wake-up, statslist, show, update, deleteforget / restore, revise, decaycompletion, verifyexport, importIn plain English, Memory Kernel does 4 things:
This project is not trying to create a magical black-box memory. It is trying to create a memory layer you can inspect, control, export, and trust.
If you just want to try it, do this:
pip install amormorri-memory-kernel
memory-kernel init
memory-kernel remember --scope my.project --kind decision --title "Keep memory local" --content "We store memory on the user's machine."
memory-kernel search "memory local"
memory-kernel export --format json --output exports\memory.jsonWhat happened there:
init created a local database.remember saved one clear memory.search fetched it back.export created a backup file you can move or restore later.If you are using the repository instead of PyPI:
pip install -e .[dev]Most people will use it like this:
remember.ingest.search, context, or wake-up.show, update, or delete.import.rememberUse remember when you already know exactly what should be saved.
Good examples:
memory-kernel remember --scope project.alpha --kind decision --title "Use SQLite FTS5" --content "We use SQLite FTS5 for local retrieval."ingestUse ingest when you have raw text and want the system to split it into structured memories.
Good examples:
memory-kernel ingest --scope project.alpha --file notes.txt --source sprint-review --tags planning transcriptAdd --dry-run to preview the segments and inferred kinds/titles/tags without writing to the database. Useful before committing a long file.
memory-kernel ingest --scope project.alpha --file notes.txt --dry-run
memory-kernel ingest --scope project.alpha --text "..." --dry-run --jsonAdd --interactive for a guided flow that prompts for scope, source, tags, and the text itself, then shows a preview and asks for confirmation before saving. Helpful for first-time users or for ad-hoc captures from the terminal without remembering the flag names.
memory-kernel ingest --interactivesearchUse search when you want a few relevant exact memories for a query.
memory-kernel search "context budget"contextUse context when you want a compact pack for an agent prompt.
memory-kernel context "How do we keep memory cheap?" --budget-chars 700wake-upUse wake-up when you want a small "hot memory" pack before a task starts.
memory-kernel wake-up --budget-chars 500statsUse stats when you want to see database size and whether the native accelerator is active.
memory-kernel stats
memory-kernel stats --since 7d
memory-kernel stats --since 2026-04-01--since adds recent-activity counts (created and updated since the cutoff) plus a per-kind breakdown for the window. Accepts either a relative form like 7d or an ISO date.
listUse list to browse recent memories (most recently updated first) with optional filters.
memory-kernel list
memory-kernel list --scope project.alpha --limit 50
memory-kernel list --kind decision --tags rust memory
memory-kernel list --jsonDefault limit is 20. The output shows id, kind/scope, title, and the timestamps so you can pipe ids into show/update/delete.
showUse show when you have a memory id (printed by search, remember --json, or export) and want the full record.
memory-kernel show --id 9f1e8c0a4b2d4e7f8a1b2c3d4e5f6a7b
memory-kernel show --id 9f1e8c0a4b2d4e7f8a1b2c3d4e5f6a7b --jsonupdateUse update to fix specific fields on an existing memory without re-importing the whole database.
memory-kernel update --id 9f1e... --title "Renamed memory" --importance 0.95
memory-kernel update --id 9f1e... --tags rust memory acceleration
memory-kernel update --id 9f1e... --tagsOnly the fields you pass change. Pass --tags with no values to clear tags. Pass --kind, --importance, or --certainty to revise validation-bound fields.
deleteUse delete to drop a memory you saved by mistake or that no longer applies.
memory-kernel delete --id 9f1e8c0a4b2d4e7f8a1b2c3d4e5f6a7bThe command exits non-zero if the id does not exist, so wrap it in shell logic if you script around it.
forget / restoredelete removes a memory permanently. When you only want it out of recall but kept for safety, use forget — a soft-archive. Archived memories disappear from search, context, wake-up, and list, but the data stays and restore brings it back.
memory-kernel forget --id 9f1e...
memory-kernel restore --id 9f1e...
memory-kernel list --include-archived # see archived/superseded memoriesRe-saving the same memory with remember/ingest also resurrects it automatically.
reviseWhen a new memory replaces an old one, record the relationship with revise: the old memory is marked superseded (hidden from recall, kept for history with a pointer to its replacement).
memory-kernel revise --id <new-id> --supersedes <old-id>This keeps memory self-curating: stale decisions fade out of recall as newer ones take their place, instead of piling up as contradictory noise.
decaydecay applies a forgetting curve: it auto-archives memories that are old, rarely recalled, and low-value, so the store and your recall stay lean over time. Each memory has a retention score built from its importance, how often it has been recalled (reinforcement), and how long since it was last seen (time decay).
memory-kernel decay --dry-run # preview what would fade
memory-kernel decay # apply (archives, recoverable)
memory-kernel decay --min-age-days 60 --max-access 0 --scope project.alphaOnly note and fact memories are eligible — decision, constraint, task, and preference are never decayed. Archiving is the soft, recoverable kind, so restore and list --include-archived still reach faded memories. This is the heart of the project's thesis: spend the budget on what matters, let trivia fade.
completionUse completion to print a shell completion script for memory-kernel. The script is generated dynamically from the current parser, so it stays in sync as commands are added.
memory-kernel completion powershell | Out-File -Encoding utf8 $PROFILE.CurrentUserAllHosts -Append
memory-kernel completion bash > ~/.local/share/bash-completion/completions/memory-kernelAfter installing, memory-kernel <Tab><Tab> shows all subcommands; memory-kernel remember --<Tab> lists flags for that command; memory-kernel remember --kind <Tab> cycles through valid kind values.
verifyUse verify to check that the database is internally consistent: schema version is current, derived columns (stems_text, fingerprint) match the source content, and the FTS5 index row count matches the memories table.
memory-kernel verify
memory-kernel verify --repair
memory-kernel verify --repair --jsonWithout --repair, exit code is 0 when healthy and 1 when issues are found. With --repair, mismatches are recomputed in-place and the FTS index is rebuilt if its row count drifted; exit code is 0 if everything was fixed.
Useful after restoring from a manual backup, after editing the database with raw SQL, or as a periodic sanity check in CI.
exportUse export for backup, migration, or inspection.
memory-kernel export --format json --output exports\memory.json
memory-kernel export --scope project.alpha --format jsonl --output exports\project-alpha.jsonlimportUse import to restore a previous export.
memory-kernel import --file exports\memory.json
memory-kernel import --file exports\project-alpha.jsonlimport is idempotent for the same exported records because it upserts by memory id.
Memory Kernel ships an MCP server so an LLM can save and recall memories itself during a session. It works with Claude Desktop, Claude Code, Cursor, and any other MCP client, over stdio.
Install with the MCP extra:
pip install "amormorri-memory-kernel[mcp]"Run it directly to check it starts:
memory-kernel-mcp --db .memory-kernel\memory.db
# or via the main CLI:
memory-kernel serve-mcp --db-path .memory-kernel\memory.dbThen register it with your client. For Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"memory-kernel": {
"command": "memory-kernel-mcp",
"env": { "MEMORY_KERNEL_DB": "C:\\Users\\you\\.memory-kernel\\memory.db" }
}
}
}For Claude Code / Cursor (.mcp.json in the project root):
{
"mcpServers": {
"memory-kernel": {
"command": "memory-kernel-mcp",
"args": ["--db", "${workspaceFolder}/.memory-kernel/memory.db"]
}
}
}The server exposes seven tools:
| Tool | Purpose | Read-only |
|---|---|---|
memory_remember | Save one precise memory | no (dedup-merge, non-destructive) |
memory_ingest | Split raw text into structured memories | no |
memory_forget | Soft-archive a memory (recoverable) | no (reversible) |
memory_search | Find relevant memories (Ukrainian forms bridged) | yes |
memory_build_context | Budget-limited context pack for a prompt | yes |
memory_wake_up | Hot-memory pack for session start | yes |
memory_list | Browse recent memories | yes |
memory_stats | Store statistics | yes |
memory_forget is exposed because it is reversible — an agent can let a stale memory fade, and a human can restore it from the CLI. Truly destructive edits (delete, update, revise) are deliberately not exposed over MCP: an agent can add, recall, and soft-forget, but only you can permanently rewrite or remove.
Tools take flat parameters, so the model sees scope, kind, title, … directly. Verify the whole protocol round-trip any time with python scripts/mcp_smoke.py, and see docs/REAL_AI_TEST.md for a hand-test script to run on a real model.
The core idea is simple:
SQLite and FTS5.That is how Memory Kernel reduces both blur and overhead.
flowchart TD
A[Raw input: note, transcript, command] --> B{Entry mode}
B -->|remember| C[One validated memory]
B -->|ingest| D[Split into memory candidates]
D --> E[Infer kind, title, summary, tags, importance, certainty]
E --> F[Duplicate-aware upsert]
C --> F
F --> G[(SQLite + FTS5)]
G --> H[Search candidates]
H --> I[Deterministic ranking]
I --> J[Top memories]
J --> K[Context pack with hard size limit]
K --> L[LLM or AI agent]flowchart LR
U[User or Agent] --> CLI[CLI or Python API]
CLI --> STORE[MemoryStore]
STORE --> DB[(SQLite + FTS5)]
STORE --> ACCEL[Optional Rust accelerator]
STORE --> PACK[Context pack builder]
PACK --> MODEL[LLM]MemoryRecord
|- scope
|- kind
|- title
|- summary
|- content
|- tags
|- source
|- importance
|- certainty
|- access_count
|- created_at
|- updated_at
\- last_accessed_atWhen building a context or wake-up pack, Memory Kernel skips a memory whose content closely overlaps one already included (token-overlap above a threshold). Under the same character budget, the pack then carries more distinct facts and less repetition — directly lowering the redundant context handed to the model. Tune or disable per call with dedup_threshold (1.0 disables).
Search bridges Ukrainian morphology in two layers:
вирішили → виріш*). This finds вирішили, вирішення, вирішує, вирішена — anything sharing the same prefix.stems_text column inside the FTS5 index. The query also matches against deep stems exactly (stems_text:ріш). This bridges across different prefixes, so a search for рішення also finds вирішили and невирішене — they all collapse to the same ріш stem.Stored title/summary/content/tags stay exact, so fingerprints, deduplication, ranking, and export all remain deterministic. Only the FTS5 index gains a derived stems_text column.
Disable with:
$env:MEMORY_KERNEL_DISABLE_STEMMER=1Disabling only affects the query side. stems_text keeps being populated on writes so toggling the env back on does not require a rebuild.
Memory Kernel stays small on purpose:
SQLite + FTS5 instead of a mandatory vector databaseRust acceleration only where it actually helpsFor embedded Python usage, MemoryStore keeps a long-lived SQLite connection for throughput. Prefer with MemoryStore(...) as store: or call store.close() when you are done.
This is a good fit when you want:
This is a weaker fit when you want:
Current stage: working alpha.
Already working:
Still in progress:
The Python implementation is the stable default.
If you want lower overhead on ingest and heuristic hot paths, build the optional Rust module:
.\scripts\build_native.ps1After that, memory-kernel stats will show whether accelerator: rust is active.
You can benchmark the current hot paths with:
python .\scripts\benchmark_ingest.py
python .\scripts\benchmark_upsert.pyExperimental native ranking is available for profiling:
$env:MEMORY_KERNEL_EXPERIMENTAL_NATIVE_RANK=1Apache License 2.0 (see LICENSE and NOTICE). Versions up to and including 0.3.1 were released under the Unlicense and remain available under those terms; all later versions are Apache-2.0. Contributions require a DCO sign-off — see CONTRIBUTING.md.
Issue tracker: https://github.com/Artem362/memory-kernel/issues
Issue template chooser: https://github.com/Artem362/memory-kernel/issues/new/choose
There is also a first-run feedback template in: .github/ISSUE_TEMPLATE/first-run-feedback.yml
The most useful early report includes:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.