memory — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited memory (Plugin) 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.
A standalone semantic-memory MCP server. It stores text "memories" with free-form provenance and recalls them by meaning (vector search), by keyword (FTS5), or by structured filter. Backed by SQLite + [sqlite-vec], embeddings from a local [Ollama] model.
It is persona-agnostic: no journal/persona/approval coupling, just a generic memory store and tool surface. It can be used on its own, or as a Claude Code plugin.
[sqlite-vec]: https://github.com/asg017/sqlite-vec [Ollama]: https://ollama.com
A memory is content plus provenance:
| field | meaning |
|---|---|
content | the text (embedded for recall) |
source | where it came from — free-form (owner, web, tool:foo) |
observed | how it was observed — free-form (stated, inferred, imported) |
date | ISO date the memory pertains to (defaults to today, UTC) |
tags | free-form tags for filtering |
supersedes | id of a prior memory this one replaces (history is kept) |
Recall is hybrid: recall (semantic), lexical (FTS5 keyword), and query (structured). reindex + recall_docs index/search a directory of markdown documents separately from the memory store.
The server registers under the id `fortytwo-memory`, so a consumer calls the tools as mcp__fortytwo-memory__<tool>:
| tool | description |
|---|---|
store | store a memory (+ provenance); set supersedes to replace one |
query | structured query (source/observed/tag/time; live rows by default) |
recall | semantic top-k recall by meaning |
recall_docs | semantic recall over reindexed markdown |
lexical | full-text keyword search (FTS5) |
reindex | self-heal the doc index from a markdown directory |
export_range | render a date range of memories to markdown |
Consumers depend on the tool surface, not the internals. The contract is versioned:
import { MEMORY_TOOL_CONTRACT_VERSION, memoryToolContract } from '@justfortytwo/memory/contract';a contract break → bump MEMORY_TOOL_CONTRACT_VERSION. Siblings pin a caret range on @justfortytwo/memory, so a major bump forces an explicit opt-in.
memoryToolContract is the authoritative human-readable list of tools and their guarantees, kept in sync with the wire schema in src/tools.ts.
The default embedder is `OllamaEmbedder`, which calls a local Ollama /api/embeddings endpoint.
OLLAMA_BASE_URL=http://localhost:11434 # default
EMBED_MODEL=qwen3-embedding:0.6b # default model (1024-dim)Pull the model once:
ollama pull qwen3-embedding:0.6bIf EMBED_MODEL is unset, the server falls back to a deterministic, dependency-free `FakeEmbedder` — useful for tests, CI, and first-run smoke checks with zero infra. (The vector tables are fixed at 1024-dim; a model with a different dimensionality requires a schema change.)
# build (once); the server runs the built JS, not TS
npm run build
# apply migrations to the DB (DB_PATH or ./memory.db)
DB_PATH=./memory.db npm run migrate
# run the MCP server over stdio
DB_PATH=./memory.db EMBED_MODEL=qwen3-embedding:0.6b fortytwo-memoryThe bin is fortytwo-memory → dist/index.js. You can also run it with npx -y @justfortytwo/memory (it is published to npm).
import { openDb, runMigrations, OllamaEmbedder, store, recall, deleteByIds } from '@justfortytwo/memory';
const h = openDb('memory.db');
await runMigrations(h.k);
const embedder = new OllamaEmbedder();
await store(h, embedder, { content: 'the deploy script lives in scripts/deploy.sh', source: 'owner', observed: 'stated' });
const hits = await recall(h, embedder, 'how do I deploy?', 5);
deleteByIds(h, [hits[0].id]); // hard-delete (row + vector + FTS); returns the count removeddeleteByIds(h, ids) hard-deletes memories — the row, its vector, and its FTS entry — so nothing resurfaces in recall/lexical/query. It is intentionally a library API and NOT an MCP tool: deletion is an owner-privileged operation, and exposing it to the assistant's turn loop would let prompt-injected content trick it into erasing memories. Selecting which ids to remove (by query, tag, date range, …) is the caller's job — see @justfortytwo/installer's forget.
.claude-plugin/plugin.json declares the plugin; .mcp.json registers the fortytwo-memory server. By default it launches via npx:
{
"mcpServers": {
"fortytwo-memory": {
"command": "npx",
"args": ["-y", "@justfortytwo/memory"],
"env": {
"OLLAMA_BASE_URL": "http://localhost:11434",
"EMBED_MODEL": "qwen3-embedding:0.6b",
"DB_PATH": "${CLAUDE_PLUGIN_DATA}/memory.db"
}
}
}
}${CLAUDE_PLUGIN_DATA} survives plugin updates, so the DB persists across upgrades. When developing from source, build first (npm run build) and swap the command to node with args ["${CLAUDE_PLUGIN_ROOT}/dist/index.js"]. Claude Code does not build MCP servers — they run via npm/npx.
enrich(h, embedder, candidates) folds a batch of candidate memories into the store: it drops low-salience candidates, dedupes near-duplicates by meaning, and writes the survivors with provenance — honoring an explicit supersedes to replace a stale belief (history is kept, never a silent overwrite). enrichFromTurn(h, embedder, turn, extractor) runs an injected SalienceExtractor and feeds its candidates to enrich.
The salience extractor itself is model-driven and lives in the sibling `@justfortytwo/salience` engine (a SalienceExtractor with an injected LlmClient) — memory owns only the dedupe + write, never the model call.
memory depends on two sibling packages one-directionally (declared as optional peers, no cycle):
GateApprovalStore(src/gate-approval-store.ts), a durable SQLite-backed implementation of gate's ApprovalStore + AuditLogger interfaces. Pass it to gate's decide(..., { store, audit }) to back the safety gate's one-shot approvals with memory's db instead of the gate's standalone JSONL store.
into enrichFromTurn (see above).
npm run build # tsc
npm test # vitest run
npm run test:watch # vitestSet RUN_OLLAMA_TESTS=1 to run the opt-in live-Ollama embedder test.
MIT © 2026 Enrico Deleo
Created and maintained by Enrico Deleo.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.